Initialize Tizen 2.3
[framework/system/deviced.git] / src / display / key-filter.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24
25 #include <vconf.h>
26 #include <Ecore.h>
27
28 #include "util.h"
29 #include "core.h"
30 #include "poll.h"
31 #include "brightness.h"
32 #include "device-node.h"
33 #include "core/queue.h"
34 #include "core/common.h"
35 #include "core/data.h"
36 #include "core/device-notifier.h"
37 #include "core/edbus-handler.h"
38 #include "core/device-handler.h"
39
40 #include <linux/input.h>
41 #ifndef KEY_SCREENLOCK
42 #define KEY_SCREENLOCK          0x98
43 #endif
44 #ifndef SW_GLOVE
45 #define SW_GLOVE                0x16
46 #endif
47
48 #define PREDEF_LEAVESLEEP       "leavesleep"
49 #define POWEROFF_ACT                    "poweroff"
50 #define PWROFF_POPUP_ACT                "pwroff-popup"
51 #define USEC_PER_SEC                    1000000
52 #define COMBINATION_INTERVAL            0.5     /* 0.5 second */
53 #define KEYBACKLIGHT_TIME_90            90      /* 1.5 second */
54 #define KEYBACKLIGHT_TIME_360           360     /* 6 second */
55 #define KEYBACKLIGHT_TIME_ALWAYS_ON             -1      /* always on */
56 #define KEYBACKLIGHT_TIME_ALWAYS_OFF    0       /* always off */
57 #define KEYBACKLIGHT_BASE_TIME          60      /* 1min = 60sec */
58 #define KEYBACKLIGHT_PRESSED_TIME       15      /*  15 second */
59 #define KEY_MAX_DELAY_TIME              700     /* ms */
60
61 #define KEY_RELEASED            0
62 #define KEY_PRESSED             1
63 #define KEY_BEING_PRESSED       2
64
65 #define KEY_COMBINATION_STOP            0
66 #define KEY_COMBINATION_START           1
67 #define KEY_COMBINATION_SCREENCAPTURE   2
68
69 #define SIGNAL_CHANGE_HARDKEY           "ChangeHardkey"
70
71 #define NORMAL_POWER(val)               (val == 0)
72 #define KEY_TEST_MODE_POWER(val)        (val == 2)
73
74 #define TOUCH_RELEASE           (-1)
75
76 #ifndef VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION
77 #define VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION VCONFKEY_SETAPPL_PREFIX"/display/touchkey_light_duration"
78 #endif
79
80 #define GLOVE_MODE      1
81
82 int __WEAK__ get_glove_state(void);
83 void __WEAK__ switch_glove_key(int val);
84
85 static struct timeval pressed_time;
86 static Ecore_Timer *longkey_timeout_id = NULL;
87 static Ecore_Timer *combination_timeout_id = NULL;
88 static Ecore_Timer *hardkey_timeout_id = NULL;
89 static int cancel_lcdoff;
90 static int key_combination = KEY_COMBINATION_STOP;
91 static int volumedown_pressed = false;
92 static int hardkey_duration;
93 static bool touch_pressed = false;
94 static int skip_lcd_off = false;
95 static bool powerkey_pressed = false;
96
97 static inline int current_state_in_on(void)
98 {
99         return (pm_cur_state == S_LCDDIM || pm_cur_state == S_NORMAL);
100 }
101
102 static inline void restore_custom_brightness(void)
103 {
104         if (pm_cur_state == S_LCDDIM &&
105             backlight_ops.get_custom_status())
106                 backlight_ops.custom_update();
107 }
108
109 static void longkey_pressed()
110 {
111         int val = 0;
112         int ret;
113         int csc_mode;
114         char *opt;
115         _I("Power key long pressed!");
116         cancel_lcdoff = 1;
117
118         /* change state - LCD on */
119         recv_data.pid = -1;
120         recv_data.cond = 0x100;
121         (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
122
123         (*g_pm_callback) (INPUT_POLL_EVENT, NULL);
124
125         ret = vconf_get_int(VCONFKEY_TESTMODE_POWER_OFF_POPUP, &val);
126         if (ret != 0 || NORMAL_POWER(val)) {
127                 ret = vconf_get_int(VCONFKEY_CSC_CONFIG_MODE_RUNNING,
128                         &csc_mode);
129                 if (ret >= 0 && csc_mode) {
130                         _I("csc config mode! No poweroff-popup!");
131                         return;
132                 }
133                 opt = PWROFF_POPUP_ACT;
134                 goto entry_call;
135         }
136         if (KEY_TEST_MODE_POWER(val)) {
137                 _I("skip power off control during factory key test mode");
138                 return;
139         }
140         opt = POWEROFF_ACT;
141 entry_call:
142         notify_action(opt, 0);
143 }
144
145 static Eina_Bool longkey_pressed_cb(void *data)
146 {
147         longkey_pressed();
148         longkey_timeout_id = NULL;
149
150         return EINA_FALSE;
151 }
152
153 static Eina_Bool combination_failed_cb(void *data)
154 {
155         key_combination = KEY_COMBINATION_STOP;
156         combination_timeout_id = NULL;
157
158         return EINA_FALSE;
159 }
160
161 static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
162 {
163         unsigned long udiff;
164
165         udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
166         udiff += (t2.tv_usec - t1.tv_usec);
167
168         return udiff;
169 }
170
171 static void stop_key_combination(void)
172 {
173         key_combination = KEY_COMBINATION_STOP;
174         if (combination_timeout_id > 0) {
175                 g_source_remove(combination_timeout_id);
176                 combination_timeout_id = NULL;
177         }
178 }
179
180 static inline void check_key_pair(int code, int new, int *old)
181 {
182         if (new == *old)
183                 _E("key pair is not matched! (%d, %d)", code, new);
184         else
185                 *old = new;
186 }
187
188 static inline bool switch_on_lcd(void)
189 {
190         if (current_state_in_on())
191                 return false;
192
193         if (backlight_ops.get_lcd_power() == PM_LCD_POWER_ON)
194                 return false;
195
196         lcd_on_direct();
197
198         return true;
199 }
200
201 static inline void switch_off_lcd(void)
202 {
203         if (!current_state_in_on())
204                 return;
205
206         if (backlight_ops.get_lcd_power() == PM_LCD_POWER_OFF)
207                 return;
208
209         lcd_off_procedure();
210 }
211
212 static int process_menu_key(struct input_event *pinput)
213 {
214         if (pinput->value == KEY_PRESSED)
215                 switch_on_lcd();
216
217         stop_key_combination();
218
219         return false;
220 }
221
222 static int decide_lcdoff(void)
223 {
224         /* It's not needed if it's already LCD off state */
225         if (!current_state_in_on() &&
226             backlight_ops.get_lcd_power() != PM_LCD_POWER_ON)
227                 return false;
228
229         /*
230          * This flag is set at the moment
231          * that LCD is turned on by power key
232          * LCD has not to turned off in the situation.
233          */
234         if (skip_lcd_off)
235                 return false;
236
237         /* LCD is not turned off when powerkey is pressed,not released */
238         if (powerkey_pressed)
239                 return false;
240
241         /* LCD-off is blocked at the moment poweroff popup shows */
242         if (cancel_lcdoff)
243                 return false;
244
245         /* LCD-off is blocked at the moment volumedown key is pressed */
246         if (volumedown_pressed)
247                 return false;
248
249         /* LCD-off is blocked when powerkey and volmedown key are pressed */
250         if (key_combination == KEY_COMBINATION_SCREENCAPTURE)
251                 return false;
252
253         return true;
254 }
255
256 static int lcdoff_powerkey(void)
257 {
258         int ignore = true;
259
260         if (decide_lcdoff() == true) {
261                 check_processes(S_LCDOFF);
262                 check_processes(S_LCDDIM);
263
264                 if (!check_holdkey_block(S_LCDOFF) &&
265                     !check_holdkey_block(S_LCDDIM)) {
266                         if (display_info.update_auto_brightness)
267                                 display_info.update_auto_brightness(false);
268                         switch_off_lcd();
269                         delete_condition(S_LCDOFF);
270                         delete_condition(S_LCDDIM);
271                         update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
272                         recv_data.pid = -1;
273                         recv_data.cond = 0x400;
274                         (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
275                 }
276         } else {
277                 ignore = false;
278         }
279         cancel_lcdoff = 0;
280
281         return ignore;
282 }
283
284 static int process_power_key(struct input_event *pinput)
285 {
286         int ignore = true;
287         static int value = KEY_RELEASED;
288
289         switch (pinput->value) {
290         case KEY_RELEASED:
291                 powerkey_pressed = false;
292                 check_key_pair(pinput->code, pinput->value, &value);
293
294                 if (!display_conf.powerkey_doublepress) {
295                         ignore = lcdoff_powerkey();
296                 } else if (skip_lcd_off) {
297                         ignore = false;
298                 }
299
300                 stop_key_combination();
301                 if (longkey_timeout_id > 0) {
302                         ecore_timer_del(longkey_timeout_id);
303                         longkey_timeout_id = NULL;
304                 }
305
306                 break;
307         case KEY_PRESSED:
308                 powerkey_pressed = true;
309                 skip_lcd_off = switch_on_lcd();
310                 check_key_pair(pinput->code, pinput->value, &value);
311                 _I("power key pressed");
312                 pressed_time.tv_sec = (pinput->time).tv_sec;
313                 pressed_time.tv_usec = (pinput->time).tv_usec;
314                 if (key_combination == KEY_COMBINATION_STOP) {
315                         /* add long key timer */
316                         longkey_timeout_id = ecore_timer_add(
317                                     display_conf.longpress_interval,
318                                     (Ecore_Task_Cb)longkey_pressed_cb, NULL);
319                         key_combination = KEY_COMBINATION_START;
320                         combination_timeout_id = ecore_timer_add(
321                                     COMBINATION_INTERVAL,
322                                     (Ecore_Task_Cb)combination_failed_cb, NULL);
323                 } else if (key_combination == KEY_COMBINATION_START) {
324                         if (combination_timeout_id > 0) {
325                                 ecore_timer_del(combination_timeout_id);
326                                 combination_timeout_id = NULL;
327                         }
328                         _I("capture mode");
329                         key_combination = KEY_COMBINATION_SCREENCAPTURE;
330                         skip_lcd_off = true;
331                         ignore = false;
332                 }
333                 if (skip_lcd_off)
334                         ignore = false;
335                 cancel_lcdoff = 0;
336
337                 break;
338         case KEY_BEING_PRESSED:
339                 if (timediff_usec(pressed_time, pinput->time) >
340                     (display_conf.longpress_interval * USEC_PER_SEC))
341                         longkey_pressed();
342                 break;
343         }
344         return ignore;
345 }
346
347 static int process_volumedown_key(struct input_event *pinput)
348 {
349         int ignore = true;
350
351         if (pinput->value == KEY_PRESSED) {
352                 if (key_combination == KEY_COMBINATION_STOP) {
353                         key_combination = KEY_COMBINATION_START;
354                         combination_timeout_id = ecore_timer_add(
355                                     COMBINATION_INTERVAL,
356                                     (Ecore_Task_Cb)combination_failed_cb, NULL);
357                 } else if (key_combination == KEY_COMBINATION_START) {
358                         if (combination_timeout_id > 0) {
359                                 ecore_timer_del(combination_timeout_id);
360                                 combination_timeout_id = NULL;
361                         }
362                         if (longkey_timeout_id > 0) {
363                                 ecore_timer_del(longkey_timeout_id);
364                                 longkey_timeout_id = NULL;
365                         }
366                         _I("capture mode");
367                         key_combination = KEY_COMBINATION_SCREENCAPTURE;
368                         skip_lcd_off = true;
369                         ignore = false;
370                 }
371                 volumedown_pressed = true;
372         } else if (pinput->value == KEY_RELEASED) {
373                 if (key_combination != KEY_COMBINATION_SCREENCAPTURE) {
374                         stop_key_combination();
375                         if (current_state_in_on())
376                                 ignore = false;
377                 }
378                 volumedown_pressed = false;
379         }
380
381         return ignore;
382 }
383
384 static int process_brightness_key(struct input_event *pinput, int action)
385 {
386         if (pinput->value == KEY_RELEASED) {
387                 stop_key_combination();
388                 return true;
389         }
390
391         if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
392                 return false;
393
394         /* check weak function symbol */
395         if (!control_brightness_key)
396                 return true;
397
398         return control_brightness_key(action);
399 }
400
401 static int process_screenlock_key(struct input_event *pinput)
402 {
403         if (pinput->value != KEY_RELEASED) {
404                 stop_key_combination();
405                 return true;
406         }
407
408         if (!current_state_in_on())
409                 return false;
410
411         check_processes(S_LCDOFF);
412         check_processes(S_LCDDIM);
413
414         if (!check_holdkey_block(S_LCDOFF) && !check_holdkey_block(S_LCDDIM)) {
415                 delete_condition(S_LCDOFF);
416                 delete_condition(S_LCDDIM);
417                 update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
418
419                 /* LCD off forcly */
420                 recv_data.pid = -1;
421                 recv_data.cond = 0x400;
422                 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
423         }
424
425         return true;
426 }
427
428 static void turnon_hardkey_backlight(void)
429 {
430         int val, ret;
431
432         ret = device_get_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, &val);
433         if (ret < 0 || !val) {
434                 /* key backlight on */
435                 ret = device_set_property(DEVICE_TYPE_LED,
436                     PROP_LED_HARDKEY, STATUS_ON);
437                 if (ret < 0)
438                         _E("Fail to turn off key backlight!");
439         }
440 }
441
442 static void turnoff_hardkey_backlight(void)
443 {
444         int val, ret;
445
446         ret = device_get_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, &val);
447         /* check key backlight is already off */
448         if (!ret && !val)
449                 return;
450
451         /* key backlight off */
452         ret = device_set_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, STATUS_OFF);
453         if (ret < 0)
454                 _E("Fail to turn off key backlight!");
455 }
456
457 static Eina_Bool key_backlight_expired(void *data)
458 {
459         hardkey_timeout_id = NULL;
460
461         turnoff_hardkey_backlight();
462
463         return ECORE_CALLBACK_CANCEL;
464 }
465
466 static void sound_vibrate_hardkey(void)
467 {
468         /* device notify(vibrator) */
469         device_notify(DEVICE_NOTIFIER_TOUCH_HARDKEY, NULL);
470         /* sound(dbus) */
471         broadcast_edbus_signal(DEVICED_PATH_KEY, DEVICED_INTERFACE_KEY,
472                         SIGNAL_CHANGE_HARDKEY, NULL, NULL);
473 }
474
475 static void process_hardkey_backlight(struct input_event *pinput)
476 {
477         float fduration;
478
479         if (pinput->value == KEY_PRESSED) {
480                 if (touch_pressed) {
481                         _I("Touch is pressed, then hard key is not working!");
482                         return;
483                 }
484                 /* Sound & Vibrate only in unlock state */
485                 if (get_lock_screen_state() == VCONFKEY_IDLE_UNLOCK
486                     || get_lock_screen_bg_state())
487                         sound_vibrate_hardkey();
488                 /* release existing timer */
489                 if (hardkey_timeout_id > 0) {
490                         ecore_timer_del(hardkey_timeout_id);
491                         hardkey_timeout_id = NULL;
492                 }
493                 /* if hardkey option is always off */
494                 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
495                         return;
496                 /* turn on hardkey backlight */
497                 turnon_hardkey_backlight();
498                 /* start timer */
499                 hardkey_timeout_id = ecore_timer_add(
500                             KEYBACKLIGHT_PRESSED_TIME,
501                             key_backlight_expired, NULL);
502
503         } else if (pinput->value == KEY_RELEASED) {
504                 /* if lockscreen is idle lock */
505                 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK) {
506                         _D("Lock state, key backlight is off when phone is unlocked!");
507                         return;
508                 }
509                 /* release existing timer */
510                 if (hardkey_timeout_id > 0) {
511                         ecore_timer_del(hardkey_timeout_id);
512                         hardkey_timeout_id = NULL;
513                 }
514                 /* if hardkey option is always on or off */
515                 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON ||
516                         hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
517                         return;
518                 /* start timer */
519                 fduration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
520                 hardkey_timeout_id = ecore_timer_add(
521                             fduration,
522                             key_backlight_expired, NULL);
523         }
524 }
525
526 static int check_key(struct input_event *pinput, int fd)
527 {
528         int ignore = true;
529
530         switch (pinput->code) {
531         case KEY_MENU:
532                 ignore = process_menu_key(pinput);
533                 break;
534         case KEY_POWER:
535                 ignore = process_power_key(pinput);
536                 break;
537         case KEY_VOLUMEDOWN:
538                 ignore = process_volumedown_key(pinput);
539                 break;
540         case KEY_BRIGHTNESSDOWN:
541                 ignore = process_brightness_key(pinput, BRIGHTNESS_DOWN);
542                 break;
543         case KEY_BRIGHTNESSUP:
544                 ignore = process_brightness_key(pinput, BRIGHTNESS_UP);
545                 break;
546         case KEY_SCREENLOCK:
547                 ignore = process_screenlock_key(pinput);
548                 break;
549         case KEY_BACK:
550         case KEY_PHONE:
551                 stop_key_combination();
552                 if (current_state_in_on()) {
553                         process_hardkey_backlight(pinput);
554                         ignore = false;
555                 } else if (!check_pre_install(fd)) {
556                         ignore = false;
557                 }
558                 break;
559         case KEY_VOLUMEUP:
560         case KEY_CAMERA:
561         case KEY_EXIT:
562         case KEY_CONFIG:
563         case KEY_MEDIA:
564         case KEY_MUTE:
565         case KEY_PLAYPAUSE:
566         case KEY_PLAYCD:
567         case KEY_PAUSECD:
568         case KEY_STOPCD:
569         case KEY_NEXTSONG:
570         case KEY_PREVIOUSSONG:
571         case KEY_REWIND:
572         case KEY_FASTFORWARD:
573                 stop_key_combination();
574                 if (current_state_in_on())
575                         ignore = false;
576                 break;
577         case 0x1DB:
578         case 0x1DC:
579         case 0x1DD:
580         case 0x1DE:
581                 stop_key_combination();
582                 break;
583         default:
584                 stop_key_combination();
585                 ignore = false;
586         }
587 #ifdef ENABLE_PM_LOG
588         if (pinput->value == KEY_PRESSED)
589                 pm_history_save(PM_LOG_KEY_PRESS, pinput->code);
590         else if (pinput->value == KEY_RELEASED)
591                 pm_history_save(PM_LOG_KEY_RELEASE, pinput->code);
592 #endif
593         return ignore;
594 }
595
596 static inline int check_powerkey_delay(struct input_event *pinput)
597 {
598         struct timespec tp;
599         int delay;
600
601         if (pinput->code != KEY_POWER ||
602             pinput->value != KEY_PRESSED)
603                 return false;
604
605         if (backlight_ops.get_lcd_power() != PM_LCD_POWER_ON)
606                 return false;
607
608         clock_gettime(CLOCK_MONOTONIC, &tp);
609
610         delay = SEC_TO_MSEC(tp.tv_sec) +
611             NSEC_TO_MSEC(tp.tv_nsec) -
612             (SEC_TO_MSEC((pinput->time).tv_sec) +
613             USEC_TO_MSEC((pinput->time).tv_usec));
614
615         if (delay < KEY_MAX_DELAY_TIME)
616                 return false;
617
618         return true;
619 }
620
621 static int check_key_filter(int length, char buf[], int fd)
622 {
623         struct input_event *pinput;
624         int ignore = true;
625         int idx = 0;
626         static int old_fd, code, value;
627
628         do {
629                 pinput = (struct input_event *)&buf[idx];
630                 switch (pinput->type) {
631                 case EV_KEY:
632                         if (pinput->code == BTN_TOUCH &&
633                             pinput->value == KEY_RELEASED)
634                                 touch_pressed = false;
635                         /*
636                          * The later inputs are going to be ignored when
637                          * powerkey is pressed several times for a short time
638                          */
639                         if (check_powerkey_delay(pinput) == true) {
640                                 _D("power key is delayed, then ignored!");
641                                 return 0;
642                         }
643                         /*
644                          * Normally, touch press/release events don't occur
645                          * in lcd off state. But touch release events can occur
646                          * in the state abnormally. Then touch events are ignored
647                          * when lcd is off state.
648                          */
649                         if (pinput->code == BTN_TOUCH && !current_state_in_on())
650                                 break;
651                         if (get_standby_state() && pinput->code != KEY_POWER) {
652                                 _D("standby mode,key ignored except powerkey");
653                                 break;
654                         }
655                         if (pinput->code == code && pinput->value == value) {
656                                 _E("Same key(%d, %d) is polled [%d,%d]",
657                                     code, value, old_fd, fd);
658                         }
659                         old_fd = fd;
660                         code = pinput->code;
661                         value = pinput->value;
662
663                         ignore = check_key(pinput, fd);
664                         restore_custom_brightness();
665
666                         break;
667                 case EV_REL:
668                         if (get_standby_state())
669                                 break;
670                         ignore = false;
671                         break;
672                 case EV_ABS:
673                         if (get_standby_state())
674                                 break;
675                         if (current_state_in_on())
676                                 ignore = false;
677                         restore_custom_brightness();
678
679                         touch_pressed =
680                             (pinput->value == TOUCH_RELEASE ? false : true);
681                         break;
682                 case EV_SW:
683                         if (!get_glove_state || !switch_glove_key)
684                                 break;
685                         if (pinput->code == SW_GLOVE &&
686                             get_glove_state() == GLOVE_MODE) {
687                                 switch_glove_key(pinput->value);
688                         }
689                         break;
690                 }
691                 idx += sizeof(struct input_event);
692                 if (ignore == true && length <= idx)
693                         return 1;
694         } while (length > idx);
695
696         return 0;
697 }
698
699 void key_backlight_enable(bool enable)
700 {
701         /* release existing timer */
702         if (hardkey_timeout_id > 0) {
703                 ecore_timer_del(hardkey_timeout_id);
704                 hardkey_timeout_id = NULL;
705         }
706
707         /* start timer in case of backlight enabled */
708         if (enable) {
709                 /* if hardkey option is always off */
710                 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
711                         return;
712
713                 /* turn on hardkey backlight */
714                 turnon_hardkey_backlight();
715
716                 /* do not create turnoff timer in case of idle lock state */
717                 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
718                         return;
719
720                 /* start timer */
721                 hardkey_timeout_id = ecore_timer_add(
722                             KEYBACKLIGHT_PRESSED_TIME,
723                                 key_backlight_expired, NULL);
724         } else {
725                 /* if hardkey option is always on */
726                 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
727                         return;
728
729                 /* turn off hardkey backlight */
730                 turnoff_hardkey_backlight();
731         }
732 }
733
734 static void hardkey_duration_cb(keynode_t *key, void *data)
735 {
736         float duration;
737
738         hardkey_duration = vconf_keynode_get_int(key);
739
740         /* release existing timer */
741         if (hardkey_timeout_id > 0) {
742                 ecore_timer_del(hardkey_timeout_id);
743                 hardkey_timeout_id = NULL;
744         }
745
746         /* if hardkey option is always off */
747         if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF) {
748                 /* turn off hardkey backlight */
749                 turnoff_hardkey_backlight();
750                 return;
751         }
752
753         /* turn on hardkey backlight */
754         turnon_hardkey_backlight();
755
756         /* if hardkey option is always on */
757         if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
758                 return;
759
760         /* start timer */
761         duration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
762         hardkey_timeout_id = ecore_timer_add(
763                     duration,
764                     key_backlight_expired, NULL);
765 }
766
767 static int hardkey_lcd_changed_cb(void *data)
768 {
769         int lcd_state = (int)data;
770
771         if (lcd_state == S_NORMAL
772             && battery.temp == TEMP_HIGH
773             && hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON) {
774                 turnon_hardkey_backlight();
775                 return 0;
776         }
777
778         /* when lcd state is dim and battery is over temp,
779            hardkey led should turn off */
780         if (lcd_state == S_LCDDIM && battery.health == HEALTH_BAD) {
781                 /* release existing timer */
782                 if (hardkey_timeout_id > 0) {
783                         ecore_timer_del(hardkey_timeout_id);
784                         hardkey_timeout_id = NULL;
785                 }
786
787                 /* turn off hardkey backlight */
788                 turnoff_hardkey_backlight();
789         }
790         return 0;
791 }
792
793 static void keyfilter_init(void)
794 {
795         /* get touchkey light duration setting */
796         if (vconf_get_int(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, &hardkey_duration) < 0) {
797                 _W("Fail to get VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION!!");
798                 hardkey_duration = KEYBACKLIGHT_TIME_90;
799         }
800
801         vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb, NULL);
802
803         /* register notifier */
804         register_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
805
806         /* update touchkey light duration right now */
807         if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
808                 turnon_hardkey_backlight();
809 }
810
811 static void keyfilter_exit(void)
812 {
813         /* unregister notifier */
814         unregister_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
815
816         vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb);
817 }
818
819 static const struct display_keyfilter_ops normal_keyfilter_ops = {
820         .init                   = keyfilter_init,
821         .exit                   = keyfilter_exit,
822         .check                  = check_key_filter,
823         .set_powerkey_ignore    = NULL,
824         .powerkey_lcdoff        = NULL,
825         .backlight_enable       = key_backlight_enable,
826 };
827 const struct display_keyfilter_ops *keyfilter_ops = &normal_keyfilter_ops;
828