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.
26 #include <sys/types.h>
27 #include <libsyscommon/libgdbus.h>
28 #include <libsyscommon/resource-manager.h>
29 #include <libsyscommon/log.h>
30 #include <system/syscommon-plugin-deviced-common-interface.h>
31 #include <system/syscommon-plugin-deviced-display-interface.h>
32 #include <linux/input.h>
34 #include "ambient-mode.h"
37 #include "device-interface.h"
38 #include "display-actor.h"
39 #include "display-panel.h"
40 #include "display-backlight.h"
41 #include "display-ops.h"
42 #include "display-config.h"
43 #include "display-misc.h"
44 #include "display-state-transition.h"
45 #include "display-util.h"
46 #include "shared/common.h"
47 #include "shared/devices.h"
48 #include "shared/device-notifier.h"
49 #include "shared/common.h"
50 #include "shared/plugin.h"
51 #include "shared/apps.h"
52 #include "power/power-off.h"
53 #include "power/power-suspend.h"
54 #include "led/touch-key.h"
55 #include "display-lock.h"
56 #include "input/input.h"
58 #ifndef KEY_SCREENLOCK
59 #define KEY_SCREENLOCK 0x98
65 #define USEC_PER_SEC 1000000
67 #define CAPTURE_COMBINATION_INTERVAL 0.5 /* 0.5 second */
68 #define TORCH_COMBINATION_INTERVAL 0.1 /* 0.1 second */
69 #define DEFAULT_COMBINATION_INTERVAL 0.1 /* 0.1 second */
71 #define LONGKEY_PRESSED_TIME 4 /* 4 second */
73 #define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
74 #define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
75 #define SIGNAL_LCDOFF_BY_POWERKEY "LCDOffByPowerkey"
77 enum key_combination_flags {
78 KEY_COMBINATION_STOP = 0,
79 KEY_COMBINATION_POWERKEY = BIT(0),
80 KEY_COMBINATION_MENUKEY = BIT(1),
81 KEY_COMBINATION_VOLUMEUP = BIT(2),
82 KEY_COMBINATION_VOLUMEDOWN = BIT(3),
85 enum combination_process {
86 COMBINATION_STOP = KEY_COMBINATION_STOP,
87 COMBINATION_SCREENCAPTURE = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_MENUKEY,
88 COMBINATION_TORCH = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_VOLUMEUP,
89 COMBINATION_QUICKTALK = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_VOLUMEDOWN,
92 static struct display_plugin *disp_plgn;
93 static struct display_backlight_ops *backlight_ops;
94 static struct timeval pressed_time;
95 static guint longkey_timeout_id = 0;
96 static guint longkey_restore_id = 0;
97 static guint displayon_by_powerkey_timeout_id = 0;
98 static int cancel_lcdoff;
99 static int key_combination = KEY_COMBINATION_STOP;
100 static double combination_pressed_time;
101 static bool touch_pressed = false;
102 static int skip_lcd_off = false;
103 static int skip_combination = false;
104 static int bezel_wakeup = true;
105 static int booting_check = true;
107 static inline int current_state_in_on(void)
110 enum syscommon_deviced_display_state current;
112 ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
113 DEVICED_DISPLAY_ATTR_INT_CURRENT_STATE, (int32_t *) ¤t);
117 return ((current == SYSCOMMON_DEVICED_DISPLAY_STATE_DIM) || (current == SYSCOMMON_DEVICED_DISPLAY_STATE_ON));
120 static inline void restore_custom_brightness(void)
124 enum syscommon_deviced_display_state current;
126 ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
127 DEVICED_DISPLAY_ATTR_INT_CURRENT_STATE, (int32_t *) ¤t);
131 display_backlight_get_custom_status(&custom_status);
132 if (current == SYSCOMMON_DEVICED_DISPLAY_STATE_DIM && custom_status)
133 display_backlight_update_by_custom_brightness();
136 static void pwroff_popup(void)
140 ret = launch_system_app(APP_POWERKEY, 2, APP_KEY_TYPE, APP_POWERKEY);
142 _E("Failed to launch power off popup.");
145 static void longkey_pressed(void)
149 _I("Power key long pressed!");
152 caps = display_get_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY);
154 if (display_has_caps(caps, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON)) {
155 /* change state - LCD on */
156 syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
157 DEVICED_DISPLAY_ATTR_TUPLE2_CURRENT_STATE,
158 SYSCOMMON_DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT_POWERKEY);
161 if (!display_has_caps(caps, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF)) {
162 _D("No poweroff capability!");
169 static gboolean longkey_restore_cb(void *data)
171 syscommon_notifier_emit_notify(DEVICED_NOTIFIER_LONGKEY_RESTORE, (void *)NULL);
172 longkey_restore_id = 0;
174 return G_SOURCE_REMOVE;
177 static gboolean longkey_pressed_cb(void *data)
180 longkey_timeout_id = 0;
182 return G_SOURCE_REMOVE;
185 static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
189 udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
190 udiff += (t2.tv_usec - t1.tv_usec);
195 static inline void check_key_pair(int code, int new, int *old)
198 _E("key pair is not matched! (%d, %d)", code, new);
203 static inline void broadcast_lcdon_by_powerkey(void)
205 gdbus_signal_emit(NULL,
206 DEVICED_PATH_DISPLAY,
207 DEVICED_INTERFACE_DISPLAY,
208 SIGNAL_LCDON_BY_POWERKEY,
212 static inline void broadcast_lcdoff_by_powerkey(void)
214 gdbus_signal_emit(NULL,
215 DEVICED_PATH_DISPLAY,
216 DEVICED_INTERFACE_DISPLAY,
217 SIGNAL_LCDOFF_BY_POWERKEY,
221 static inline bool switch_on_lcd(enum device_flags flags)
223 if (current_state_in_on())
226 if (display_panel_get_dpms_cached_state() == SYSCOMMON_DEVICED_DPMS_ON) {
227 if (ambient_get_state() == false)
231 if (flags & LCD_ON_BY_POWER_KEY)
232 broadcast_lcdon_by_powerkey();
233 else if (flags & LCD_ON_BY_TOUCH)
234 _I("Display on by Touch_wakeup event");
236 display_panel_lcd_on_direct(flags);
241 static inline void switch_off_lcd(void)
243 if (!current_state_in_on())
246 if (display_panel_get_dpms_cached_state() == SYSCOMMON_DEVICED_DPMS_OFF)
249 broadcast_lcdoff_by_powerkey();
251 display_panel_lcd_off_procedure(LCD_OFF_BY_POWER_KEY);
254 static void check_key_combination(struct input_event *pinput)
256 double press_time, diff_time;
257 press_time = (pinput->time).tv_sec + USEC_TO_SEC((pinput->time).tv_usec);
258 diff_time = press_time - combination_pressed_time;
260 switch (key_combination) {
261 case COMBINATION_SCREENCAPTURE:
262 if (diff_time <= CAPTURE_COMBINATION_INTERVAL) {
263 _I("Combination key : SCREENCAPTURE mode");
264 skip_combination = true;
267 case COMBINATION_TORCH:
268 if (diff_time <= TORCH_COMBINATION_INTERVAL) {
269 /* When torch combination, display control should be not change. */
270 if (displayon_by_powerkey_timeout_id) {
271 g_source_remove(displayon_by_powerkey_timeout_id);
272 displayon_by_powerkey_timeout_id = 0;
274 _I("Combination key : TORCH mode");
275 skip_combination = true;
277 key_combination = COMBINATION_STOP;
279 case COMBINATION_QUICKTALK:
280 if (diff_time <= DEFAULT_COMBINATION_INTERVAL) {
281 _I("Combination key : QUICK-TALK mode");
282 skip_combination = true;
283 if (longkey_timeout_id) {
284 g_source_remove(longkey_timeout_id);
285 longkey_timeout_id = 0;
290 combination_pressed_time = press_time;
296 static void start_key_combination(struct input_event *pinput)
298 switch (pinput->code) {
300 key_combination |= KEY_COMBINATION_POWERKEY;
303 key_combination |= KEY_COMBINATION_MENUKEY;
306 key_combination |= KEY_COMBINATION_VOLUMEUP;
309 key_combination |= KEY_COMBINATION_VOLUMEDOWN;
315 check_key_combination(pinput);
318 static void stop_key_combination(struct input_event *pinput)
320 if (pinput == NULL) {
321 key_combination = KEY_COMBINATION_STOP;
325 switch (pinput->code) {
327 key_combination &= ~KEY_COMBINATION_POWERKEY;
330 key_combination &= ~KEY_COMBINATION_MENUKEY;
333 key_combination &= ~KEY_COMBINATION_VOLUMEUP;
336 key_combination &= ~KEY_COMBINATION_VOLUMEDOWN;
339 _E("This code(%d) is not combination type.", pinput->code);
344 static void process_combination_key(struct input_event *pinput)
346 if (pinput->value == KEY_PRESSED)
347 start_key_combination(pinput);
348 else if (pinput->value == KEY_RELEASED)
349 stop_key_combination(pinput);
352 static int process_menu_key(struct input_event *pinput)
356 caps = display_get_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_MENU_KEY);
358 if (!display_has_caps(caps, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON)) {
359 if (current_state_in_on())
361 _D("No lcd-on capability!");
363 } else if (pinput->value == KEY_PRESSED)
364 switch_on_lcd(LCD_ON_BY_POWER_KEY);
369 static int decide_lcdoff(void)
371 /* It's not needed if it's already LCD off state */
372 if (!current_state_in_on() &&
373 display_panel_get_dpms_cached_state() != SYSCOMMON_DEVICED_DPMS_ON)
377 * This flag is set at the moment
378 * that LCD is turned on by power key
379 * LCD has not to turned off in the situation.
384 /* LCD is not turned off when powerkey is pressed,not released */
385 if (key_combination == KEY_COMBINATION_POWERKEY)
388 /* LCD-off is blocked at the moment poweroff popup shows */
392 /* LCD-off is blocked when powerkey and volmedown key are pressed */
393 if (skip_combination)
396 /* At booting time, display must do not turn off */
403 static int lcdoff_powerkey(void)
407 if (decide_lcdoff() == true) {
409 display_lock_release_lock_all(SYSCOMMON_DEVICED_DISPLAY_STATE_ON);
410 display_lock_release_lock_all(SYSCOMMON_DEVICED_DISPLAY_STATE_DIM);
411 display_state_transition_update_lcdoff_reason(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
412 syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
413 DEVICED_DISPLAY_ATTR_TUPLE2_CURRENT_STATE,
414 SYSCOMMON_DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT_POWERKEY);
417 skip_combination = false;
424 static int process_back_key(struct input_event *pinput)
428 if (pinput->value == KEY_PRESSED) {
429 switch_on_lcd(LCD_ON_BY_BACK_KEY);
430 _I("back key pressed");
437 static int process_power_key(struct input_event *pinput)
440 static int value = KEY_RELEASED;
442 const struct syscommon_deviced_display_config *display_conf = get_var_display_config();
444 _E("Failed to get display configuration variable.");
448 caps = display_get_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY);
450 switch (pinput->value) {
452 check_key_pair(pinput->code, pinput->value, &value);
454 if (!display_conf->powerkey_doublepress) {
455 if (display_has_caps(caps, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF))
458 _D("No lcdoff capability!");
459 } else if (skip_lcd_off)
462 if (!display_has_caps(caps, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON))
465 if (longkey_timeout_id > 0) {
466 g_source_remove(longkey_timeout_id);
467 longkey_timeout_id = 0;
470 if (longkey_restore_id > 0) {
471 g_source_remove(longkey_restore_id);
472 longkey_restore_id = 0;
477 if (display_has_caps(caps, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON)) {
478 skip_lcd_off = switch_on_lcd(LCD_ON_BY_POWER_KEY);
480 _D("No lcdon capability!");
481 skip_lcd_off = false;
483 check_key_pair(pinput->code, pinput->value, &value);
484 _I("power key pressed");
485 pressed_time.tv_sec = (pinput->time).tv_sec;
486 pressed_time.tv_usec = (pinput->time).tv_usec;
487 if (key_combination == KEY_COMBINATION_POWERKEY) {
488 /* add long key timer */
489 longkey_timeout_id = g_timeout_add_seconds(
490 display_conf->longpress_interval,
491 longkey_pressed_cb, NULL);
492 /* add long key restore timer */
493 longkey_restore_id = g_timeout_add_seconds(
494 LONGKEY_PRESSED_TIME,
495 longkey_restore_cb, NULL);
500 case KEY_BEING_PRESSED:
501 if (timediff_usec(pressed_time, pinput->time) >
502 (display_conf->longpress_interval * USEC_PER_SEC))
509 static int process_screenlock_key(struct input_event *pinput)
511 if (pinput->value != KEY_RELEASED) {
512 stop_key_combination(NULL);
516 if (!current_state_in_on())
519 display_lock_release_lock_all(SYSCOMMON_DEVICED_DISPLAY_STATE_ON);
520 display_lock_release_lock_all(SYSCOMMON_DEVICED_DISPLAY_STATE_DIM);
521 display_state_transition_update_lcdoff_reason(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
524 syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
525 DEVICED_DISPLAY_ATTR_TUPLE2_CURRENT_STATE,
526 SYSCOMMON_DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT_POWERKEY);
531 static void sound_vibrate_hardkey(void)
533 /* device notify(vibrator) */
535 /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangedHardKey signal */
536 gdbus_signal_emit(NULL,
538 DEVICED_INTERFACE_KEY,
539 SIGNAL_CHANGE_HARDKEY,
543 static void process_hardkey_backlight(struct input_event *pinput)
545 _E("pinput->value : %d", pinput->value);
546 if (pinput->value == KEY_PRESSED) {
547 /* Sound & Vibrate only in unlock state */
548 if (__get_lock_screen_state() == VCONFKEY_IDLE_UNLOCK
549 || get_lock_screen_bg_state())
550 sound_vibrate_hardkey();
552 touchled_control_backlight(TOUCHLED_PRESS);
553 } else if (pinput->value == KEY_RELEASED) {
554 /* if lockscreen is idle lock */
555 if (__get_lock_screen_state() == VCONFKEY_IDLE_LOCK) {
556 _D("Lock state, key backlight is off when phone is unlocked!");
560 touchled_control_backlight(TOUCHLED_RELEASE);
564 static void update_vital_state(struct input_event *pinput)
568 /* Change vital state to SYSCOMMON_DEVICED_VITAL_EXIT only if vital mode is active */
572 /* Touch or Menu Key Release Event */
573 if (pinput->type == EV_ABS || (pinput->type == EV_KEY &&
574 pinput->value == KEY_RELEASED && pinput->code == KEY_MENU)) {
575 /* Enable all services upon receiving user input, else maintain same state */
576 type = SYSCOMMON_DEVICED_VITAL_EXIT;
577 syscommon_notifier_emit_notify(DEVICED_NOTIFIER_VITAL_STATE, &type);
581 static int check_key(struct input_event *pinput)
585 process_combination_key(pinput);
586 switch (pinput->code) {
588 ignore = process_menu_key(pinput);
591 ignore = process_power_key(pinput);
592 if (current_state_in_on())
596 ignore = process_screenlock_key(pinput);
599 ignore = process_back_key(pinput);
600 stop_key_combination(NULL);
601 if (current_state_in_on()) {
602 process_hardkey_backlight(pinput);
607 stop_key_combination(NULL);
608 if (current_state_in_on()) {
609 process_hardkey_backlight(pinput);
615 if (current_state_in_on())
628 case KEY_PREVIOUSSONG:
630 case KEY_FASTFORWARD:
631 stop_key_combination(NULL);
632 if (current_state_in_on())
639 stop_key_combination(NULL);
642 stop_key_combination(NULL);
646 if (pinput->value == KEY_PRESSED)
647 pm_history_save(SYSCOMMON_DEVICED_POWER_LOG_TYPE_KEY_PRESS, pinput->code);
648 else if (pinput->value == KEY_RELEASED)
649 pm_history_save(SYSCOMMON_DEVICED_POWER_LOG_TYPE_KEY_RELEASE, pinput->code);
654 static void check_key_filter(struct timeval time, unsigned short type, unsigned short keycode, unsigned int keyvalue)
656 struct input_event *pinput = &(struct input_event) {
663 static int code, value;
665 enum syscommon_deviced_display_state current;
669 switch (pinput->type) {
671 if (pinput->code == BTN_TOUCH &&
672 pinput->value == KEY_RELEASED)
673 touch_pressed = false;
675 * Normally, touch press/release events don't occur
676 * in lcd off state. But touch release events can occur
677 * in the state abnormally. Then touch events are ignored
678 * when lcd is off state.
680 if (pinput->code == BTN_TOUCH && !current_state_in_on())
682 if (pinput->code == code && pinput->value == value) {
683 _E("Same key(%d, %d) is polled", code, value);
686 value = pinput->value;
688 update_vital_state(pinput);
689 ignore = check_key(pinput);
690 restore_custom_brightness();
694 ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
695 DEVICED_DISPLAY_ATTR_INT_CURRENT_STATE, (int32_t *) ¤t);
699 if (current == SYSCOMMON_DEVICED_DISPLAY_STATE_OFF && bezel_wakeup) {
700 switch_on_lcd(LCD_ON_BY_BEZEL);
702 } else if (current != SYSCOMMON_DEVICED_DISPLAY_STATE_OFF)
706 if (display_misc_is_touch_event_blocked()
707 && !g_display_plugin.config->touch_wakeup
708 && pinput->value == KEY_BEING_PRESSED)
711 update_vital_state(pinput);
712 if (pinput->value == KEY_PRESSED) {
713 switch_on_lcd(LCD_ON_BY_TOUCH);
717 if (current_state_in_on())
720 restore_custom_brightness();
722 if (pinput->value == KEY_PRESSED)
723 touch_pressed = true;
724 else if (pinput->value == KEY_RELEASED)
725 touch_pressed = false;
734 /* lcd on or update lcd timeout */
735 display_state_transition_do_state_transition_by_input_poll_event();
738 static int delayed_init_done(void *data)
745 static int bezel_wakeup_cb(void *data)
747 bezel_wakeup = (int)((intptr_t)data);
754 * powerkey := LCDON | LCDOFF | POWEROFF
757 static struct syscommon_deviced_display_actor_ops display_powerkey_actor = {
758 .id = SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY,
759 .caps = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON |
760 SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF |
761 SYSCOMMON_DEVICED_DISPLAY_CAPA_POWEROFF,
764 static struct syscommon_deviced_display_actor_ops display_menukey_actor = {
765 .id = SYSCOMMON_DEVICED_DISPLAY_ACTOR_MENU_KEY,
766 .caps = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON,
769 static void __CONSTRUCTOR__ initialize(void)
771 disp_plgn = get_var_display_plugin();
773 _E("Failed to get display plugin variable.");
775 backlight_ops = get_var_backlight_ops();
777 _E("Failed to get backlight operator variable.");
779 display_add_actor(&display_powerkey_actor);
780 display_add_actor(&display_menukey_actor);
782 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_DELAYED_INIT, delayed_init_done);
783 syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_BEZEL_WAKEUP, bezel_wakeup_cb);
785 input_register_event_callback(check_key_filter, NULL, NULL, NULL);