4 * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
40 #include <linux/input.h>
41 #ifndef KEY_SCREENLOCK
42 #define KEY_SCREENLOCK 0x98
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 */
61 #define KEY_RELEASED 0
63 #define KEY_BEING_PRESSED 2
65 #define KEY_COMBINATION_STOP 0
66 #define KEY_COMBINATION_START 1
67 #define KEY_COMBINATION_SCREENCAPTURE 2
69 #define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
71 #define NORMAL_POWER(val) (val == 0)
72 #define KEY_TEST_MODE_POWER(val) (val == 2)
74 #define TOUCH_RELEASE (-1)
76 #ifndef VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION
77 #define VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION VCONFKEY_SETAPPL_PREFIX"/display/touchkey_light_duration"
82 int __WEAK__ get_glove_state(void);
83 void __WEAK__ switch_glove_key(int val);
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;
97 static inline int current_state_in_on(void)
99 return (pm_cur_state == S_LCDDIM || pm_cur_state == S_NORMAL);
102 static inline void restore_custom_brightness(void)
104 if (pm_cur_state == S_LCDDIM &&
105 backlight_ops.get_custom_status())
106 backlight_ops.custom_update();
109 static void longkey_pressed()
115 _I("Power key long pressed!");
118 /* change state - LCD on */
120 recv_data.cond = 0x100;
121 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
123 (*g_pm_callback) (INPUT_POLL_EVENT, NULL);
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,
129 if (ret >= 0 && csc_mode) {
130 _I("csc config mode! No poweroff-popup!");
133 opt = PWROFF_POPUP_ACT;
136 if (KEY_TEST_MODE_POWER(val)) {
137 _I("skip power off control during factory key test mode");
142 notify_action(opt, 0);
145 static Eina_Bool longkey_pressed_cb(void *data)
148 longkey_timeout_id = NULL;
153 static Eina_Bool combination_failed_cb(void *data)
155 key_combination = KEY_COMBINATION_STOP;
156 combination_timeout_id = NULL;
161 static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
165 udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
166 udiff += (t2.tv_usec - t1.tv_usec);
171 static void stop_key_combination(void)
173 key_combination = KEY_COMBINATION_STOP;
174 if (combination_timeout_id > 0) {
175 g_source_remove(combination_timeout_id);
176 combination_timeout_id = NULL;
180 static inline void check_key_pair(int code, int new, int *old)
183 _E("key pair is not matched! (%d, %d)", code, new);
188 static inline bool switch_on_lcd(void)
190 if (current_state_in_on())
193 if (backlight_ops.get_lcd_power() == PM_LCD_POWER_ON)
201 static inline void switch_off_lcd(void)
203 if (!current_state_in_on())
206 if (backlight_ops.get_lcd_power() == PM_LCD_POWER_OFF)
212 static int process_menu_key(struct input_event *pinput)
214 if (pinput->value == KEY_PRESSED)
217 stop_key_combination();
222 static int decide_lcdoff(void)
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)
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.
237 /* LCD is not turned off when powerkey is pressed,not released */
238 if (powerkey_pressed)
241 /* LCD-off is blocked at the moment poweroff popup shows */
245 /* LCD-off is blocked at the moment volumedown key is pressed */
246 if (volumedown_pressed)
249 /* LCD-off is blocked when powerkey and volmedown key are pressed */
250 if (key_combination == KEY_COMBINATION_SCREENCAPTURE)
256 static int lcdoff_powerkey(void)
260 if (decide_lcdoff() == true) {
261 check_processes(S_LCDOFF);
262 check_processes(S_LCDDIM);
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);
269 delete_condition(S_LCDOFF);
270 delete_condition(S_LCDDIM);
271 update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
273 recv_data.cond = 0x400;
274 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
284 static int process_power_key(struct input_event *pinput)
287 static int value = KEY_RELEASED;
289 switch (pinput->value) {
291 powerkey_pressed = false;
292 check_key_pair(pinput->code, pinput->value, &value);
294 if (!display_conf.powerkey_doublepress) {
295 ignore = lcdoff_powerkey();
296 } else if (skip_lcd_off) {
300 stop_key_combination();
301 if (longkey_timeout_id > 0) {
302 ecore_timer_del(longkey_timeout_id);
303 longkey_timeout_id = NULL;
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;
329 key_combination = KEY_COMBINATION_SCREENCAPTURE;
338 case KEY_BEING_PRESSED:
339 if (timediff_usec(pressed_time, pinput->time) >
340 (display_conf.longpress_interval * USEC_PER_SEC))
347 static int process_volumedown_key(struct input_event *pinput)
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;
362 if (longkey_timeout_id > 0) {
363 ecore_timer_del(longkey_timeout_id);
364 longkey_timeout_id = NULL;
367 key_combination = KEY_COMBINATION_SCREENCAPTURE;
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())
378 volumedown_pressed = false;
384 static int process_brightness_key(struct input_event *pinput, int action)
386 if (pinput->value == KEY_RELEASED) {
387 stop_key_combination();
391 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
394 /* check weak function symbol */
395 if (!control_brightness_key)
398 return control_brightness_key(action);
401 static int process_screenlock_key(struct input_event *pinput)
403 if (pinput->value != KEY_RELEASED) {
404 stop_key_combination();
408 if (!current_state_in_on())
411 check_processes(S_LCDOFF);
412 check_processes(S_LCDDIM);
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);
421 recv_data.cond = 0x400;
422 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
428 static void turnon_hardkey_backlight(void)
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);
438 _E("Fail to turn off key backlight!");
442 static void turnoff_hardkey_backlight(void)
446 ret = device_get_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, &val);
447 /* check key backlight is already off */
451 /* key backlight off */
452 ret = device_set_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, STATUS_OFF);
454 _E("Fail to turn off key backlight!");
457 static Eina_Bool key_backlight_expired(void *data)
459 hardkey_timeout_id = NULL;
461 turnoff_hardkey_backlight();
463 return ECORE_CALLBACK_CANCEL;
466 static void sound_vibrate_hardkey(void)
468 /* device notify(vibrator) */
469 device_notify(DEVICE_NOTIFIER_TOUCH_HARDKEY, NULL);
471 broadcast_edbus_signal(DEVICED_PATH_KEY, DEVICED_INTERFACE_KEY,
472 SIGNAL_CHANGE_HARDKEY, NULL, NULL);
475 static void process_hardkey_backlight(struct input_event *pinput)
479 if (pinput->value == KEY_PRESSED) {
481 _I("Touch is pressed, then hard key is not working!");
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;
493 /* if hardkey option is always off */
494 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
496 /* turn on hardkey backlight */
497 turnon_hardkey_backlight();
499 hardkey_timeout_id = ecore_timer_add(
500 KEYBACKLIGHT_PRESSED_TIME,
501 key_backlight_expired, NULL);
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!");
509 /* release existing timer */
510 if (hardkey_timeout_id > 0) {
511 ecore_timer_del(hardkey_timeout_id);
512 hardkey_timeout_id = NULL;
514 /* if hardkey option is always on or off */
515 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON ||
516 hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
519 fduration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
520 hardkey_timeout_id = ecore_timer_add(
522 key_backlight_expired, NULL);
526 static int check_key(struct input_event *pinput, int fd)
530 switch (pinput->code) {
532 ignore = process_menu_key(pinput);
535 ignore = process_power_key(pinput);
538 ignore = process_volumedown_key(pinput);
540 case KEY_BRIGHTNESSDOWN:
541 ignore = process_brightness_key(pinput, BRIGHTNESS_DOWN);
543 case KEY_BRIGHTNESSUP:
544 ignore = process_brightness_key(pinput, BRIGHTNESS_UP);
547 ignore = process_screenlock_key(pinput);
551 stop_key_combination();
552 if (current_state_in_on()) {
553 process_hardkey_backlight(pinput);
555 } else if (!check_pre_install(fd)) {
570 case KEY_PREVIOUSSONG:
572 case KEY_FASTFORWARD:
573 stop_key_combination();
574 if (current_state_in_on())
581 stop_key_combination();
584 stop_key_combination();
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);
596 static inline int check_powerkey_delay(struct input_event *pinput)
601 if (pinput->code != KEY_POWER ||
602 pinput->value != KEY_PRESSED)
605 if (backlight_ops.get_lcd_power() != PM_LCD_POWER_ON)
608 clock_gettime(CLOCK_MONOTONIC, &tp);
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));
615 if (delay < KEY_MAX_DELAY_TIME)
621 static int check_key_filter(int length, char buf[], int fd)
623 struct input_event *pinput;
626 static int old_fd, code, value;
629 pinput = (struct input_event *)&buf[idx];
630 switch (pinput->type) {
632 if (pinput->code == BTN_TOUCH &&
633 pinput->value == KEY_RELEASED)
634 touch_pressed = false;
636 * The later inputs are going to be ignored when
637 * powerkey is pressed several times for a short time
639 if (check_powerkey_delay(pinput) == true) {
640 _D("power key is delayed, then ignored!");
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.
649 if (pinput->code == BTN_TOUCH && !current_state_in_on())
651 if (get_standby_state() && pinput->code != KEY_POWER) {
652 _D("standby mode,key ignored except powerkey");
655 if (pinput->code == code && pinput->value == value) {
656 _E("Same key(%d, %d) is polled [%d,%d]",
657 code, value, old_fd, fd);
661 value = pinput->value;
663 ignore = check_key(pinput, fd);
664 restore_custom_brightness();
668 if (get_standby_state())
673 if (get_standby_state())
675 if (current_state_in_on())
677 restore_custom_brightness();
680 (pinput->value == TOUCH_RELEASE ? false : true);
683 if (!get_glove_state || !switch_glove_key)
685 if (pinput->code == SW_GLOVE &&
686 get_glove_state() == GLOVE_MODE) {
687 switch_glove_key(pinput->value);
691 idx += sizeof(struct input_event);
692 if (ignore == true && length <= idx)
694 } while (length > idx);
699 void key_backlight_enable(bool enable)
701 /* release existing timer */
702 if (hardkey_timeout_id > 0) {
703 ecore_timer_del(hardkey_timeout_id);
704 hardkey_timeout_id = NULL;
707 /* start timer in case of backlight enabled */
709 /* if hardkey option is always off */
710 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
713 /* turn on hardkey backlight */
714 turnon_hardkey_backlight();
716 /* do not create turnoff timer in case of idle lock state */
717 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
721 hardkey_timeout_id = ecore_timer_add(
722 KEYBACKLIGHT_PRESSED_TIME,
723 key_backlight_expired, NULL);
725 /* if hardkey option is always on */
726 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
729 /* turn off hardkey backlight */
730 turnoff_hardkey_backlight();
734 static void hardkey_duration_cb(keynode_t *key, void *data)
738 hardkey_duration = vconf_keynode_get_int(key);
740 /* release existing timer */
741 if (hardkey_timeout_id > 0) {
742 ecore_timer_del(hardkey_timeout_id);
743 hardkey_timeout_id = NULL;
746 /* if hardkey option is always off */
747 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF) {
748 /* turn off hardkey backlight */
749 turnoff_hardkey_backlight();
753 /* turn on hardkey backlight */
754 turnon_hardkey_backlight();
756 /* if hardkey option is always on */
757 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
761 duration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
762 hardkey_timeout_id = ecore_timer_add(
764 key_backlight_expired, NULL);
767 static int hardkey_lcd_changed_cb(void *data)
769 int lcd_state = (int)data;
771 if (lcd_state == S_NORMAL
772 && battery.temp == TEMP_HIGH
773 && hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON) {
774 turnon_hardkey_backlight();
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;
787 /* turn off hardkey backlight */
788 turnoff_hardkey_backlight();
793 static void keyfilter_init(void)
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;
801 vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb, NULL);
803 /* register notifier */
804 register_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
806 /* update touchkey light duration right now */
807 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
808 turnon_hardkey_backlight();
811 static void keyfilter_exit(void)
813 /* unregister notifier */
814 unregister_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
816 vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb);
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,
827 const struct display_keyfilter_ops *keyfilter_ops = &normal_keyfilter_ops;