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 "display-actor.h"
34 #include "core/common.h"
35 #include "core/devices.h"
36 #include "core/device-notifier.h"
37 #include "core/edbus-handler.h"
38 #include "core/device-handler.h"
39 #include "power/power-handler.h"
41 #include <linux/input.h>
42 #ifndef KEY_SCREENLOCK
43 #define KEY_SCREENLOCK 0x98
49 #define PREDEF_LEAVESLEEP "leavesleep"
50 #define POWEROFF_ACT "poweroff"
51 #define PWROFF_POPUP_ACT "pwroff-popup"
52 #define USEC_PER_SEC 1000000
53 #define COMBINATION_INTERVAL 0.5 /* 0.5 second */
54 #define KEYBACKLIGHT_TIME_90 90 /* 1.5 second */
55 #define KEYBACKLIGHT_TIME_360 360 /* 6 second */
56 #define KEYBACKLIGHT_TIME_ALWAYS_ON -1 /* always on */
57 #define KEYBACKLIGHT_TIME_ALWAYS_OFF 0 /* always off */
58 #define KEYBACKLIGHT_BASE_TIME 60 /* 1min = 60sec */
59 #define KEYBACKLIGHT_PRESSED_TIME 15 /* 15 second */
60 #define KEY_MAX_DELAY_TIME 700 /* ms */
62 #define KEY_RELEASED 0
64 #define KEY_BEING_PRESSED 2
66 #define KEY_COMBINATION_STOP 0
67 #define KEY_COMBINATION_START 1
68 #define KEY_COMBINATION_SCREENCAPTURE 2
70 #define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
71 #define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
72 #define SIGNAL_LCDOFF_BY_POWERKEY "LCDOffByPowerkey"
74 #define NORMAL_POWER(val) (val == 0)
75 #define KEY_TEST_MODE_POWER(val) (val == 2)
77 #define TOUCH_RELEASE (-1)
79 #ifndef VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION
80 #define VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION VCONFKEY_SETAPPL_PREFIX"/display/touchkey_light_duration"
85 int __WEAK__ get_glove_state(void);
86 void __WEAK__ switch_glove_key(int val);
88 static struct timeval pressed_time;
89 static Ecore_Timer *longkey_timeout_id = NULL;
90 static Ecore_Timer *combination_timeout_id = NULL;
91 static Ecore_Timer *hardkey_timeout_id = NULL;
92 static int cancel_lcdoff;
93 static int key_combination = KEY_COMBINATION_STOP;
94 static int menu_pressed = false;
95 static int hardkey_duration;
96 static bool touch_pressed = false;
97 static int skip_lcd_off = false;
98 static bool powerkey_pressed = false;
100 static inline int current_state_in_on(void)
102 return (pm_cur_state == S_LCDDIM || pm_cur_state == S_NORMAL);
105 static inline void restore_custom_brightness(void)
107 if (pm_cur_state == S_LCDDIM &&
108 backlight_ops.get_custom_status())
109 backlight_ops.custom_update();
112 static int power_execute(void *data)
114 static const struct device_ops *ops = NULL;
116 FIND_DEVICE_INT(ops, POWER_OPS_NAME);
118 return ops->execute(data);
121 static void longkey_pressed()
129 _I("Power key long pressed!");
132 caps = display_get_caps(DISPLAY_ACTOR_POWER_KEY);
134 if (display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
135 /* change state - LCD on */
136 recv_data.pid = getpid();
137 recv_data.cond = 0x100;
138 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
139 (*g_pm_callback)(INPUT_POLL_EVENT, NULL);
142 if (!display_has_caps(caps, DISPLAY_CAPA_LCDOFF)) {
143 _D("No poweroff capability!");
147 ret = vconf_get_int(VCONFKEY_TESTMODE_POWER_OFF_POPUP, &val);
148 if (ret != 0 || NORMAL_POWER(val)) {
149 ret = vconf_get_int(VCONFKEY_CSC_CONFIG_MODE_RUNNING,
151 if (ret >= 0 && csc_mode) {
152 _I("csc config mode! No poweroff-popup!");
155 opt = PWROFF_POPUP_ACT;
158 if (KEY_TEST_MODE_POWER(val)) {
159 _I("skip power off control during factory key test mode");
167 static Eina_Bool longkey_pressed_cb(void *data)
170 longkey_timeout_id = NULL;
175 static Eina_Bool combination_failed_cb(void *data)
177 key_combination = KEY_COMBINATION_STOP;
178 combination_timeout_id = NULL;
183 static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
187 udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
188 udiff += (t2.tv_usec - t1.tv_usec);
193 static void stop_key_combination(void)
195 key_combination = KEY_COMBINATION_STOP;
196 if (combination_timeout_id > 0) {
197 g_source_remove(combination_timeout_id);
198 combination_timeout_id = NULL;
202 static inline void check_key_pair(int code, int new, int *old)
205 _E("key pair is not matched! (%d, %d)", code, new);
210 static inline void broadcast_lcdon_by_powerkey(void)
212 broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
213 SIGNAL_LCDON_BY_POWERKEY, NULL, NULL);
216 static inline void broadcast_lcdoff_by_powerkey(void)
218 broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
219 SIGNAL_LCDOFF_BY_POWERKEY, NULL, NULL);
222 static inline bool switch_on_lcd(void)
224 if (current_state_in_on())
227 if (backlight_ops.get_lcd_power() == PM_LCD_POWER_ON)
230 broadcast_lcdon_by_powerkey();
232 lcd_on_direct(LCD_ON_BY_POWER_KEY);
237 static inline void switch_off_lcd(void)
239 if (!current_state_in_on())
242 if (backlight_ops.get_lcd_power() == PM_LCD_POWER_OFF)
245 broadcast_lcdoff_by_powerkey();
250 static void process_combination_key(struct input_event *pinput)
252 if (pinput->value == KEY_PRESSED) {
253 if (key_combination == KEY_COMBINATION_STOP) {
254 key_combination = KEY_COMBINATION_START;
255 combination_timeout_id = ecore_timer_add(
256 COMBINATION_INTERVAL,
257 (Ecore_Task_Cb)combination_failed_cb, NULL);
258 } else if (key_combination == KEY_COMBINATION_START) {
259 if (combination_timeout_id > 0) {
260 ecore_timer_del(combination_timeout_id);
261 combination_timeout_id = NULL;
263 if (longkey_timeout_id > 0) {
264 ecore_timer_del(longkey_timeout_id);
265 longkey_timeout_id = NULL;
268 key_combination = KEY_COMBINATION_SCREENCAPTURE;
272 } else if (pinput->value == KEY_RELEASED) {
273 if (key_combination != KEY_COMBINATION_SCREENCAPTURE)
274 stop_key_combination();
275 menu_pressed = false;
280 static int process_menu_key(struct input_event *pinput)
284 caps = display_get_caps(DISPLAY_ACTOR_MENU_KEY);
286 if (!display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
287 if (current_state_in_on()) {
288 process_combination_key(pinput);
291 _D("No lcd-on capability!");
293 } else if (pinput->value == KEY_PRESSED) {
297 process_combination_key(pinput);
302 static int decide_lcdoff(void)
304 /* It's not needed if it's already LCD off state */
305 if (!current_state_in_on() &&
306 backlight_ops.get_lcd_power() != PM_LCD_POWER_ON)
310 * This flag is set at the moment
311 * that LCD is turned on by power key
312 * LCD has not to turned off in the situation.
317 /* LCD is not turned off when powerkey is pressed,not released */
318 if (powerkey_pressed)
321 /* LCD-off is blocked at the moment poweroff popup shows */
325 /* LCD-off is blocked at the moment volumedown key is pressed */
329 /* LCD-off is blocked when powerkey and volmedown key are pressed */
330 if (key_combination == KEY_COMBINATION_SCREENCAPTURE)
336 static int lcdoff_powerkey(void)
340 if (decide_lcdoff() == true) {
341 check_processes(S_LCDOFF);
342 check_processes(S_LCDDIM);
344 if (!check_holdkey_block(S_LCDOFF) &&
345 !check_holdkey_block(S_LCDDIM)) {
346 if (display_info.update_auto_brightness)
347 display_info.update_auto_brightness(false);
349 delete_condition(S_LCDOFF);
350 delete_condition(S_LCDDIM);
351 update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
352 recv_data.pid = getpid();
353 recv_data.cond = 0x400;
354 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
364 static int process_power_key(struct input_event *pinput)
367 static int value = KEY_RELEASED;
370 caps = display_get_caps(DISPLAY_ACTOR_POWER_KEY);
372 switch (pinput->value) {
374 powerkey_pressed = false;
375 check_key_pair(pinput->code, pinput->value, &value);
377 if (!display_conf.powerkey_doublepress) {
378 if (display_has_caps(caps, DISPLAY_CAPA_LCDOFF))
379 ignore = lcdoff_powerkey();
381 _D("No lcdoff capability!");
382 } else if (skip_lcd_off) {
386 if (!display_has_caps(caps, DISPLAY_CAPA_LCDON))
389 stop_key_combination();
390 if (longkey_timeout_id > 0) {
391 ecore_timer_del(longkey_timeout_id);
392 longkey_timeout_id = NULL;
397 powerkey_pressed = true;
398 if (display_has_caps(caps, DISPLAY_CAPA_LCDON)) {
399 skip_lcd_off = switch_on_lcd();
401 _D("No lcdon capability!");
402 skip_lcd_off = false;
404 check_key_pair(pinput->code, pinput->value, &value);
405 _I("power key pressed");
406 pressed_time.tv_sec = (pinput->time).tv_sec;
407 pressed_time.tv_usec = (pinput->time).tv_usec;
408 if (key_combination == KEY_COMBINATION_STOP) {
409 /* add long key timer */
410 longkey_timeout_id = ecore_timer_add(
411 display_conf.longpress_interval,
412 (Ecore_Task_Cb)longkey_pressed_cb, NULL);
413 key_combination = KEY_COMBINATION_START;
414 combination_timeout_id = ecore_timer_add(
415 COMBINATION_INTERVAL,
416 (Ecore_Task_Cb)combination_failed_cb, NULL);
417 } else if (key_combination == KEY_COMBINATION_START) {
418 if (combination_timeout_id > 0) {
419 ecore_timer_del(combination_timeout_id);
420 combination_timeout_id = NULL;
423 key_combination = KEY_COMBINATION_SCREENCAPTURE;
432 case KEY_BEING_PRESSED:
433 if (timediff_usec(pressed_time, pinput->time) >
434 (display_conf.longpress_interval * USEC_PER_SEC))
441 static int process_brightness_key(struct input_event *pinput, int action)
443 if (pinput->value == KEY_RELEASED) {
444 stop_key_combination();
448 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
451 /* check weak function symbol */
452 if (!control_brightness_key)
455 return control_brightness_key(action);
458 static int process_screenlock_key(struct input_event *pinput)
460 if (pinput->value != KEY_RELEASED) {
461 stop_key_combination();
465 if (!current_state_in_on())
468 check_processes(S_LCDOFF);
469 check_processes(S_LCDDIM);
471 if (!check_holdkey_block(S_LCDOFF) && !check_holdkey_block(S_LCDDIM)) {
472 delete_condition(S_LCDOFF);
473 delete_condition(S_LCDDIM);
474 update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
478 recv_data.cond = 0x400;
479 (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
485 static void turnon_hardkey_backlight(void)
489 ret = device_get_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, &val);
490 if (ret < 0 || !val) {
491 /* key backlight on */
492 ret = device_set_property(DEVICE_TYPE_LED,
493 PROP_LED_HARDKEY, STATUS_ON);
495 _E("Fail to turn off key backlight!");
499 static void turnoff_hardkey_backlight(void)
503 ret = device_get_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, &val);
504 /* check key backlight is already off */
508 /* key backlight off */
509 ret = device_set_property(DEVICE_TYPE_LED, PROP_LED_HARDKEY, STATUS_OFF);
511 _E("Fail to turn off key backlight!");
514 static Eina_Bool key_backlight_expired(void *data)
516 hardkey_timeout_id = NULL;
518 turnoff_hardkey_backlight();
520 return ECORE_CALLBACK_CANCEL;
523 static void sound_vibrate_hardkey(void)
525 /* device notify(vibrator) */
526 device_notify(DEVICE_NOTIFIER_TOUCH_HARDKEY, NULL);
528 broadcast_edbus_signal(DEVICED_PATH_KEY, DEVICED_INTERFACE_KEY,
529 SIGNAL_CHANGE_HARDKEY, NULL, NULL);
532 static void process_hardkey_backlight(struct input_event *pinput)
536 if (pinput->value == KEY_PRESSED) {
538 _I("Touch is pressed, then hard key is not working!");
541 /* Sound & Vibrate only in unlock state */
542 if (get_lock_screen_state() == VCONFKEY_IDLE_UNLOCK
543 || get_lock_screen_bg_state())
544 sound_vibrate_hardkey();
545 /* release existing timer */
546 if (hardkey_timeout_id > 0) {
547 ecore_timer_del(hardkey_timeout_id);
548 hardkey_timeout_id = NULL;
550 /* if hardkey option is always off */
551 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
553 /* turn on hardkey backlight */
554 turnon_hardkey_backlight();
556 hardkey_timeout_id = ecore_timer_add(
557 KEYBACKLIGHT_PRESSED_TIME,
558 key_backlight_expired, NULL);
560 } else if (pinput->value == KEY_RELEASED) {
561 /* if lockscreen is idle lock */
562 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK) {
563 _D("Lock state, key backlight is off when phone is unlocked!");
566 /* release existing timer */
567 if (hardkey_timeout_id > 0) {
568 ecore_timer_del(hardkey_timeout_id);
569 hardkey_timeout_id = NULL;
571 /* if hardkey option is always on or off */
572 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON ||
573 hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
576 fduration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
577 hardkey_timeout_id = ecore_timer_add(
579 key_backlight_expired, NULL);
583 static int check_key(struct input_event *pinput, int fd)
587 switch (pinput->code) {
589 ignore = process_menu_key(pinput);
592 ignore = process_power_key(pinput);
594 case KEY_BRIGHTNESSDOWN:
595 ignore = process_brightness_key(pinput, BRIGHTNESS_DOWN);
597 case KEY_BRIGHTNESSUP:
598 ignore = process_brightness_key(pinput, BRIGHTNESS_UP);
601 ignore = process_screenlock_key(pinput);
605 stop_key_combination();
606 if (current_state_in_on()) {
607 process_hardkey_backlight(pinput);
609 } else if (!check_pre_install(fd)) {
625 case KEY_PREVIOUSSONG:
627 case KEY_FASTFORWARD:
628 stop_key_combination();
629 if (current_state_in_on())
636 stop_key_combination();
639 stop_key_combination();
643 if (pinput->value == KEY_PRESSED)
644 pm_history_save(PM_LOG_KEY_PRESS, pinput->code);
645 else if (pinput->value == KEY_RELEASED)
646 pm_history_save(PM_LOG_KEY_RELEASE, pinput->code);
651 static int check_key_filter(int length, char buf[], int fd)
653 struct input_event *pinput;
656 static int old_fd, code, value;
659 pinput = (struct input_event *)&buf[idx];
660 switch (pinput->type) {
662 if (pinput->code == BTN_TOUCH &&
663 pinput->value == KEY_RELEASED)
664 touch_pressed = false;
666 * Normally, touch press/release events don't occur
667 * in lcd off state. But touch release events can occur
668 * in the state abnormally. Then touch events are ignored
669 * when lcd is off state.
671 if (pinput->code == BTN_TOUCH && !current_state_in_on())
673 if (get_standby_state() && pinput->code != KEY_POWER) {
674 _D("standby mode,key ignored except powerkey");
677 if (pinput->code == code && pinput->value == value) {
678 _E("Same key(%d, %d) is polled [%d,%d]",
679 code, value, old_fd, fd);
683 value = pinput->value;
685 ignore = check_key(pinput, fd);
686 restore_custom_brightness();
690 if (get_standby_state())
695 if (get_standby_state())
697 if (current_state_in_on())
699 restore_custom_brightness();
702 (pinput->value == TOUCH_RELEASE ? false : true);
705 if (!get_glove_state || !switch_glove_key)
707 if (pinput->code == SW_GLOVE &&
708 get_glove_state() == GLOVE_MODE) {
709 switch_glove_key(pinput->value);
713 idx += sizeof(struct input_event);
714 if (ignore == true && length <= idx)
716 } while (length > idx);
721 void key_backlight_enable(bool enable)
723 /* release existing timer */
724 if (hardkey_timeout_id > 0) {
725 ecore_timer_del(hardkey_timeout_id);
726 hardkey_timeout_id = NULL;
729 /* start timer in case of backlight enabled */
731 /* if hardkey option is always off */
732 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF)
735 /* turn on hardkey backlight */
736 turnon_hardkey_backlight();
738 /* do not create turnoff timer in case of idle lock state */
739 if (get_lock_screen_state() == VCONFKEY_IDLE_LOCK)
743 hardkey_timeout_id = ecore_timer_add(
744 KEYBACKLIGHT_PRESSED_TIME,
745 key_backlight_expired, NULL);
747 /* if hardkey option is always on */
748 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
751 /* turn off hardkey backlight */
752 turnoff_hardkey_backlight();
756 static void hardkey_duration_cb(keynode_t *key, void *data)
760 hardkey_duration = vconf_keynode_get_int(key);
762 /* release existing timer */
763 if (hardkey_timeout_id > 0) {
764 ecore_timer_del(hardkey_timeout_id);
765 hardkey_timeout_id = NULL;
768 /* if hardkey option is always off */
769 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_OFF) {
770 /* turn off hardkey backlight */
771 turnoff_hardkey_backlight();
775 /* turn on hardkey backlight */
776 turnon_hardkey_backlight();
778 /* if hardkey option is always on */
779 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
783 duration = (float)hardkey_duration / KEYBACKLIGHT_BASE_TIME;
784 hardkey_timeout_id = ecore_timer_add(
786 key_backlight_expired, NULL);
789 static int hardkey_lcd_changed_cb(void *data)
791 int lcd_state = (int)data;
793 if (lcd_state == S_NORMAL
794 && battery.temp == TEMP_HIGH
795 && hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON) {
796 turnon_hardkey_backlight();
800 /* when lcd state is dim and battery is over temp,
801 hardkey led should turn off */
802 if (lcd_state == S_LCDDIM && battery.health == HEALTH_BAD) {
803 /* release existing timer */
804 if (hardkey_timeout_id > 0) {
805 ecore_timer_del(hardkey_timeout_id);
806 hardkey_timeout_id = NULL;
809 /* turn off hardkey backlight */
810 turnoff_hardkey_backlight();
817 * powerkey := LCDON | LCDOFF | POWEROFF
820 static struct display_actor_ops display_powerkey_actor = {
821 .id = DISPLAY_ACTOR_POWER_KEY,
822 .caps = DISPLAY_CAPA_LCDON |
823 DISPLAY_CAPA_LCDOFF |
824 DISPLAY_CAPA_POWEROFF,
827 static struct display_actor_ops display_menukey_actor = {
828 .id = DISPLAY_ACTOR_MENU_KEY,
829 .caps = DISPLAY_CAPA_LCDON,
832 static void keyfilter_init(void)
834 display_add_actor(&display_powerkey_actor);
835 display_add_actor(&display_menukey_actor);
837 /* get touchkey light duration setting */
838 if (vconf_get_int(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, &hardkey_duration) < 0) {
839 _W("Fail to get VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION!!");
840 hardkey_duration = KEYBACKLIGHT_TIME_90;
843 vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb, NULL);
845 /* register notifier */
846 register_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
848 /* update touchkey light duration right now */
849 if (hardkey_duration == KEYBACKLIGHT_TIME_ALWAYS_ON)
850 turnon_hardkey_backlight();
853 static void keyfilter_exit(void)
855 /* unregister notifier */
856 unregister_notifier(DEVICE_NOTIFIER_LCD, hardkey_lcd_changed_cb);
858 vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCHKEY_LIGHT_DURATION, hardkey_duration_cb);
861 static const struct display_keyfilter_ops normal_keyfilter_ops = {
862 .init = keyfilter_init,
863 .exit = keyfilter_exit,
864 .check = check_key_filter,
865 .set_powerkey_ignore = NULL,
866 .powerkey_lcdoff = NULL,
867 .backlight_enable = key_backlight_enable,
869 const struct display_keyfilter_ops *keyfilter_ops = &normal_keyfilter_ops;