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