From: Youngjae Cho Date: Wed, 23 Aug 2023 06:25:29 +0000 (+0900) Subject: input: Add input backend X-Git-Tag: accepted/tizen/unified/20230825.044255^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bd01fd8d88897b5136d9777c32a9d6bf100d41cb;p=platform%2Fcore%2Fsystem%2Fplugin%2Fdeviced-headed.git input: Add input backend It has been separated from the deviced iot-headed plugin. Change-Id: Ie21942654846882b5e4e2fa2931592651c8a08a6 Signed-off-by: Youngjae Cho --- diff --git a/src/deviced-input/CMakeLists.txt b/src/deviced-input/CMakeLists.txt index 26f038a..98580b7 100644 --- a/src/deviced-input/CMakeLists.txt +++ b/src/deviced-input/CMakeLists.txt @@ -11,7 +11,8 @@ pkg_check_modules(pkgs REQUIRED libsyscommon libsyscommon-plugin-api-deviced libinput - glib-2.0) + glib-2.0 + vconf) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_LIB_CFLAGS "${EXTRA_LIB_CFLAGS} ${flag}") ENDFOREACH(flag) diff --git a/src/deviced-input/deviced-input.c b/src/deviced-input/deviced-input.c index 1a87afb..0c39b84 100644 --- a/src/deviced-input/deviced-input.c +++ b/src/deviced-input/deviced-input.c @@ -16,38 +16,951 @@ * limitations under the License. */ -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include #include #include +#include +#include #include #include #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",