* limitations under the License.
*/
-#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <vconf.h>
+#include <sys/types.h>
+#include <linux/input.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-display-interface.h>
+#include <system/syscommon-plugin-deviced-power-interface.h>
#include <system/syscommon-plugin-deviced-input.h>
#include <system/syscommon-plugin-deviced-input-interface.h>
#define EXPORT __attribute__ ((visibility("default")))
-static syscommon_plugin_backend_deviced_input_funcs g_input_funcs;
+#ifndef KEY_SCREENLOCK
+#define KEY_SCREENLOCK 0x98
+#endif
+#ifndef SW_GLOVE
+#define SW_GLOVE 0x16
+#endif
+
+#define USEC_PER_SEC 1000000
+
+#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 */
+
+#define LONGKEY_PRESSED_TIME 4 /* 4 second */
+
+#define SIGNAL_CHANGE_HARDKEY "ChangeHardkey"
+#define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
+#define SIGNAL_LCDOFF_BY_POWERKEY "LCDOffByPowerkey"
+
+/**
+ * FIXME: Move it to the libsyscommon. Fix it and so does the deviced.
+ */
+#define KEY_RELEASED 0
+#define KEY_PRESSED 1
+#define KEY_BEING_PRESSED 2
+
+enum key_combination_flags {
+ KEY_COMBINATION_STOP = 0,
+ KEY_COMBINATION_POWERKEY = (1 << 0),
+ KEY_COMBINATION_MENUKEY = (1 << 1),
+ KEY_COMBINATION_VOLUMEUP = (1 << 2),
+ KEY_COMBINATION_VOLUMEDOWN = (1 << 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 bezel_wakeup = true;
+static int booting_check = true;
+
+#define POPUP_METHOD "PopupLaunch"
+#define APP_POWERKEY "powerkey"
+#define APP_OVERHEAT "overheat"
+#define APP_DEFAULT "system"
+#define APP_ABNORMAL "abnormal"
+#define APP_REMOVE "remove"
+#define APP_KEY_TYPE "_SYSPOPUP_CONTENT_"
-static void deviced_input_event_cb(struct timeval time, unsigned short type,
- unsigned short keycode, unsigned int keyvalue)
+static const struct app_dbus_match {
+ const char *type;
+ const char *bus;
+ const char *path;
+ const char *iface;
+ const char *method;
+} app_match[] = {
+ { APP_DEFAULT , POPUP_BUS_NAME, POPUP_PATH_SYSTEM , POPUP_INTERFACE_SYSTEM , POPUP_METHOD },
+ { APP_POWERKEY, POPUP_BUS_NAME, POPUP_PATH_POWERKEY, POPUP_INTERFACE_POWERKEY, POPUP_METHOD },
+ { APP_OVERHEAT, POPUP_BUS_NAME, POPUP_PATH_OVERHEAT, POPUP_INTERFACE_OVERHEAT, POPUP_METHOD },
+ { APP_ABNORMAL, POPUP_BUS_NAME, POPUP_PATH_SYSTEM , POPUP_INTERFACE_SYSTEM , POPUP_METHOD },
+ { APP_REMOVE , POPUP_BUS_NAME, POPUP_PATH_SYSTEM , POPUP_INTERFACE_SYSTEM , POPUP_METHOD },
+};
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+static void __cb(GVariant *var, void *user_data, GError *err)
{
+ int ret;
+
+ if (!var) {
+ _E("No message: %s", err->message);
+ return;
+ }
+
+ if (!g_variant_get_safe(var, "(i)", &ret)) {
+ _E("No message: %s", g_variant_get_type_string(var));
+ goto out;
+ }
+
+ _D("Reply value: %d", ret);
+
+out:
+ g_variant_unref(var);
}
-static int deviced_input_init(void **data)
+static int launch_system_app(char *type, int num, ...)
{
- *data = (void *)&g_input_funcs;
+ char *app_type;
+ va_list args;
+ int i, match, ret;
+
+ if (type)
+ app_type = type;
+ else
+ app_type = APP_DEFAULT;
+
+ match = -1;
+ for (i = 0 ; i < ARRAY_SIZE(app_match) ; i++) {
+ if (strncmp(app_type, app_match[i].type, strlen(app_type)))
+ continue;
+ match = i;
+ break;
+ }
+ if (match < 0) {
+ _E("Failed to find matched app type(%s).", app_type);
+ return -EINVAL;
+ }
+
+ va_start(args, num);
+
+ ret = gdbus_call_pairs_async_with_reply(app_match[match].bus,
+ app_match[match].path,
+ app_match[match].iface,
+ app_match[match].method,
+ num,
+ args,
+ __cb,
+ -1,
+ NULL);
+ va_end(args);
+
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_SET_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_ON,
+ DEVICED_EVENT_MISC_POPUP);
+
+ return ret;
+}
+
+static int is_lockscreen_enabled(void)
+{
+ int ret;
+ int enabled;
+
+ ret = vconf_get_int(VCONFKEY_IDLE_LOCK_STATE, &enabled);
+
+ return (ret == 0 && enabled) ? VCONFKEY_IDLE_LOCK : VCONFKEY_IDLE_UNLOCK;
+}
+
+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_GET_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_GET_CURRENT_STATE, (int32_t *) ¤t);
+ if (ret < 0)
+ return;
+
+ syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CUSTOM_BRIGHTNESS, (int *) &custom_status);
+ if (current == SYSCOMMON_DEVICED_DISPLAY_STATE_DIM && custom_status)
+ syscommon_resman_set_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_CUSTOM_BRIGHTNESS, true);
+}
+
+static int set_lcdoff_reason(int source)
+{
+ int ret;
+
+ switch (source) {
+ case VCONFKEY_PM_LCDOFF_BY_TIMEOUT:
+ _I("LCD OFF by timeout.");
+ break;
+ case VCONFKEY_PM_LCDOFF_BY_POWERKEY:
+ _I("LCD OFF by powerkey.");
+ break;
+ default:
+ _E("Invalid value(%d).", source);
+ return -EINVAL;
+ }
+ ret = vconf_set_int(VCONFKEY_PM_LCDOFF_SOURCE, source);
+ if (ret < 0) {
+ _E("Failed to set vconf value for lcd off source: %d", vconf_get_ext_errno());
+ return -EPERM;
+ }
return 0;
}
-static int deviced_input_exit(void *data)
+static void pwroff_popup(void)
+{
+ int ret;
+
+ ret = launch_system_app(APP_POWERKEY, 2, APP_KEY_TYPE, APP_POWERKEY);
+ if (ret < 0)
+ _E("Failed to launch power off popup.");
+}
+
+static int check_actor_caps(int actor_id, unsigned int caps)
+{
+ int ret = 0;
+ u_int64_t capability = 0;
+
+ ret = syscommon_resman_get_resource_attr_uint64_with_2_user_data(
+ SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_UINT64_GET_ACTOR_CAPABILITY,
+ (u_int64_t *) &actor_id,
+ (u_int64_t *) &caps,
+ &capability);
+
+ if (ret < 0)
+ return 0; /* no capability */
+
+ return capability;
+}
+
+static void longkey_pressed(void)
+{
+ _I("Power key long pressed!");
+ cancel_lcdoff = 1;
+ if (check_actor_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON)) {
+ /* change state - LCD on */
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_SET_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT_POWERKEY);
+ }
+
+ if (!check_actor_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF)) {
+ _D("No poweroff capability!");
+ return;
+ }
+
+ pwroff_popup();
+}
+
+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)
+{
+ int dpms_state;
+ int ret;
+
+ if (current_state_in_on())
+ return false;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE, &dpms_state);
+ if (ret == 0 && dpms_state == SYSCOMMON_DEVICED_DPMS_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");
+ else
+ reason = DEVICED_EVENT_UNKNOWN;
+
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_SET_DISPLAY_DIRECT, SYSCOMMON_DEVICED_DPMS_ON, reason);
+
+ return true;
+}
+
+static inline void switch_off_lcd(void)
+{
+ int dpms_state;
+ int ret;
+
+ if (!current_state_in_on())
+ return;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE, &dpms_state);
+ if (ret == 0 && 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_SET_DISPLAY_DIRECT, SYSCOMMON_DEVICED_DPMS_OFF, DEVICED_EVENT_INPUT_POWERKEY);
+}
+
+static void check_key_combination(struct input_event *pinput)
+{
+ double press_time, diff_time;
+ press_time = (pinput->time).tv_sec + ((pinput->time).tv_usec / 1000000.0);
+ 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 == KEY_PRESSED)
+ start_key_combination(pinput);
+ else if (pinput->value == KEY_RELEASED)
+ stop_key_combination(pinput);
+}
+
+static int process_menu_key(struct input_event *pinput)
+{
+ if (!check_actor_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_MENU_KEY, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON)) {
+ if (current_state_in_on())
+ return false;
+ _D("No lcd-on capability!");
+ return true;
+ } else if (pinput->value == KEY_PRESSED)
+ switch_on_lcd(DEVICED_EVENT_INPUT_POWERKEY);
+
+ return false;
+}
+
+static int decide_lcdoff(void)
+{
+ int dpms_state;
+ int ret;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_DPMS_STATE, &dpms_state);
+
+ if (ret < 0)
+ return false;
+
+ /* 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_SET_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_SET_RELEASE_LOCK_ALL, SYSCOMMON_DEVICED_DISPLAY_STATE_DIM);
+ set_lcdoff_reason(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_SET_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_OFF, DEVICED_EVENT_INPUT_POWERKEY);
+ } else {
+ ignore = false;
+ skip_combination = false;
+ }
+ cancel_lcdoff = 0;
+
+ return ignore;
+}
+
+static int process_back_key(struct input_event *pinput)
+{
+ int ignore = true;
+
+ if (pinput->value == 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 = KEY_RELEASED;
+ int powerkey_doublepress;
+ double longpress_interval;
+ int ret;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_GET_CONFIG_POWERKEY_DOUBLEPRESS, &powerkey_doublepress);
+ if (ret < 0) /* TODO : Haven't checked returning false is correct */
+ return false;
+
+ ret = syscommon_resman_get_resource_attr_double(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_DOUBLE_GET_CONFIG_LONGPRESS_INTERVAL, &longpress_interval);
+ if (ret < 0) /* TODO : Haven't checked returning false is correct */
+ return false;
+
+ switch (pinput->value) {
+ case KEY_RELEASED:
+ check_key_pair(pinput->code, pinput->value, &value);
+
+
+ if (!powerkey_doublepress) {
+ if (check_actor_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF))
+
+ lcdoff_powerkey();
+ else
+ _D("No lcdoff capability!");
+ } else if (skip_lcd_off)
+ ignore = false;
+
+ if (!check_actor_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON))
+ 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 KEY_PRESSED:
+ if (check_actor_caps(SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY, SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON)) {
+ skip_lcd_off = switch_on_lcd(DEVICED_EVENT_INPUT_POWERKEY);
+ } 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_seconds(
+ 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 KEY_BEING_PRESSED:
+ if (timediff_usec(pressed_time, pinput->time) >
+ (longpress_interval * USEC_PER_SEC))
+ longkey_pressed();
+ break;
+ }
+ return ignore;
+}
+
+static int process_screenlock_key(struct input_event *pinput)
+{
+ if (pinput->value != 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_SET_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_SET_RELEASE_LOCK_ALL, SYSCOMMON_DEVICED_DISPLAY_STATE_DIM);
+ set_lcdoff_reason(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
+
+ /* LCD off forcly */
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_SET_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)
+{
+ _E("pinput->value : %d", pinput->value);
+ if (pinput->value == KEY_PRESSED) {
+ /* Sound & Vibrate only in unlock state */
+ if (is_lockscreen_enabled() == VCONFKEY_IDLE_UNLOCK)
+ sound_vibrate_hardkey();
+ } else if (pinput->value == KEY_RELEASED) {
+ /* if lockscreen is idle lock */
+ if (is_lockscreen_enabled() == VCONFKEY_IDLE_LOCK) {
+ _D("Lock state, key backlight is off when phone is unlocked!");
+ return;
+ }
+ }
+}
+
+static void update_vital_state(struct input_event *pinput)
+{
+ int type;
+ int vital_mode;
+ int ret;
+
+ /* Change vital state to SYSCOMMON_DEVICED_VITAL_EXIT only if vital mode is active */
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
+ DEVICED_POWER_ATTR_INT_GET_VITAL_MODE, &vital_mode);
+ if (ret < 0 || vital_mode != 0)
+ return;
+
+ /* Touch or Menu Key Release Event */
+ if (pinput->type == EV_ABS || (pinput->type == EV_KEY &&
+ pinput->value == KEY_RELEASED && pinput->code == KEY_MENU)) {
+ /* Enable all services upon receiving user input, else maintain same state */
+ type = SYSCOMMON_DEVICED_VITAL_EXIT;
+ syscommon_notifier_emit_notify(DEVICED_NOTIFIER_VITAL_STATE, &type);
+ }
+}
+
+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 == KEY_PRESSED)
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
+ DEVICED_POWER_ATTR_TUPLE2_SET_HISTORY_LOG,
+ SYSCOMMON_DEVICED_POWER_LOG_TYPE_KEY_PRESS, pinput->code);
+ else if (pinput->value == KEY_RELEASED)
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_POWER),
+ DEVICED_POWER_ATTR_TUPLE2_SET_HISTORY_LOG,
+ 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 = 0;
+ int touch_wakeup = 0;
+
+ assert(pinput);
+
+ switch (pinput->type) {
+ case EV_KEY:
+ if (pinput->code == BTN_TOUCH &&
+ pinput->value == 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);
+ }
+ gdbus_signal_emit(NULL,
+ DEVICED_PATH_INPUT,
+ DEVICED_INTERFACE_INPUT,
+ "key",
+ g_variant_new("(iiii)", pinput->code, pinput->value, pinput->time.tv_sec, pinput->time.tv_usec));
+
+ 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_GET_CURRENT_STATE, (int32_t *) ¤t);
+ if (ret < 0)
+ break;
+
+ if (current == SYSCOMMON_DEVICED_DISPLAY_STATE_OFF && bezel_wakeup) {
+ switch_on_lcd(DEVICED_EVENT_INPUT_BEZEL);
+ ignore = false;
+ } else if (current != SYSCOMMON_DEVICED_DISPLAY_STATE_OFF)
+ ignore = false;
+ break;
+ case EV_ABS:
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_GET_TOUCH_EVENT_BLOCKED, &touch_event_blocked);
+ if (ret < 0)
+ break;
+
+ ret = syscommon_resman_get_resource_attr_int(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_INT_GET_CONFIG_TOUCH_WAKEUP, &touch_wakeup);
+ if (ret < 0)
+ break;
+
+ if (touch_event_blocked
+ && !touch_wakeup
+ && pinput->value == KEY_BEING_PRESSED)
+ return;
+
+ update_vital_state(pinput);
+ if (pinput->value == KEY_PRESSED) {
+ switch_on_lcd(DEVICED_EVENT_TOUCHSCREEN);
+ ignore = false;
+ }
+
+ if (current_state_in_on())
+ ignore = false;
+
+ restore_custom_brightness();
+
+ if (pinput->value == KEY_PRESSED)
+ touch_pressed = true;
+ else if (pinput->value == KEY_RELEASED)
+ touch_pressed = false;
+ break;
+ case EV_SW:
+ break;
+ }
+
+ if (ignore)
+ return;
+
+ /* lcd on or update lcd timeout */
+ syscommon_resman_set_resource_attr_uint64_2(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE2_SET_CURRENT_STATE,
+ SYSCOMMON_DEVICED_DISPLAY_STATE_ON, DEVICED_EVENT_INPUT);
+}
+
+static int delayed_init_done(void *data)
{
+ booting_check = 0;
+
+ return 0;
+}
+
+static int bezel_wakeup_cb(void *data)
+{
+ bezel_wakeup = (int)((intptr_t)data);
+
return 0;
}
static syscommon_plugin_backend_deviced_input_funcs g_input_funcs = {
- .input_event_cb = deviced_input_event_cb,
+ .input_event_cb = check_key_filter,
};
+static int deviced_input_init(void **data)
+{
+ /*
+ * Default capability
+ * powerkey := LCDON | LCDOFF | POWEROFF
+ * homekey := LCDON
+ */
+ syscommon_resman_set_resource_attr_uint64_3(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE3_SET_ACTOR_CAPABILITY,
+ SYSCOMMON_DEVICED_DISPLAY_ACTOR_POWER_KEY,
+ (SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON | SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDOFF | SYSCOMMON_DEVICED_DISPLAY_CAPA_POWEROFF),
+ 1);
+ syscommon_resman_set_resource_attr_uint64_3(SYSCOMMON_RESOURCE_ID(DEVICED_RESOURCE_TYPE_DISPLAY),
+ DEVICED_DISPLAY_ATTR_TUPLE3_SET_ACTOR_CAPABILITY,
+ SYSCOMMON_DEVICED_DISPLAY_ACTOR_MENU_KEY,
+ SYSCOMMON_DEVICED_DISPLAY_CAPA_LCDON,
+ 1);
+
+ syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_DELAYED_INIT, delayed_init_done);
+ syscommon_notifier_subscribe_notify(DEVICED_NOTIFIER_BEZEL_WAKEUP, bezel_wakeup_cb);
+
+ *data = (void *)&g_input_funcs;
+
+ 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",