callback: add callback for key input signal
[platform/core/api/device.git] / src / callback.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <vconf.h>
23 #include <gio/gio.h>
24 #include <libsyscommon/libgdbus.h>
25 #include <libsyscommon/list.h>
26 #include <system_info.h>
27
28 #include "callback.h"
29 #include "battery.h"
30 #include "display.h"
31 #include "display-internal.h"
32 #include "common.h"
33
34 #define SIGNAL_FLASH_STATE  "ChangeFlashState"
35
36 struct device_cb_info {
37         device_changed_cb cb;
38         void *data;
39         int type;
40 };
41
42 #define DEVICE_CALLBACK_KEY_INPUT_SIZE    (DEVICE_CALLBACK_KEY_INPUT_MAX - DEVICE_CALLBACK_KEY_INPUT_MIN)
43
44 static GList *device_cb_list[DEVICE_CALLBACK_MAX];
45 static GList *device_key_cb_list;
46 static int flash_sigid;
47 static int key_sigid;
48
49 //LCOV_EXCL_START Not called Callback
50 static void battery_capacity_cb(keynode_t *key, void *data)
51 {
52         static device_callback_e type = DEVICE_CALLBACK_BATTERY_CAPACITY;
53         struct device_cb_info *cb_info;
54         GList *elem, *elem_next;
55         int val;
56
57         val = vconf_keynode_get_int(key);
58
59         /* invoke the each callback with value */
60         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
61                 cb_info->cb(type, (void*)(intptr_t)val, cb_info->data);
62 }
63 //LCOV_EXCL_STOP
64
65 //LCOV_EXCL_START Not called Callback
66 static void battery_charging_cb(keynode_t *key, void *data)
67 {
68         static device_callback_e type = DEVICE_CALLBACK_BATTERY_CHARGING;
69         struct device_cb_info *cb_info;
70         GList *elem, *elem_next;
71         int val;
72
73         val = vconf_keynode_get_int(key);
74
75         /* invoke the each callback with value */
76         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
77                 cb_info->cb(type, (void*)(intptr_t)val, cb_info->data);
78 }
79 //LCOV_EXCL_STOP
80
81 //LCOV_EXCL_START Not called Callback
82 static void battery_level_cb(keynode_t *key, void *data)
83 {
84         static device_callback_e type = DEVICE_CALLBACK_BATTERY_LEVEL;
85         struct device_cb_info *cb_info;
86         GList *elem, *elem_next;
87         int val, status;
88
89         val = vconf_keynode_get_int(key);
90
91         if (val == VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY)
92                 status = DEVICE_BATTERY_LEVEL_EMPTY;
93         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL)
94                 status = DEVICE_BATTERY_LEVEL_CRITICAL;
95         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_LOW)
96                 status = DEVICE_BATTERY_LEVEL_LOW;
97         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_HIGH)
98                 status = DEVICE_BATTERY_LEVEL_HIGH;
99         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_FULL)
100                 status = DEVICE_BATTERY_LEVEL_FULL;
101         else
102                 status = -1;
103
104         /* invoke the each callback with value */
105         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
106                 cb_info->cb(type, (void*)(intptr_t)status, cb_info->data);
107 }
108 //LCOV_EXCL_STOP
109
110 //LCOV_EXCL_START Not called Callback
111 static void display_changed_cb(keynode_t *key, void *data)
112 {
113         static device_callback_e type = DEVICE_CALLBACK_DISPLAY_STATE;
114         struct device_cb_info *cb_info;
115         GList *elem, *elem_next;
116         display_state_e state;
117         int val;
118
119         val = vconf_keynode_get_int(key);
120
121         switch (val) {
122         case 1: state = DISPLAY_STATE_NORMAL;
123                         break;
124         case 2: state = DISPLAY_STATE_SCREEN_DIM;
125                         break;
126         case 3: state = DISPLAY_STATE_SCREEN_OFF;
127                         break;
128         default: state = -1;
129                         break;
130         }
131
132         /* invoke the each callback with value */
133         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
134                 cb_info->cb(type, (void*)state, cb_info->data);
135 }
136 //LCOV_EXCL_STOP
137
138 //LCOV_EXCL_START Not called Callback
139 static void flash_state_cb(GDBusConnection *conn,
140                 const gchar *sender,
141                 const gchar *object,
142                 const gchar *interface,
143                 const gchar *signal,
144                 GVariant *parameters,
145                 gpointer user_data)
146 {
147         static int type = DEVICE_CALLBACK_FLASH_BRIGHTNESS;
148         struct device_cb_info *cb_info;
149         GList *elem, *elem_next;
150         int val;
151
152         if (strncmp(signal, SIGNAL_FLASH_STATE,
153                                 sizeof(SIGNAL_FLASH_STATE)) != 0) {
154                 _E("wrong parameter : signal(%s)", signal);
155                 return;
156         }
157
158         /* get camera value */
159         g_variant_get(parameters, "(i)", &val);
160         _D("%s - %d", signal, val);
161
162         /* invoke the each callback with value */
163         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
164                 cb_info->cb(type, (void*)(intptr_t)val, cb_info->data);
165 }
166 //LCOV_EXCL_STOP
167
168 //LCOV_EXCL_START Target specific callback
169 static void key_input_cb(GDBusConnection *conn,
170                 const gchar *sender,
171                 const gchar *object,
172                 const gchar *interface,
173                 const gchar *signal,
174                 GVariant *parameters,
175                 gpointer user_data)
176 {
177         struct device_cb_info *cb_info;
178         GList *elem, *elem_next;
179         int type = 0;
180
181         g_variant_get(parameters, "(i)", &type);
182         if (type < DEVICE_CALLBACK_KEY_INPUT_MIN || type >= DEVICE_CALLBACK_KEY_INPUT_MAX)
183                 return;
184
185         SYS_G_LIST_FOREACH_SAFE(device_key_cb_list, elem, elem_next, cb_info) {
186                 if (cb_info->type == type)
187                         cb_info->cb(type, NULL, cb_info->data);
188         }
189 }
190 //LCOV_EXCL_STOP
191
192 static int register_signal(const char *bus_name,
193                 const char *object_path,
194                 const char *interface_name,
195                 const char *signal,
196                 GDBusSignalCallback callback,
197                 int *sig_id)
198 {
199         GError *err = NULL;
200         GDBusConnection *conn;
201         int id;
202
203 #if !GLIB_CHECK_VERSION(2, 35, 0)
204         g_type_init();
205 #endif
206
207         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
208         if (!conn) {
209 //LCOV_EXCL_START System Error
210                 _E("fail to get dbus connection : %s", err->message);
211                 g_clear_error(&err);
212                 return -EPERM;
213 //LCOV_EXCL_STOP
214         }
215
216         /* subscribe signal */
217         id = g_dbus_connection_signal_subscribe(conn,
218                         bus_name,
219                         interface_name,
220                         signal,         /* null to match on all signals */
221                         object_path,
222                         NULL,           /* null to match on all kinds of arguments */
223                         G_DBUS_SIGNAL_FLAGS_NONE,
224                         callback,
225                         NULL,
226                         NULL);
227         if (id == 0) {
228 //LCOV_EXCL_START System Error
229                 _E("fail to connect %s signal", signal);
230                 return -EPERM;
231 //LCOV_EXCL_STOP
232         }
233
234         if (sig_id)
235                 *sig_id = id;
236
237         return 0;
238 }
239
240 static int unregister_signal(int *sig_id)
241 {
242         GError *err = NULL;
243         GDBusConnection *conn;
244
245         if (!sig_id)
246                 return -EINVAL;
247
248         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
249         if (!conn) {
250 //LCOV_EXCL_START System Error
251                 _E("fail to get dbus connection : %s", err->message);
252                 g_clear_error(&err);
253                 return -EPERM;
254 //LCOV_EXCL_STOP
255         }
256
257         /* unsubscribe signal */
258         g_dbus_connection_signal_unsubscribe(conn, *sig_id);
259         *sig_id = 0;
260
261         return 0;
262 }
263
264 static int register_request(int type)
265 {
266         switch (type) {
267         case DEVICE_CALLBACK_BATTERY_CAPACITY:
268                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
269                                 battery_capacity_cb, NULL);
270         case DEVICE_CALLBACK_BATTERY_LEVEL:
271                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS,
272                                 battery_level_cb, NULL);
273         case DEVICE_CALLBACK_BATTERY_CHARGING:
274                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
275                                 battery_charging_cb, NULL);
276         case DEVICE_CALLBACK_DISPLAY_STATE:
277                 return vconf_notify_key_changed(VCONFKEY_PM_STATE,
278                                 display_changed_cb, NULL);
279         case DEVICE_CALLBACK_FLASH_BRIGHTNESS:
280                 /* sig_id begins with 1. */
281                 if (flash_sigid)
282                         return -EEXIST;
283                 return register_signal(DEVICED_BUS_NAME,
284                                 DEVICED_PATH_LED,
285                                 DEVICED_INTERFACE_LED,
286                                 SIGNAL_FLASH_STATE, flash_state_cb, &flash_sigid);
287         default:
288                 if (type >= DEVICE_CALLBACK_KEY_INPUT_MIN && type < DEVICE_CALLBACK_KEY_INPUT_MAX) {
289                         if (key_sigid)
290                                 return -EEXIST;
291                         return register_signal(DEVICED_BUS_NAME,
292                                 DEVICED_PATH_INPUT,
293                                 DEVICED_INTERFACE_INPUT,
294                                 "Key", key_input_cb, &key_sigid);
295                 }
296                 break;
297         }
298
299         return -EINVAL;
300 }
301
302 static int release_request(int type)
303 {
304         switch (type) {
305         case DEVICE_CALLBACK_BATTERY_CAPACITY:
306                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
307                                 battery_capacity_cb);
308         case DEVICE_CALLBACK_BATTERY_LEVEL:
309                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS,
310                                 battery_level_cb);
311         case DEVICE_CALLBACK_BATTERY_CHARGING:
312                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
313                                 battery_charging_cb);
314         case DEVICE_CALLBACK_DISPLAY_STATE:
315                 return vconf_ignore_key_changed(VCONFKEY_PM_STATE,
316                                 display_changed_cb);
317         case DEVICE_CALLBACK_FLASH_BRIGHTNESS:
318                 if (!flash_sigid)
319                         return -ENOENT;
320                 return unregister_signal(&flash_sigid);
321         default:
322                 if (type >= DEVICE_CALLBACK_KEY_INPUT_MIN && type < DEVICE_CALLBACK_KEY_INPUT_MAX) {
323                         if (!key_sigid)
324                                 return -ENOENT;
325                         return unregister_signal(&key_sigid);
326                 }
327                 break;
328         }
329
330         return -EINVAL;
331 }
332
333 static int device_callback_check_feature_supported(int type)
334 {
335         static bool f_display = false;
336         static bool f_battery = false;
337         static bool f_flash = false;
338
339         int retval;
340         bool supported;
341
342         switch (type) {
343         case DEVICE_CALLBACK_BATTERY_CAPACITY:
344         case DEVICE_CALLBACK_BATTERY_LEVEL:
345         case DEVICE_CALLBACK_BATTERY_CHARGING:
346                 if (f_battery)
347                         return 0;
348
349                 retval = system_info_get_platform_bool("http://tizen.org/feature/battery", &supported);
350                 if (retval != SYSTEM_INFO_ERROR_NONE || !supported)
351                         return -ENOTSUP;
352
353                 f_battery = true;
354                 return 0;
355         case DEVICE_CALLBACK_DISPLAY_STATE:
356                 if (f_display)
357                         return 0;
358
359                 retval = system_info_get_platform_bool("http://tizen.org/feature/display", &supported);
360                 if (retval != SYSTEM_INFO_ERROR_NONE || !supported)
361                         return -ENOTSUP;
362                 retval = system_info_get_platform_bool("http://tizen.org/feature/display.state", &supported);
363                 if (retval != SYSTEM_INFO_ERROR_NONE || !supported)
364                         return -ENOTSUP;
365
366                 f_display = true;
367                 return 0;
368         case DEVICE_CALLBACK_FLASH_BRIGHTNESS:
369                 if (f_flash)
370                         return 0;
371
372                 retval = system_info_get_platform_bool("http://tizen.org/feature/camera.back.flash", &supported);
373                 if (retval != SYSTEM_INFO_ERROR_NONE || !supported)
374                         return -ENOTSUP;
375
376                 f_flash = true;
377                 return 0;
378         default:
379                 return 0;
380         }
381 }
382
383 int device_add_callback(device_callback_e enumtype, device_changed_cb cb, void *data)
384 {
385         struct device_cb_info *cb_info;
386         GList *elem, *elem_next;
387         GList **cb_list;
388         int ret_request, n;
389         int type = (int) enumtype;
390
391         if ((type < 0 || type >= DEVICE_CALLBACK_MAX)
392                 && (type < DEVICE_CALLBACK_KEY_INPUT_MIN || type >= DEVICE_CALLBACK_KEY_INPUT_MAX))
393                 return DEVICE_ERROR_INVALID_PARAMETER;
394
395         if (!cb)
396                 return DEVICE_ERROR_INVALID_PARAMETER;
397
398         if (device_callback_check_feature_supported(type) != 0)
399                 return DEVICE_ERROR_NOT_SUPPORTED;
400
401         if (type >= 0 && type < DEVICE_CALLBACK_MAX)
402                 cb_list = &device_cb_list[type];
403         else if (type >= DEVICE_CALLBACK_KEY_INPUT_MIN && type < DEVICE_CALLBACK_KEY_INPUT_MAX)
404                 cb_list = &device_key_cb_list;
405         else
406                 return DEVICE_ERROR_INVALID_PARAMETER;
407
408         /* check if it is the first request */
409         n = SYS_G_LIST_LENGTH(*cb_list);
410         if (n == 0) {
411                 ret_request = register_request(type);
412                 if (ret_request < 0)
413                         return DEVICE_ERROR_OPERATION_FAILED;
414         }
415
416         /* check for the same request */
417         SYS_G_LIST_FOREACH_SAFE(*cb_list, elem, elem_next, cb_info) {
418                 if (cb_info->cb == cb)
419                         return DEVICE_ERROR_ALREADY_IN_PROGRESS;
420         }
421
422         /* add device changed callback to list (local) */
423         cb_info = malloc(sizeof(struct device_cb_info));
424         if (!cb_info)
425                 return DEVICE_ERROR_OPERATION_FAILED;
426
427         cb_info->cb = cb;
428         cb_info->data = data;
429         cb_info->type = type;
430
431         SYS_G_LIST_APPEND(*cb_list, cb_info);
432
433         return DEVICE_ERROR_NONE;
434 }
435
436 int device_remove_callback(device_callback_e enumtype, device_changed_cb cb)
437 {
438         struct device_cb_info *cb_info;
439         GList *elem, *elem_next;
440         GList **cb_list;
441         int ret_request, n;
442         int type = (int) enumtype;
443
444         if ((type < 0 || type >= DEVICE_CALLBACK_MAX)
445                 && (type < DEVICE_CALLBACK_KEY_INPUT_MIN || type >= DEVICE_CALLBACK_KEY_INPUT_MAX))
446                 return DEVICE_ERROR_INVALID_PARAMETER;
447
448         if (!cb)
449                 return DEVICE_ERROR_INVALID_PARAMETER;
450
451         if (device_callback_check_feature_supported(type) != 0)
452                 return DEVICE_ERROR_NOT_SUPPORTED;
453
454         if (type >= 0 && type < DEVICE_CALLBACK_MAX)
455                 cb_list = &device_cb_list[type];
456         else if (type >= DEVICE_CALLBACK_KEY_INPUT_MIN && type < DEVICE_CALLBACK_KEY_INPUT_MAX)
457                 cb_list = &device_key_cb_list;
458         else
459                 return DEVICE_ERROR_INVALID_PARAMETER;
460
461         /* search for the same element with callback */
462         SYS_G_LIST_FOREACH_SAFE(*cb_list, elem, elem_next, cb_info) {
463                 if (cb_info->cb == cb)
464                         break;
465         }
466
467         if (!cb_info)
468                 return DEVICE_ERROR_INVALID_PARAMETER;
469
470         /* remove device callback from list (local) */
471         SYS_G_LIST_REMOVE(*cb_list, cb_info);
472         free(cb_info);
473
474         /* check if this callback is last element */
475         n = SYS_G_LIST_LENGTH(*cb_list);
476         if (n == 0) {
477                 ret_request = release_request(type);
478                 if (ret_request < 0)
479                         return DEVICE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE System Error
480         }
481
482         return DEVICE_ERROR_NONE;
483 }