Change prefix of list definition
[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/dbus-system.h>
25 #include <libsyscommon/list.h>
26
27 #include "callback.h"
28 #include "battery.h"
29 #include "display.h"
30 #include "common.h"
31
32 #define SIGNAL_FLASH_STATE  "ChangeFlashState"
33
34 struct device_cb_info {
35         device_changed_cb cb;
36         void *data;
37 };
38
39 static GList *device_cb_list[DEVICE_CALLBACK_MAX];
40 static int flash_sigid;
41
42 //LCOV_EXCL_START Not called Callback
43 static void battery_capacity_cb(keynode_t *key, void *data)
44 {
45         static device_callback_e type = DEVICE_CALLBACK_BATTERY_CAPACITY;
46         struct device_cb_info *cb_info;
47         GList *elem, *elem_next;
48         int val;
49
50         val = vconf_keynode_get_int(key);
51
52         /* invoke the each callback with value */
53         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
54                 cb_info->cb(type, (void*)val, cb_info->data);
55 }
56 //LCOV_EXCL_STOP
57
58 //LCOV_EXCL_START Not called Callback
59 static void battery_charging_cb(keynode_t *key, void *data)
60 {
61         static device_callback_e type = DEVICE_CALLBACK_BATTERY_CHARGING;
62         struct device_cb_info *cb_info;
63         GList *elem, *elem_next;
64         int val;
65
66         val = vconf_keynode_get_int(key);
67
68         /* invoke the each callback with value */
69         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
70                 cb_info->cb(type, (void*)val, cb_info->data);
71 }
72 //LCOV_EXCL_STOP
73
74 //LCOV_EXCL_START Not called Callback
75 static void battery_level_cb(keynode_t *key, void *data)
76 {
77         static device_callback_e type = DEVICE_CALLBACK_BATTERY_LEVEL;
78         struct device_cb_info *cb_info;
79         GList *elem, *elem_next;
80         int val, status;
81
82         val = vconf_keynode_get_int(key);
83
84         if (val == VCONFKEY_SYSMAN_BAT_LEVEL_EMPTY)
85                 status = DEVICE_BATTERY_LEVEL_EMPTY;
86         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_CRITICAL)
87                 status = DEVICE_BATTERY_LEVEL_CRITICAL;
88         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_LOW)
89                 status = DEVICE_BATTERY_LEVEL_LOW;
90         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_HIGH)
91                 status = DEVICE_BATTERY_LEVEL_HIGH;
92         else if (val == VCONFKEY_SYSMAN_BAT_LEVEL_FULL)
93                 status = DEVICE_BATTERY_LEVEL_FULL;
94         else
95                 status = -1;
96
97         /* invoke the each callback with value */
98         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
99                 cb_info->cb(type, (void*)status, cb_info->data);
100 }
101 //LCOV_EXCL_STOP
102
103 //LCOV_EXCL_START Not called Callback
104 static void display_changed_cb(keynode_t *key, void *data)
105 {
106         static device_callback_e type = DEVICE_CALLBACK_DISPLAY_STATE;
107         struct device_cb_info *cb_info;
108         GList *elem, *elem_next;
109         display_state_e state;
110         int val;
111
112         val = vconf_keynode_get_int(key);
113
114         switch (val) {
115         case 1: state = DISPLAY_STATE_NORMAL;
116                         break;
117         case 2: state = DISPLAY_STATE_SCREEN_DIM;
118                         break;
119         case 3: state = DISPLAY_STATE_SCREEN_OFF;
120                         break;
121         default: state = -1;
122                         break;
123         }
124
125         /* invoke the each callback with value */
126         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
127                 cb_info->cb(type, (void*)state, cb_info->data);
128 }
129 //LCOV_EXCL_STOP
130
131 //LCOV_EXCL_START Not called Callback
132 static void flash_state_cb(GDBusConnection *conn,
133                 const gchar *sender,
134                 const gchar *object,
135                 const gchar *interface,
136                 const gchar *signal,
137                 GVariant *parameters,
138                 gpointer user_data)
139 {
140         static int type = DEVICE_CALLBACK_FLASH_BRIGHTNESS;
141         struct device_cb_info *cb_info;
142         GList *elem, *elem_next;
143         int val;
144
145         if (strncmp(signal, SIGNAL_FLASH_STATE,
146                                 sizeof(SIGNAL_FLASH_STATE)) != 0) {
147                 _E("wrong parameter : signal(%s)", signal);
148                 return;
149         }
150
151         /* get camera value */
152         g_variant_get(parameters, "(i)", &val);
153         _D("%s - %d", signal, val);
154
155         /* invoke the each callback with value */
156         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info)
157                 cb_info->cb(type, (void*)val, cb_info->data);
158 }
159 //LCOV_EXCL_STOP
160
161 static int register_signal(const char *bus_name,
162                 const char *object_path,
163                 const char *interface_name,
164                 const char *signal,
165                 GDBusSignalCallback callback,
166                 int *sig_id)
167 {
168         GError *err = NULL;
169         GDBusConnection *conn;
170         int id;
171
172 #if !GLIB_CHECK_VERSION(2, 35, 0)
173         g_type_init();
174 #endif
175
176         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
177         if (!conn) {
178 //LCOV_EXCL_START System Error
179                 _E("fail to get dbus connection : %s", err->message);
180                 g_clear_error(&err);
181                 return -EPERM;
182 //LCOV_EXCL_STOP
183         }
184
185         /* subscribe signal */
186         id = g_dbus_connection_signal_subscribe(conn,
187                         bus_name,
188                         interface_name,
189                         signal,         /* null to match on all signals */
190                         object_path,
191                         NULL,           /* null to match on all kinds of arguments */
192                         G_DBUS_SIGNAL_FLAGS_NONE,
193                         callback,
194                         NULL,
195                         NULL);
196         if (id == 0) {
197 //LCOV_EXCL_START System Error
198                 _E("fail to connect %s signal", signal);
199                 return -EPERM;
200 //LCOV_EXCL_STOP
201         }
202
203         if (sig_id)
204                 *sig_id = id;
205
206         return 0;
207 }
208
209 static int unregister_signal(int *sig_id)
210 {
211         GError *err = NULL;
212         GDBusConnection *conn;
213
214         if (!sig_id)
215                 return -EINVAL;
216
217         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
218         if (!conn) {
219 //LCOV_EXCL_START System Error
220                 _E("fail to get dbus connection : %s", err->message);
221                 g_clear_error(&err);
222                 return -EPERM;
223 //LCOV_EXCL_STOP
224         }
225
226         /* unsubscribe signal */
227         g_dbus_connection_signal_unsubscribe(conn, *sig_id);
228         *sig_id = 0;
229
230         return 0;
231 }
232
233 static int register_request(device_callback_e type)
234 {
235         switch (type) {
236         case DEVICE_CALLBACK_BATTERY_CAPACITY:
237                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
238                                 battery_capacity_cb, NULL);
239         case DEVICE_CALLBACK_BATTERY_LEVEL:
240                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS,
241                                 battery_level_cb, NULL);
242         case DEVICE_CALLBACK_BATTERY_CHARGING:
243                 return vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
244                                 battery_charging_cb, NULL);
245         case DEVICE_CALLBACK_DISPLAY_STATE:
246                 return vconf_notify_key_changed(VCONFKEY_PM_STATE,
247                                 display_changed_cb, NULL);
248         case DEVICE_CALLBACK_FLASH_BRIGHTNESS:
249                 /* sig_id begins with 1. */
250                 if (flash_sigid)
251                         return -EEXIST;
252                 return register_signal(DEVICED_BUS_NAME,
253                                 DEVICED_PATH_LED,
254                                 DEVICED_INTERFACE_LED,
255                                 SIGNAL_FLASH_STATE, flash_state_cb, &flash_sigid);
256         default:
257                 break;
258         }
259
260         return -EINVAL;
261 }
262
263 static int release_request(device_callback_e type)
264 {
265         switch (type) {
266         case DEVICE_CALLBACK_BATTERY_CAPACITY:
267                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CAPACITY,
268                                 battery_capacity_cb);
269         case DEVICE_CALLBACK_BATTERY_LEVEL:
270                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_LEVEL_STATUS,
271                                 battery_level_cb);
272         case DEVICE_CALLBACK_BATTERY_CHARGING:
273                 return vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW,
274                                 battery_charging_cb);
275         case DEVICE_CALLBACK_DISPLAY_STATE:
276                 return vconf_ignore_key_changed(VCONFKEY_PM_STATE,
277                                 display_changed_cb);
278         case DEVICE_CALLBACK_FLASH_BRIGHTNESS:
279                 if (!flash_sigid)
280                         return -ENOENT;
281                 return unregister_signal(&flash_sigid);
282         default:
283                 break;
284         }
285
286         return -EINVAL;
287 }
288
289 int device_add_callback(device_callback_e type, device_changed_cb cb, void *data)
290 {
291         struct device_cb_info *cb_info;
292         GList *elem, *elem_next;
293         int ret, n;
294
295         if (!is_display_supported() && type == DEVICE_CALLBACK_DISPLAY_STATE)
296                 return DEVICE_ERROR_NOT_SUPPORTED;
297
298         if (type < 0 || type >= DEVICE_CALLBACK_MAX)
299                 return DEVICE_ERROR_INVALID_PARAMETER;
300
301         if (!cb)
302                 return DEVICE_ERROR_INVALID_PARAMETER;
303
304         /* check if it is the first request */
305         n = SYS_G_LIST_LENGTH(device_cb_list[type]);
306         if (n == 0) {
307                 ret = register_request(type);
308                 if (ret < 0)
309                         return DEVICE_ERROR_OPERATION_FAILED;
310         }
311
312         /* check for the same request */
313         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info) {
314                 if (cb_info->cb == cb)
315                         return DEVICE_ERROR_ALREADY_IN_PROGRESS;
316         }
317
318         /* add device changed callback to list (local) */
319         cb_info = malloc(sizeof(struct device_cb_info));
320         if (!cb_info)
321                 return DEVICE_ERROR_OPERATION_FAILED;
322
323         cb_info->cb = cb;
324         cb_info->data = data;
325
326         SYS_G_LIST_APPEND(device_cb_list[type], cb_info);
327
328         return DEVICE_ERROR_NONE;
329 }
330
331 int device_remove_callback(device_callback_e type, device_changed_cb cb)
332 {
333         struct device_cb_info *cb_info;
334         GList *elem, *elem_next;
335         int ret, n;
336
337         if (!is_display_supported() && type == DEVICE_CALLBACK_DISPLAY_STATE)
338                 return DEVICE_ERROR_NOT_SUPPORTED;
339
340         if (type < 0 || type >= DEVICE_CALLBACK_MAX)
341                 return DEVICE_ERROR_INVALID_PARAMETER;
342
343         if (!cb)
344                 return DEVICE_ERROR_INVALID_PARAMETER;
345
346         /* search for the same element with callback */
347         SYS_G_LIST_FOREACH_SAFE(device_cb_list[type], elem, elem_next, cb_info) {
348                 if (cb_info->cb == cb)
349                         break;
350         }
351
352         if (!cb_info)
353                 return DEVICE_ERROR_INVALID_PARAMETER;
354
355         /* remove device callback from list (local) */
356         SYS_G_LIST_REMOVE(device_cb_list[type], cb_info);
357         free(cb_info);
358
359         /* check if this callback is last element */
360         n = SYS_G_LIST_LENGTH(device_cb_list[type]);
361         if (n == 0) {
362                 ret = release_request(type);
363                 if (ret < 0)
364                         return DEVICE_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE System Error
365         }
366
367         return DEVICE_ERROR_NONE;
368 }