--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <glib.h>
+#include <linux/input.h>
+#include <sys/types.h>
+#include <vconf.h>
+
+#include <libsyscommon/ini-parser.h>
+#include <libsyscommon/log.h>
+#include <libsyscommon/libgdbus.h>
+#include <libsyscommon/notifier.h>
+#include <libsyscommon/resource-manager.h>
+#include <system/syscommon-plugin-common-interface.h>
+#include <system/syscommon-plugin-deviced-common-interface.h>
+#include <system/syscommon-plugin-deviced-input.h>
+#include <system/syscommon-plugin-deviced-input-interface.h>
+#include <system/syscommon-plugin-deviced-display-interface.h>
+#include <system/syscommon-plugin-deviced-power-interface.h>
+#include <system/syscommon-plugin-deviced-touchled-interface.h>
+
+#define EXPORT __attribute__ ((visibility("default")))
+
+#define BYTES_PER_LONG (sizeof(unsigned long))
+#define BITS_PER_LONG (BYTES_PER_LONG * 8)
+#define OFFSET(x) ((x) & (BITS_PER_LONG - 1))
+#define BIT(x) (1UL << OFFSET(x))
+#define USEC_TO_SEC(x) ((x)/1000000.0)
+
+#define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
+#define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
+#define SIGNAL_LCDOFF_BY_POWERKEY "LCDOffByPowerkey"
+
+#define USEC_PER_SEC 1000000
+#define USEC_PER_MSEC 1000
+
+#define LONGKEY_PRESSED_TIME 4 /* 4 second */
+
+#define CAPTURE_COMBINATION_INTERVAL 0.5 /* 0.5 second */
+#define TORCH_COMBINATION_INTERVAL 0.1 /* 0.1 second */
+#define DEFAULT_COMBINATION_INTERVAL 0.1 /* 0.1 second */
+
+enum key_combination_flags {
+ KEY_COMBINATION_STOP = 0,
+ KEY_COMBINATION_POWERKEY = BIT(0),
+ KEY_COMBINATION_MENUKEY = BIT(1),
+ KEY_COMBINATION_VOLUMEUP = BIT(2),
+ KEY_COMBINATION_VOLUMEDOWN = BIT(3),
+};
+
+enum combination_process {
+ COMBINATION_STOP = KEY_COMBINATION_STOP,
+ COMBINATION_SCREENCAPTURE = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_MENUKEY,
+ COMBINATION_TORCH = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_VOLUMEUP,
+ COMBINATION_QUICKTALK = KEY_COMBINATION_POWERKEY | KEY_COMBINATION_VOLUMEDOWN,
+};
+
+static struct timeval pressed_time;
+static guint longkey_timeout_id = 0;
+static guint longkey_restore_id = 0;
+static guint displayon_by_powerkey_timeout_id = 0;
+static int cancel_lcdoff;
+static int key_combination = KEY_COMBINATION_STOP;
+static double combination_pressed_time;
+static bool touch_pressed = false;
+static int skip_lcd_off = false;
+static int skip_combination = false;
+static int booting_check = true;
+
+/* FIXME: This module needs actual operation test in mobile target */
+static inline int current_state_in_on(void)
+{
+ int ret;
+ enum syscommon_deviced_display_state current;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CURRENT_STATE, (int32_t *) ¤t);
+ if (ret < 0)
+ return 0;
+
+ return ((current == SYSCOMMON_DEVICED_DISPLAY_STATE_DIM) || (current == SYSCOMMON_DEVICED_DISPLAY_STATE_ON));
+}
+
+static inline void restore_custom_brightness(void)
+{
+ bool custom_status;
+ int ret;
+ enum syscommon_deviced_display_state current;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CURRENT_STATE, (int32_t *) ¤t);
+ if (ret < 0)
+ return;
+
+ if (current != SYSCOMMON_DEVICED_DISPLAY_STATE_DIM)
+ return;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CUSTOM_BRIGHTNESS,
+ (int32_t *) &custom_status);
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CUSTOM_BRIGHTNESS,
+ custom_status);
+}
+
+static void longkey_pressed(void)
+{
+ unsigned int caps;
+ enum syscommon_deviced_display_actor_id actor_power_key = SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY;
+ enum syscommon_deviced_display_capability lcdon_cap = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON;
+ enum syscommon_deviced_display_capability lcdoff_cap = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF;
+
+ _I("Power key long pressed!");
+ cancel_lcdoff = 1;
+
+ syscommon_resman_get_resource_attr_uint64_with_2_user_data(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_UINT64_ACTOR_CAPABILITY,
+ (u_int64_t *) &actor_power_key,
+ (u_int64_t *) &lcdon_cap,
+ (u_int64_t *) &caps);
+
+ if (caps) {
+ /* change state - LCD on */
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT_POWERKEY);
+ }
+
+ syscommon_resman_get_resource_attr_uint64_with_2_user_data(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_UINT64_ACTOR_CAPABILITY,
+ (u_int64_t *) &actor_power_key,
+ (u_int64_t *) &lcdoff_cap,
+ (u_int64_t *) &caps);
+
+ if (!caps) {
+ _D("No poweroff capability!");
+ return;
+ }
+}
+
+static gboolean longkey_restore_cb(void *data)
+{
+ syscommon_notifier_emit_notify(DEVICED_NOTIFIER_LONGKEY_RESTORE, (void *)NULL);
+ longkey_restore_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean longkey_pressed_cb(void *data)
+{
+ longkey_pressed();
+ longkey_timeout_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+static unsigned long timediff_usec(struct timeval t1, struct timeval t2)
+{
+ unsigned long udiff;
+
+ udiff = (t2.tv_sec - t1.tv_sec) * USEC_PER_SEC;
+ udiff += (t2.tv_usec - t1.tv_usec);
+
+ return udiff;
+}
+
+static inline void check_key_pair(int code, int new, int *old)
+{
+ if (new == *old)
+ _E("key pair is not matched! (%d, %d)", code, new);
+ else
+ *old = new;
+}
+
+static inline void broadcast_lcdon_by_powerkey(void)
+{
+ gdbus_signal_emit(NULL,
+ DEVICED_PATH_DISPLAY,
+ DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_LCDON_BY_POWERKEY,
+ NULL);
+}
+
+static inline void broadcast_lcdoff_by_powerkey(void)
+{
+ gdbus_signal_emit(NULL,
+ DEVICED_PATH_DISPLAY,
+ DEVICED_INTERFACE_DISPLAY,
+ SIGNAL_LCDOFF_BY_POWERKEY,
+ NULL);
+}
+
+static inline bool switch_on_lcd(enum deviced_event reason)
+{
+ if (current_state_in_on())
+ return false;
+
+ if (reason == DEVICED_EVENT_INPUT_POWERKEY)
+ broadcast_lcdon_by_powerkey();
+ else if (reason == DEVICED_EVENT_TOUCHSCREEN)
+ _I("Display on by Touch_wakeup event");
+
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_DISPLAY_DIRECT,
+ SYSCOMMON_DEVICED_DPMS_ON,
+ reason);
+
+ return true;
+}
+
+static inline void switch_off_lcd(void)
+{
+ int dpms_state;
+
+ if (!current_state_in_on())
+ return;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE,
+ (int32_t *) &dpms_state);
+ if (dpms_state == SYSCOMMON_DEVICED_DPMS_OFF)
+ return;
+
+ broadcast_lcdoff_by_powerkey();
+
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_DISPLAY_DIRECT,
+ SYSCOMMON_DEVICED_DPMS_OFF,
+ DEVICED_EVENT_INPUT_POWERKEY);
+}
+
+static void update_vital_state(struct input_event *pinput)
+{
+ int vital_mode;
+ /* Change vital state to SYSCOMMON_DEVICED_VITAL_EXIT only if vital mode is active */
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
+ DEVICED_POWER_ATTR_INT_VITAL_MODE,
+ &vital_mode);
+ if (!vital_mode)
+ return;
+
+ /* Touch or Menu Key Release Event */
+ if (pinput->type == EV_ABS || (pinput->type == EV_KEY &&
+ pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_RELEASED && pinput->code == KEY_MENU)) {
+ /* Enable all services upon receiving user input, else maintain same state */
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
+ DEVICED_POWER_ATTR_INT_VITAL_MODE, SYSCOMMON_DEVICED_VITAL_EXIT);
+ }
+}
+
+static void check_key_combination(struct input_event *pinput)
+{
+ double press_time, diff_time;
+ press_time = (pinput->time).tv_sec + USEC_TO_SEC((pinput->time).tv_usec);
+ diff_time = press_time - combination_pressed_time;
+
+ switch (key_combination) {
+ case COMBINATION_SCREENCAPTURE:
+ if (diff_time <= CAPTURE_COMBINATION_INTERVAL) {
+ _I("Combination key : SCREENCAPTURE mode");
+ skip_combination = true;
+ }
+ break;
+ case COMBINATION_TORCH:
+ if (diff_time <= TORCH_COMBINATION_INTERVAL) {
+ /* When torch combination, display control should be not change. */
+ if (displayon_by_powerkey_timeout_id) {
+ g_source_remove(displayon_by_powerkey_timeout_id);
+ displayon_by_powerkey_timeout_id = 0;
+ }
+ _I("Combination key : TORCH mode");
+ skip_combination = true;
+ } else
+ key_combination = COMBINATION_STOP;
+ break;
+ case COMBINATION_QUICKTALK:
+ if (diff_time <= DEFAULT_COMBINATION_INTERVAL) {
+ _I("Combination key : QUICK-TALK mode");
+ skip_combination = true;
+ if (longkey_timeout_id) {
+ g_source_remove(longkey_timeout_id);
+ longkey_timeout_id = 0;
+ }
+ }
+ break;
+ default:
+ combination_pressed_time = press_time;
+ return;
+ }
+}
+
+static void start_key_combination(struct input_event *pinput)
+{
+ switch (pinput->code) {
+ case KEY_POWER:
+ key_combination |= KEY_COMBINATION_POWERKEY;
+ break;
+ case KEY_MENU:
+ key_combination |= KEY_COMBINATION_MENUKEY;
+ break;
+ case KEY_VOLUMEUP:
+ key_combination |= KEY_COMBINATION_VOLUMEUP;
+ break;
+ case KEY_VOLUMEDOWN:
+ key_combination |= KEY_COMBINATION_VOLUMEDOWN;
+ break;
+ default:
+ return;
+ }
+
+ check_key_combination(pinput);
+}
+
+static void stop_key_combination(struct input_event *pinput)
+{
+ if (pinput == NULL) {
+ key_combination = KEY_COMBINATION_STOP;
+ return;
+ }
+
+ switch (pinput->code) {
+ case KEY_POWER:
+ key_combination &= ~KEY_COMBINATION_POWERKEY;
+ break;
+ case KEY_MENU:
+ key_combination &= ~KEY_COMBINATION_MENUKEY;
+ break;
+ case KEY_VOLUMEUP:
+ key_combination &= ~KEY_COMBINATION_VOLUMEUP;
+ break;
+ case KEY_VOLUMEDOWN:
+ key_combination &= ~KEY_COMBINATION_VOLUMEDOWN;
+ break;
+ default:
+ _E("This code(%d) is not combination type.", pinput->code);
+ break;
+ }
+}
+
+static void process_combination_key(struct input_event *pinput)
+{
+ if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED)
+ start_key_combination(pinput);
+ else if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_RELEASED)
+ stop_key_combination(pinput);
+}
+
+
+static int process_menu_key(struct input_event *pinput)
+{
+ int caps;
+ enum syscommon_deviced_display_actor_id actor_menu_key = SYSCOMMON_DEVICED_DISPLAY_ACTOR_MENU_KEY;
+ enum syscommon_deviced_display_capability lcdon_cap = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON;
+
+ syscommon_resman_get_resource_attr_uint64_with_2_user_data(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_UINT64_ACTOR_CAPABILITY,
+ (u_int64_t *) &actor_menu_key,
+ (u_int64_t *) &lcdon_cap,
+ (u_int64_t *) &caps);
+ if (!caps) {
+ if (current_state_in_on())
+ return false;
+ _D("No lcd-on capability!");
+ return true;
+ } else if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED)
+ switch_on_lcd(DEVICED_EVENT_INPUT_POWERKEY);
+
+ return false;
+}
+
+static int decide_lcdoff(void)
+{
+ int dpms_state;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE,
+ (int32_t *) &dpms_state);
+
+ /* It's not needed if it's already LCD off state */
+ if (!current_state_in_on() && dpms_state != SYSCOMMON_DEVICED_DPMS_ON)
+ return false;
+
+ /*
+ * This flag is set at the moment
+ * that LCD is turned on by power key
+ * LCD has not to turned off in the situation.
+ */
+ if (skip_lcd_off)
+ return false;
+
+ /* LCD is not turned off when powerkey is pressed,not released */
+ if (key_combination == KEY_COMBINATION_POWERKEY)
+ return false;
+
+ /* LCD-off is blocked at the moment poweroff popup shows */
+ if (cancel_lcdoff)
+ return false;
+
+ /* LCD-off is blocked when powerkey and volmedown key are pressed */
+ if (skip_combination)
+ return false;
+
+ /* At booting time, display must do not turn off */
+ if (booting_check)
+ return false;
+
+ return true;
+}
+
+static int lcdoff_powerkey(void)
+{
+ int ignore = true;
+
+ if (decide_lcdoff() == true) {
+ switch_off_lcd();
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_RELEASE_LOCK_ALL,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_ON);
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_RELEASE_LOCK_ALL,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_DIM);
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_LCDOFF_REASON,
+ DEVICED_EVENT_INPUT_POWERKEY);
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT_POWERKEY);
+ } else {
+ ignore = false;
+ skip_combination = false;
+ }
+ cancel_lcdoff = 0;
+
+ return ignore;
+}
+
+static bool key_check_display_on(void)
+{
+ int dpms_state;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE,
+ (int32_t *) &dpms_state);
+
+ if (current_state_in_on())
+ return false;
+
+ if (dpms_state == SYSCOMMON_DEVICED_DPMS_ON) {
+ _W("display power was on");
+ return false;
+ }
+
+ return true;
+}
+
+
+static gboolean display_on_cb(void *data)
+{
+ int dpms_state;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE,
+ (int32_t *) &dpms_state);
+
+ if (displayon_by_powerkey_timeout_id == 0)
+ return G_SOURCE_REMOVE;
+
+ displayon_by_powerkey_timeout_id = 0;
+ if (dpms_state != SYSCOMMON_DEVICED_DPMS_ON || current_state_in_on() == false) {
+ broadcast_lcdon_by_powerkey();
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_DISPLAY_DIRECT,
+ SYSCOMMON_DEVICED_DPMS_ON,
+ DEVICED_EVENT_INPUT_POWERKEY);
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_STATE_TRANSITION,
+ DEVICED_EVENT_INPUT);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static int process_back_key(struct input_event *pinput)
+{
+ int ignore = true;
+
+ if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED) {
+ switch_on_lcd(DEVICED_EVENT_INPUT_BACKKEY);
+ _I("back key pressed");
+ ignore = false;
+ }
+
+ return ignore;
+}
+
+static int process_power_key(struct input_event *pinput)
+{
+ int ignore = true;
+ static int value = SYSCOMMON_DEVICED_INPUT_KEY_RELEASED;
+ int dpms_state;
+ int powerkey_doublepress;
+ double longpress_interval;
+ unsigned int lcdoff_caps;
+ unsigned int lcdon_caps;
+ enum syscommon_deviced_display_actor_id actor_power_key = SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY;
+ enum syscommon_deviced_display_capability lcdon_cap = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON;
+ enum syscommon_deviced_display_capability lcdoff_cap = SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF;
+
+ syscommon_resman_get_resource_attr_uint64_with_2_user_data(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_UINT64_ACTOR_CAPABILITY,
+ (u_int64_t *) &actor_power_key,
+ (u_int64_t *) &lcdoff_cap,
+ (u_int64_t *) &lcdoff_caps);
+ syscommon_resman_get_resource_attr_uint64_with_2_user_data(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_UINT64_ACTOR_CAPABILITY,
+ (u_int64_t *) &actor_power_key,
+ (u_int64_t *) &lcdon_cap,
+ (u_int64_t *) &lcdon_caps);
+ syscommon_resman_get_resource_attr_double(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_DOUBLE_CONFIG_LONGPRESS_INTERVAL,
+ (double *) &longpress_interval);
+
+ switch (pinput->value) {
+ case SYSCOMMON_DEVICED_INPUT_KEY_RELEASED:
+ check_key_pair(pinput->code, pinput->value, &value);
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CONFIG_POWERKEY_DOUBLEPRESS,
+ (int32_t *) &powerkey_doublepress);
+ if (!powerkey_doublepress) {
+ if (lcdoff_caps)
+ lcdoff_powerkey();
+ else
+ _D("No lcdoff capability!");
+ } else if (skip_lcd_off)
+ ignore = false;
+
+ if (!lcdon_caps)
+ ignore = true;
+
+ if (longkey_timeout_id > 0) {
+ g_source_remove(longkey_timeout_id);
+ longkey_timeout_id = 0;
+ }
+
+ if (longkey_restore_id > 0) {
+ g_source_remove(longkey_restore_id);
+ longkey_restore_id = 0;
+ }
+
+ break;
+ case SYSCOMMON_DEVICED_INPUT_KEY_PRESSED:
+ if (lcdon_caps) {
+ /*
+ * LCD does not turn on immediately at mobile.
+ * It will be turned on after 0.1 second because of torch concept.
+ */
+ skip_lcd_off = key_check_display_on();
+ ignore = true;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE,
+ (int32_t *) &dpms_state);
+ if (!displayon_by_powerkey_timeout_id &&
+ dpms_state != SYSCOMMON_DEVICED_DPMS_ON &&
+ key_combination != COMBINATION_TORCH) {
+ displayon_by_powerkey_timeout_id = g_timeout_add(
+ 100,
+ display_on_cb, NULL);
+ }
+ } else {
+ _D("No lcdon capability!");
+ skip_lcd_off = false;
+ }
+ check_key_pair(pinput->code, pinput->value, &value);
+ _I("power key pressed");
+ pressed_time.tv_sec = (pinput->time).tv_sec;
+ pressed_time.tv_usec = (pinput->time).tv_usec;
+ if (key_combination == KEY_COMBINATION_POWERKEY) {
+ /* add long key timer */
+ longkey_timeout_id = g_timeout_add(
+ longpress_interval,
+ longkey_pressed_cb, NULL);
+ /* add long key restore timer */
+ longkey_restore_id = g_timeout_add_seconds(
+ LONGKEY_PRESSED_TIME,
+ longkey_restore_cb, NULL);
+ }
+ cancel_lcdoff = 0;
+
+ break;
+ case SYSCOMMON_DEVICED_INPUT_KEY_BEING_PRESSED:
+ if (timediff_usec(pressed_time, pinput->time) > (longpress_interval * USEC_PER_MSEC))
+ longkey_pressed();
+ break;
+ }
+ return ignore;
+}
+
+static int process_screenlock_key(struct input_event *pinput)
+{
+ if (pinput->value != SYSCOMMON_DEVICED_INPUT_KEY_RELEASED) {
+ stop_key_combination(NULL);
+ return true;
+ }
+
+ if (!current_state_in_on())
+ return false;
+
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_RELEASE_LOCK_ALL,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_ON);
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_RELEASE_LOCK_ALL,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_DIM);
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_LCDOFF_REASON,
+ DEVICED_EVENT_INPUT_POWERKEY);
+
+ /* LCD off forcly */
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT_POWERKEY);
+
+ return true;
+}
+
+static void sound_vibrate_hardkey(void)
+{
+ /* device notify(vibrator) */
+ /* sound(dbus) */
+ /* Need to notify to deviced-vibrator. deviced-vibrator receives ChangedHardKey signal */
+ gdbus_signal_emit(NULL,
+ DEVICED_PATH_KEY,
+ DEVICED_INTERFACE_KEY,
+ SIGNAL_CHANGE_HARDKEY,
+ NULL);
+}
+
+static void process_hardkey_backlight(struct input_event *pinput)
+{
+ int lockscreen_state = VCONFKEY_IDLE_UNLOCK;
+ int lockscreen_bg_state = 0;
+
+ _D("pinput->value : %d", pinput->value);
+
+ syscommon_resman_get_resource_attr_int(
+ SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_LOCKSCREEN_STATE, &lockscreen_state);
+ syscommon_resman_get_resource_attr_int(
+ SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_LOCKSCREEN_BG_STATE, &lockscreen_bg_state);
+
+ if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED) {
+ /* Sound & Vibrate only in unlock state */
+ if (lockscreen_state == VCONFKEY_IDLE_UNLOCK || lockscreen_bg_state)
+ sound_vibrate_hardkey();
+
+ syscommon_resman_set_resource_attr_int(
+ SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_TOUCHLED),
+ DEVICED_TOUCHLED_ATTR_INT_BACKLIGHT,
+ SYSCOMMON_DEVICED_TOUCHLED_PRESS);
+ } else if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_RELEASED) {
+ /* if lockscreen is idle lock */
+ if (lockscreen_state == VCONFKEY_IDLE_LOCK) {
+ _D("Lock state, key backlight is off when phone is unlocked!");
+ return;
+ }
+
+ syscommon_resman_set_resource_attr_int(
+ SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_TOUCHLED),
+ DEVICED_TOUCHLED_ATTR_INT_BACKLIGHT,
+ SYSCOMMON_DEVICED_TOUCHLED_RELEASE);
+ }
+}
+
+static int check_key(struct input_event *pinput)
+{
+ int ignore = true;
+
+ process_combination_key(pinput);
+ switch (pinput->code) {
+ case KEY_MENU:
+ ignore = process_menu_key(pinput);
+ break;
+ case KEY_POWER:
+ ignore = process_power_key(pinput);
+ if (current_state_in_on())
+ ignore = false;
+ break;
+ case KEY_SCREENLOCK:
+ ignore = process_screenlock_key(pinput);
+ break;
+ case KEY_BACK:
+ ignore = process_back_key(pinput);
+ stop_key_combination(NULL);
+ if (current_state_in_on()) {
+ process_hardkey_backlight(pinput);
+ ignore = false;
+ }
+ break;
+ case KEY_PHONE:
+ stop_key_combination(NULL);
+ if (current_state_in_on()) {
+ process_hardkey_backlight(pinput);
+ ignore = false;
+ }
+ break;
+ case KEY_VOLUMEUP:
+ case KEY_VOLUMEDOWN:
+ if (current_state_in_on())
+ ignore = false;
+ break;
+ case KEY_CAMERA:
+ case KEY_EXIT:
+ case KEY_CONFIG:
+ case KEY_MEDIA:
+ case KEY_MUTE:
+ case KEY_PLAYPAUSE:
+ case KEY_PLAYCD:
+ case KEY_PAUSECD:
+ case KEY_STOPCD:
+ case KEY_NEXTSONG:
+ case KEY_PREVIOUSSONG:
+ case KEY_REWIND:
+ case KEY_FASTFORWARD:
+ stop_key_combination(NULL);
+ if (current_state_in_on())
+ ignore = false;
+ break;
+ case 0x1DB:
+ case 0x1DC:
+ case 0x1DD:
+ case 0x1DE:
+ stop_key_combination(NULL);
+ break;
+ default:
+ stop_key_combination(NULL);
+ ignore = false;
+ }
+#ifdef ENABLE_PM_LOG
+ if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED)
+ pm_history_save(SYSCOMMON_DEVICED_POWER_LOG_TYPE_KEY_PRESS, pinput->code);
+ else if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_RELEASED)
+ pm_history_save(SYSCOMMON_DEVICED_POWER_LOG_TYPE_KEY_RELEASE, pinput->code);
+#endif
+ return ignore;
+}
+
+static void check_key_filter(struct timeval time, unsigned short type, unsigned short keycode, unsigned int keyvalue)
+{
+ struct input_event *pinput = &(struct input_event) {
+ .time = time,
+ .type = type,
+ .code = keycode,
+ .value = keyvalue
+ };
+ int ignore = true;
+ static int code, value;
+ int ret;
+ enum syscommon_deviced_display_state current;
+ int touch_event_blocked;
+ int touch_event_wakeup_config;
+
+ assert(pinput);
+
+ switch (pinput->type) {
+ case EV_KEY:
+ if (pinput->code == BTN_TOUCH &&
+ pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_RELEASED)
+ touch_pressed = false;
+ /*
+ * Normally, touch press/release events don't occur
+ * in lcd off state. But touch release events can occur
+ * in the state abnormally. Then touch events are ignored
+ * when lcd is off state.
+ */
+ if (pinput->code == BTN_TOUCH && !current_state_in_on())
+ break;
+ if (pinput->code == code && pinput->value == value) {
+ _E("Same key(%d, %d) is polled", code, value);
+ }
+ code = pinput->code;
+ value = pinput->value;
+
+ update_vital_state(pinput);
+ ignore = check_key(pinput);
+ restore_custom_brightness();
+
+ break;
+ case EV_REL:
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CURRENT_STATE, (int32_t *) ¤t);
+ if (ret < 0)
+ break;
+
+ if (current == SYSCOMMON_DEVICED_DISPLAY_STATE_OFF) {
+ switch_on_lcd(DEVICED_EVENT_INPUT_BEZEL);
+ ignore = false;
+ } else if (current != SYSCOMMON_DEVICED_DISPLAY_STATE_OFF)
+ ignore = false;
+ break;
+ case EV_ABS:
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_TOUCH_EVENT_BLOCKED,
+ (int32_t *) &touch_event_blocked);
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CONFIG_TOUCH_WAKEUP,
+ (int32_t *) &touch_event_wakeup_config);
+ if (touch_event_blocked
+ && !touch_event_wakeup_config
+ && pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_BEING_PRESSED)
+ return;
+
+ update_vital_state(pinput);
+ if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED) {
+ switch_on_lcd(DEVICED_EVENT_TOUCHSCREEN);
+ ignore = false;
+ }
+
+ if (current_state_in_on())
+ ignore = false;
+
+ restore_custom_brightness();
+
+ if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_PRESSED)
+ touch_pressed = true;
+ else if (pinput->value == SYSCOMMON_DEVICED_INPUT_KEY_RELEASED)
+ touch_pressed = false;
+ break;
+ case EV_SW:
+ break;
+ }
+
+ if (ignore)
+ return;
+
+ /* lcd on or update lcd timeout */
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_STATE_TRANSITION,
+ DEVICED_EVENT_INPUT);
+}
+
+static int delayed_init_done(void *data)
+{
+ booting_check = 0;
+
+ return 0;
+}
+
+static syscommon_plugin_backend_deviced_input_funcs g_input_funcs = {
+ .input_event_cb = check_key_filter,
+};
+
+static int deviced_input_init(void **data)
+{
+ if (!data)
+ return -EINVAL;
+
+ *data = (void *)&g_input_funcs;
+ syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_DELAYED_INIT, delayed_init_done);
+
+ return 0;
+}
+
+static int deviced_input_exit(void *data)
+{
+ return 0;
+}
+
+syscommon_plugin_backend EXPORT system_plugin_backend_deviced_input_data = {
+ .name = "deviced-input",
+ .vendor = "Samsung",
+ .init = deviced_input_init,
+ .exit = deviced_input_exit,
+};