default_backend: install animation data files
[platform/core/uifw/libpui.git] / backends / default_backend.c
1 //#include <PUI.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <PUI_backend.h>
5
6 #include <json-c/json.h>
7 #include <dirent.h>
8 #include <errno.h>
9 #include <Eina.h>
10 #include <config.h>
11
12 #define ANI_COLLECTION_DIR "/usr/share/pui/"
13 #define MAX_STR 1024
14
15 #define ERROR_CHECK(exp, action, fmt, ...) \
16         do { \
17                 if (!(exp)) \
18                 { \
19                         printf(fmt, ##__VA_ARGS__);     \
20                         action; \
21                 } \
22         } while (0)
23
24 pui_backend_ani_func *ani_func = NULL;
25 Eina_Hash *_animations_hash = NULL;
26
27 typedef enum
28 {
29         None,
30         Linear,
31         EaseInSine,
32         EaseOutSine,
33         EaseInQuart,
34         EaseOutQuart
35 } pui_effect_func;
36
37 typedef struct _default_ani_info default_ani_info;
38 typedef struct _default_frame_info_t default_frame_info_t;
39 typedef struct _default_led_info_t default_led_info_t;
40
41 struct _default_ani_info
42 {
43         pui_id id;
44         pui_ani_status status;
45         pui_ani_control_buffer *buffer;
46         unsigned int repeat;
47
48         unsigned int key_frame_idx;
49         unsigned int num_key_frames;
50         default_frame_info_t *frames;
51         int interval;
52         pui_effect_func effect_func;
53 };
54
55 struct _default_frame_info_t
56 {
57         default_led_info_t *leds;
58         int num_led;
59 };
60
61 struct _default_led_info_t
62 {
63         unsigned int color;
64 };
65
66 pui_backend_ani_data *g_ani_data = NULL;
67
68 static pui_bool
69 _frame_cb(void *data, int serial)
70 {
71         pui_ani_t *ani = (pui_ani_t *)data;
72
73         //TODO
74         (void) ani;
75         //_get_next_frame();
76         //pui_backend_ani_get_buffer();
77         //pui_backend_ani_update();
78
79         return (pui_bool)1;
80 }
81
82 pui_int_error
83 get_ani_info_from_ani_collection(default_ani_info *info, pui_id id)
84 {
85         pui_int_error e = PUI_INT_ERROR_NONE;
86
87         //TODO
88         //ex> data->id = id;
89         //ex> data->interval = 30;
90
91         return e;
92 }
93
94 pui_error
95 _ani_start(pui_ani_t *ani, int repeat)
96 {
97         pui_int_error e = PUI_INT_ERROR_NONE;
98         pui_backend_ani_data *ani_data = NULL;
99
100         ani_data = pui_backend_ani_get_ani_data(ani);
101         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
102
103         //TODO
104         (void) info;
105
106         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
107         pui_backend_ani_add_frame_cb(ani, _frame_cb, 0.1);
108
109         return e;
110 }
111
112 pui_error
113 _ani_stop(pui_ani_t *ani)
114 {
115         pui_int_error e = PUI_INT_ERROR_NONE;
116         pui_backend_ani_data *ani_data = NULL;
117
118         ani_data = pui_backend_ani_get_ani_data(ani);
119         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
120
121         //TODO
122         (void) info;
123
124         pui_backend_ani_remove_frame_cb(ani);
125         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
126
127         return e;
128 }
129
130 static char *
131 _read_json_file(const char *path, int *data_size)
132 {
133         FILE *fp = fopen(path, "rb");
134         int size;
135         char *buffer;
136         ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
137
138         fseek(fp, 0, SEEK_END);
139         size = ftell(fp);
140         fseek(fp, 0, SEEK_SET);
141
142         buffer = (char *)calloc(sizeof(char), size + 1);
143
144         if (fread(buffer, size, 1, fp) < 1) {
145                 *data_size = 0;
146                 free(buffer);
147                 fclose(fp);
148                 return NULL;
149         }
150
151         *data_size = size;
152         fclose(fp);
153         return buffer;
154 }
155
156 static default_ani_info *
157 _read_json(const char *path)
158 {
159         char *buffer, *type;
160         json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
161         default_ani_info *ani_info = NULL;
162         int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
163         int data_size = 0, i, j;
164
165         buffer = _read_json_file(path, &data_size);
166         ERROR_CHECK(buffer && data_size > 0, return EINA_FALSE, "File %s has no data\n", path);
167         root_obj = json_tokener_parse(buffer);
168         ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
169
170         ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
171         ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
172
173         data_obj = json_object_object_get(root_obj, "type");
174         //printf("type: %s\n", json_object_get_string(data_obj));
175         type = (char *)json_object_get_string(data_obj);
176         ani_info->id = strndup(type, strlen(type));
177
178         data_obj = json_object_object_get(root_obj, "interval");
179         //printf("interval: %d\n", json_object_get_int(data_obj));
180         ani_info->interval = json_object_get_int(data_obj);
181
182         data_obj = json_object_object_get(root_obj, "frame");
183         frame_len = json_object_array_length(data_obj);
184
185         ani_info->num_key_frames = frame_len;
186         ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
187         ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
188         
189         for (i = 0; i < frame_len; i++) {
190                 frame_obj = json_object_array_get_idx(data_obj, i);
191
192                 frame_data_obj = json_object_object_get(frame_obj, "frame_id");
193                 //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
194                 frame_id = json_object_get_int(frame_data_obj);
195
196                 frame_data_obj = json_object_object_get(frame_obj, "led");
197                 led_len = json_object_array_length(frame_data_obj);
198                 
199                 ani_info->frames[frame_id - 1].num_led = led_len;
200                 ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
201                 ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
202                 
203                 for (j = 0; j < led_len; j++) {
204                         led_obj = json_object_array_get_idx(frame_data_obj, j);
205
206                         led_data_obj = json_object_object_get(led_obj, "id");
207                         //printf("\t\tid: %2d  ", json_object_get_int(led_data_obj));
208                         led_id = json_object_get_int(led_data_obj);
209
210                         led_data_obj = json_object_object_get(led_obj, "color");
211                         //printf("color: %s\n", json_object_get_string(led_data_obj));
212                         ani_info->frames[frame_id - 1].leds[led_id - 1].color =
213                                 strtol(json_object_get_string(led_data_obj), NULL, 16);
214                 }
215         }
216
217         free(buffer);
218         return ani_info;
219
220 error:
221         free(buffer);
222         if (ani_info) {
223                 if (ani_info->frames) {
224                         for (i = 0; i < ani_info->num_key_frames; i++) {
225                                 if (ani_info->frames[i].leds)
226                                         free(ani_info->frames[i].leds);
227                         }
228                         free(ani_info->frames);
229                 }
230                 free(ani_info->id);
231                 free(ani_info);
232         }
233         return NULL;
234 }
235
236 static int
237 _scandir_filter(const struct dirent *dirent)
238 {
239         if (!strncmp(dirent->d_name, ".", sizeof(".")) ||
240                 !strncmp(dirent->d_name, "..", sizeof("..")))
241                 return 0;
242         if (!strstr(dirent->d_name, ".json"))
243                 return 0;
244
245         return 1;
246 }
247
248
249 pui_int_error
250 _create_ani_collection(void)
251 {
252         pui_int_error e = PUI_INT_ERROR_NONE;
253         default_ani_info *ani_info;
254         struct dirent **files;
255         int count, i;
256         char file_path[MAX_STR] = {0, };
257
258         // load and store all of animation data
259
260         if ((count = scandir(ANI_COLLECTION_DIR, &files, _scandir_filter, alphasort)) == -1) {
261                 printf("Failed to get %s directory (%s)\n", ANI_COLLECTION_DIR, strerror(errno));
262                 e = PUI_INT_ERROR_INVALID_RESOURCES;
263                 return e;
264         }
265
266         for (i = 0; i < count; i++) {
267                 snprintf(file_path, sizeof(file_path), "%s%s", ANI_COLLECTION_DIR, files[i]->d_name);
268
269                 ani_info = _read_json(file_path);
270                 if (ani_info) {
271                         eina_hash_add(_animations_hash, ani_info->id, ani_info);
272                         printf("Success to load %s animation\n", files[i]->d_name);
273                 }
274                 memset(file_path, 0, sizeof(file_path));
275         }
276
277         for (i = 0; i < count; i++) {
278                 free(files[i]);
279         }
280         free(files);
281
282         //TODO
283
284         return e;
285 }
286
287 pui_int_error
288 _is_ani_supported(pui_id id)
289 {
290         pui_int_error e = PUI_INT_ERROR_NONE;
291         default_ani_info *ani_info;
292
293         //TODO
294         /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
295         if (!id) {
296                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
297                 return e;
298         }
299         ani_info = eina_hash_find(_animations_hash, id);
300         if (!ani_info) e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
301
302         return e;
303 }
304
305 static void
306 _ani_info_cleanup(default_ani_info *ani_info)
307 {
308         int i;
309
310         if (!ani_info) return;
311
312         eina_hash_del(_animations_hash, ani_info->id, ani_info);
313         if (ani_info->frames) {
314                 for (i = 0; i < ani_info->num_key_frames; i++) {
315                         if (ani_info->frames[i].leds)
316                                 free(ani_info->frames[i].leds);
317                 }
318                 free(ani_info->frames);
319         }
320         free(ani_info->id);
321         free(ani_info);
322 }
323
324 pui_backend_ani_data *
325 _ani_create(pui_id id)
326 {
327         pui_int_error e = PUI_INT_ERROR_NONE;
328
329         pui_backend_ani_data *ani_data = NULL;
330         pui_backend_ani_func *ani_func = NULL;
331
332         /* backend's animation specific info */
333         default_ani_info *ani_info = NULL;
334
335         //TODO : return NULL if the animation correspond to the given id dones't exist.
336
337         /* allocation of the structure of function pointers that will be called from pui_ani_control() */
338         ani_func = pui_backend_ani_alloc_ani_func();
339
340         if (!ani_func)
341         {
342                 pui_err("Failed to allocate memory ! (pui backend ani func)\n");
343                 return NULL;
344         }
345
346         /* Assign each function pointer that corresponds to the given id if needed. */
347         ani_func->ani_start = _ani_start;
348         ani_func->ani_stop = _ani_stop;
349
350         ani_func->reserved1 = NULL;
351         ani_func->reserved2 = NULL;
352         ani_func->reserved3 = NULL;
353         ani_func->reserved4 = NULL;
354         ani_func->reserved5 = NULL;
355         ani_func->reserved6 = NULL;
356         ani_func->reserved7 = NULL;
357         ani_func->reserved8 = NULL;
358         ani_func->reserved9 = NULL;
359         ani_func->reserved10 = NULL;
360
361         /* backend's animation specific info */
362         ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
363
364         if (!ani_info)
365         {
366                 pui_err("Failed to allocate memory ! (backend's ani specific info)\n");
367                 goto err;
368         }
369
370         /* fill animation info associate with the given id from animation collection */
371         e = get_ani_info_from_ani_collection(ani_info, id);
372         
373         if (PUI_INT_ERROR_NONE != e)
374         {
375                 pui_err("Failed to get ani info from animation collection !\n");
376                 goto err;
377         }
378
379         /* allocate backend ani_data and return it to pui ani core */
380         ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
381         
382         if (!ani_data)
383         {
384                 pui_err("Failed to allocate memory for pui backend ani data !\n");
385                 goto err;
386         }
387         
388         ani_data->ani_func = ani_func;
389         ani_data->ani_info = (pui_backend_ani_info *)ani_info;
390
391         g_ani_data = ani_data;
392
393         return ani_data;
394
395 err:
396         if (ani_func)
397         {
398                 pui_backend_ani_free_ani_func(ani_func);
399                 ani_func = NULL;
400         }
401
402         if (ani_info)
403         {
404                 _ani_info_cleanup(ani_info);
405         }
406
407         return NULL;
408 }
409
410 void
411 _ani_destroy(pui_backend_ani_data *ani_data)
412 {
413         if (!ani_data)
414                 return;
415
416         pui_backend_ani_free_ani_func(ani_data->ani_func);
417
418         //TODO : free if anything needs to be done with ani_info
419         free(ani_data->ani_info);
420
421         ani_data->ani_func = NULL;
422         if (ani_data->ani_info) {
423                 _ani_info_cleanup(ani_data->ani_info);
424                 ani_data->ani_info = NULL;
425         }
426
427         g_ani_data = NULL;
428 }
429
430 static void
431 _animation_data_free_cb(void *data)
432 {
433         default_ani_info *ani_info = (default_ani_info *)data;
434
435         _ani_info_cleanup(ani_info);
436 }
437
438 static pui_backend_module_data *
439 pui_default_backend_init(void)
440 {
441         pui_backend_module_data *backend_data = NULL;
442
443         backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data));
444
445         if (!backend_data)
446         {
447                 pui_err("Failed to allocate memory for pui backend module data !\n");
448                 return NULL;
449         }
450
451         backend_data->create_ani_collection = _create_ani_collection;
452         backend_data->ani_create = _ani_create;
453         backend_data->ani_destroy = _ani_destroy;
454
455         /* Allocate backend specific data if needed. Now it will be empty. */
456         backend_data->data = NULL;
457         _animations_hash = eina_hash_string_superfast_new(_animation_data_free_cb);
458
459         return backend_data;
460 }
461
462 static void
463 pui_default_backend_deinit(pui_backend_module_data *backend_data)
464 {
465         if (!backend_data)
466                 return;
467
468         if (backend_data->data)
469         {
470                 //TODO : free variables of backend_data
471
472                 free(backend_data->data);
473         }
474
475         if (g_ani_data)
476         {
477                 if (g_ani_data->ani_func)
478                 {
479                         pui_backend_ani_free_ani_func(g_ani_data->ani_func);
480                         g_ani_data->ani_func = NULL;
481                 }
482
483                 if (g_ani_data->ani_info)
484                 {
485                         _ani_info_cleanup(g_ani_data->ani_info);
486                         g_ani_data->ani_info = NULL;
487                 }
488         }
489
490         backend_data->create_ani_collection = NULL;
491         backend_data->ani_create = NULL;
492         backend_data->ani_destroy = NULL;
493
494         free(backend_data);
495         backend_data = NULL;
496 }
497
498 pui_backend_module pui_backend_module_info = {
499         "Tizen Reference Speaker Backend",
500         "Samsung",
501         PUI_BACKEND_SET_ABI_VERSION(1, 0),
502         pui_default_backend_init,
503         pui_default_backend_deinit
504 };
505