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