tizen 2.3 release
[framework/system/deviced.git] / src / display / key-filter-micro.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24
25 #include <vconf.h>
26 #include <Ecore.h>
27
28 #include "util.h"
29 #include "core.h"
30 #include "poll.h"
31 #include "weaks.h"
32 #include "brightness.h"
33 #include "device-node.h"
34 #include "core/common.h"
35 #include "core/devices.h"
36 #include "core/device-notifier.h"
37 #include "core/edbus-handler.h"
38 #include "core/device-handler.h"
39 #include "power/power-handler.h"
40
41 #include <linux/input.h>
42
43 #define POWEROFF_ACT                    "poweroff"
44
45 #define KEY_RELEASED            0
46 #define KEY_PRESSED             1
47
48 #define NORMAL_POWER(val)               (val == 0)
49 #define KEY_TEST_MODE_POWER(val)        (val == 2)
50
51 #define SIGNAL_LCDON_BY_POWERKEY "LCDOnByPowerkey"
52
53 static Ecore_Timer *longkey_timeout_id;
54 static bool ignore_powerkey = false;
55
56 static inline int current_state_in_on(void)
57 {
58         return (pm_cur_state == S_LCDDIM || pm_cur_state == S_NORMAL);
59 }
60
61 static int power_execute(void *data)
62 {
63         static const struct device_ops *ops = NULL;
64
65         FIND_DEVICE_INT(ops, POWER_OPS_NAME);
66
67         return ops->execute(data);
68 }
69
70 static void longkey_pressed()
71 {
72         int val, ret;
73
74         _I("Power key long pressed!");
75
76         ret = vconf_get_int(VCONFKEY_TESTMODE_POWER_OFF_POPUP, &val);
77         if (ret < 0)
78                 return;
79
80         if (NORMAL_POWER(val) || KEY_TEST_MODE_POWER(val))
81                 return;
82
83         /*
84          * Poweroff-popup has been launched by app.
85          * deviced only turns off the phone by power key
86          * when power-off popup is disabled for testmode.
87          */
88         _I("power off action!");
89
90         power_execute(POWEROFF_ACT);
91 }
92
93 static Eina_Bool longkey_pressed_cb(void *data)
94 {
95         longkey_pressed();
96         longkey_timeout_id = NULL;
97
98         return EINA_FALSE;
99 }
100
101 static inline void check_key_pair(int code, int new, int *old)
102 {
103         if (new == *old)
104                 _E("key pair is not matched! (%d, %d)", code, new);
105         else
106                 *old = new;
107 }
108
109 static inline void broadcast_lcdon_by_powerkey(void)
110 {
111         broadcast_edbus_signal(DEVICED_PATH_DISPLAY, DEVICED_INTERFACE_DISPLAY,
112             SIGNAL_LCDON_BY_POWERKEY, NULL, NULL);
113 }
114
115 static inline bool switch_on_lcd(void)
116 {
117         if (current_state_in_on())
118                 return false;
119
120         if (backlight_ops.get_lcd_power() == PM_LCD_POWER_ON)
121                 if (alpm_get_state == NULL ||
122                     alpm_get_state() == false)
123                         return false;
124
125         broadcast_lcdon_by_powerkey();
126
127         lcd_on_direct(LCD_ON_BY_POWER_KEY);
128
129         return true;
130 }
131
132 static inline void switch_off_lcd(void)
133 {
134         if (!current_state_in_on())
135                 return;
136
137         if (backlight_ops.get_lcd_power() == PM_LCD_POWER_OFF)
138                 return;
139
140         lcd_off_procedure();
141 }
142
143 static int process_power_key(struct input_event *pinput)
144 {
145         int ignore = true;
146         static int value = KEY_RELEASED;
147
148         switch (pinput->value) {
149         case KEY_RELEASED:
150                 check_key_pair(pinput->code, pinput->value, &value);
151                 ignore = false;
152
153                 if (longkey_timeout_id > 0) {
154                         ecore_timer_del(longkey_timeout_id);
155                         longkey_timeout_id = NULL;
156                 }
157                 break;
158         case KEY_PRESSED:
159                 switch_on_lcd();
160                 check_key_pair(pinput->code, pinput->value, &value);
161                 _I("power key pressed");
162
163                 /* add long key timer */
164                 longkey_timeout_id = ecore_timer_add(
165                             display_conf.longpress_interval,
166                             longkey_pressed_cb, NULL);
167                 ignore = false;
168                 break;
169         }
170         return ignore;
171 }
172
173 static int check_key(struct input_event *pinput, int fd)
174 {
175         int ignore = true;
176
177         switch (pinput->code) {
178         case KEY_POWER:
179                 ignore = process_power_key(pinput);
180                 break;
181         case KEY_PHONE: /* Flick up key */
182         case KEY_BACK: /* Flick down key */
183         case KEY_VOLUMEUP:
184         case KEY_VOLUMEDOWN:
185         case KEY_CAMERA:
186         case KEY_EXIT:
187         case KEY_CONFIG:
188         case KEY_MEDIA:
189         case KEY_MUTE:
190         case KEY_PLAYPAUSE:
191         case KEY_PLAYCD:
192         case KEY_PAUSECD:
193         case KEY_STOPCD:
194         case KEY_NEXTSONG:
195         case KEY_PREVIOUSSONG:
196         case KEY_REWIND:
197         case KEY_FASTFORWARD:
198                 /* These case do not turn on the lcd */
199                 if (current_state_in_on())
200                         ignore = false;
201                 break;
202         default:
203                 ignore = false;
204         }
205 #ifdef ENABLE_PM_LOG
206         if (pinput->value == KEY_PRESSED)
207                 pm_history_save(PM_LOG_KEY_PRESS, pinput->code);
208         else if (pinput->value == KEY_RELEASED)
209                 pm_history_save(PM_LOG_KEY_RELEASE, pinput->code);
210 #endif
211         return ignore;
212 }
213
214 static int check_key_filter(int length, char buf[], int fd)
215 {
216         struct input_event *pinput;
217         int ignore = true;
218         int idx = 0;
219         static int old_fd, code, value;
220
221         do {
222                 pinput = (struct input_event *)&buf[idx];
223                 switch (pinput->type) {
224                 case EV_KEY:
225                         if (pinput->code == code && pinput->value == value) {
226                                 _E("Same key(%d, %d) is polled [%d,%d]",
227                                     code, value, old_fd, fd);
228                         }
229                         old_fd = fd;
230                         code = pinput->code;
231                         value = pinput->value;
232
233                         ignore = check_key(pinput, fd);
234                         break;
235                 case EV_REL:
236                         ignore = false;
237                         break;
238                 case EV_ABS:
239                         if (current_state_in_on())
240                                 ignore = false;
241                         if (get_ambient_mode != NULL &&
242                             get_ambient_mode() == true) {
243                                 switch_on_lcd();
244                                 ignore = false;
245                         }
246                         if (pm_cur_state == S_LCDDIM &&
247                             backlight_ops.get_custom_status())
248                                 backlight_ops.custom_update();
249
250                         break;
251                 }
252                 idx += sizeof(struct input_event);
253                 if (ignore == true && length <= idx)
254                         return 1;
255         } while (length > idx);
256
257         return 0;
258 }
259
260 static void set_powerkey_ignore(int on)
261 {
262         _D("ignore powerkey %d", on);
263         ignore_powerkey = on;
264 }
265
266 static int powerkey_lcdoff(void)
267 {
268         /* Remove non est processes */
269         check_processes(S_LCDOFF);
270         check_processes(S_LCDDIM);
271
272         /* check holdkey block flag in lock node */
273         if (check_holdkey_block(S_LCDOFF) ||
274             check_holdkey_block(S_LCDDIM)) {
275                 return -ECANCELED;
276         }
277
278         _I("power key lcdoff");
279
280         if (display_info.update_auto_brightness)
281                 display_info.update_auto_brightness(false);
282         switch_off_lcd();
283         delete_condition(S_LCDOFF);
284         delete_condition(S_LCDDIM);
285         update_lcdoff_source(VCONFKEY_PM_LCDOFF_BY_POWERKEY);
286         recv_data.pid = getpid();
287         recv_data.cond = 0x400;
288         (*g_pm_callback)(PM_CONTROL_EVENT, &recv_data);
289
290         return 0;
291 }
292
293 static const struct display_keyfilter_ops micro_keyfilter_ops = {
294         .init                   = NULL,
295         .exit                   = NULL,
296         .check                  = check_key_filter,
297         .set_powerkey_ignore    = set_powerkey_ignore,
298         .powerkey_lcdoff        = powerkey_lcdoff,
299         .backlight_enable       = NULL,
300 };
301 const struct display_keyfilter_ops *keyfilter_ops = &micro_keyfilter_ops;
302