default_backend: fix some svace issues
[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 "default_backend.h"
27 #include <limits.h>
28
29 pui_backend_ani_func *ani_func = NULL;
30 Eina_Hash *_animations_hash = NULL;
31 pui_backend_ani_data *g_ani_data = NULL;
32
33 #if 0
34 static double
35 _ani_backend_ease_function_get_intensity(pui_effect_func func, double interval)
36 {
37         double intensity = interval;
38         switch (func)
39         {
40                 case None:
41                         break;
42                 case Linear:
43                         break;
44                 case EaseInSine:
45                         intensity = 1 - cos(PI / 2 * interval);
46                         break;
47                 case EaseOutSine:
48                         intensity = sin(PI / 2 * interval);
49                         break;
50                 case EaseInQuart:
51                         intensity = interval * interval;
52                         break;
53                 case EaseOutQuart:
54                         intensity = interval * (2 - interval);
55                         break;
56                 default:
57                         break;
58         }
59
60         return intensity;
61 }
62
63 static unsigned int
64 _ani_backend_get_value(unsigned int end_frame, unsigned int start_frame, double interval)
65 {
66         double res = 0.0;
67
68         // interval: frame ratio between key frame to key frame
69         // end_frame and start_frame is key frame
70
71         res = (end_frame - start_frame) * interval + start_frame;
72
73         return res;
74 }
75 #endif
76
77 static pui_bool
78 _ani_backend_frame_cb(void *data, int serial)
79 {
80         pui_int_error e = PUI_INT_ERROR_NONE;
81         pui_ani_t *ani = (pui_ani_t *)data;
82         pui_backend_ani_data *ani_data = NULL;
83         pui_ani_control_buffer *buffer = NULL;
84         double now;
85
86         ani_data = pui_backend_ani_get_ani_data(ani);
87         default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
88
89         now = ecore_time_unix_get();
90
91         pui_info("[time:%.3f] serial=%d\n", now, serial);
92
93         /* TODO : make use of ani_info */
94         (void) ani_info;
95
96         buffer = pui_backend_ani_get_buffer(ani);
97
98         if (!buffer)
99         {
100                 pui_err("Failed to get buffer !\n");
101                 return 0;
102         }
103
104         /* test example */
105         for(int i = 0; i<12; i++)
106         {
107                 buffer->ptr[4*i] = 0;
108                 buffer->ptr[4*i + 1] = (ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_RED) >> 16;//R
109                 buffer->ptr[4*i + 2] = (ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_GREEN) >> 8;//G
110                 buffer->ptr[4*i + 3] = ani_info->frames[ani_info->frame_idx].leds[i].color & LED_MASK_BLUE;//B
111         }
112
113         e = pui_backend_ani_set_buffer(ani, buffer);
114
115         if (e != PUI_INT_ERROR_NONE)
116         {
117                 pui_err("Failed on setting buffer on animation !(e=%d)\n", e);
118                 return (pui_bool)0;
119         }
120
121         e = pui_backend_ani_update(ani);
122
123         if (e != PUI_INT_ERROR_NONE)
124         {
125                 pui_err("Failed on updating animation !(e=%d)\n", e);
126                 return (pui_bool)0;
127         }
128
129         pui_info("... update (serial=%d)\n", serial);
130
131         return (pui_bool)1;
132 }
133
134 default_ani_info *
135 get_ani_info_from_ani_collection(pui_id id)
136 {
137         default_ani_info *ani_info = NULL;
138
139         if (!_animations_hash)
140                 return NULL;
141
142         pui_info("... id: %s\n", id);
143
144         ani_info = eina_hash_find(_animations_hash, id);
145
146         if (!ani_info)
147         {
148                 pui_err("ani_info has NOT been found ! (id:%s)\n", id);
149                 return NULL;
150         }
151
152         pui_info("ani_info has been found ! (id:%s)\n", id);
153
154         return ani_info;
155 }
156
157 pui_error
158 _ani_start(pui_ani_t *ani, int repeat)
159 {
160         pui_bool ret = 0;
161         pui_int_error e = PUI_INT_ERROR_NONE;
162         pui_backend_ani_data *ani_data = NULL;
163
164         ani_data = pui_backend_ani_get_ani_data(ani);
165         default_ani_info *ani_info = (default_ani_info *)ani_data->ani_info;
166
167         pui_info("... info->id: %s, repeat : %d\n", ani_info->id, repeat);
168
169         pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STARTED);
170         ret = pui_backend_ani_add_frame_cb(ani, _ani_backend_frame_cb, (double)ani_info->interval / 1000);
171
172         if (!ret)
173         {
174                 pui_err("Failed to add frame callback !\n");
175                 e = PUI_INT_ERROR_INVALID_RESOURCES;
176         }
177
178         return e;
179 }
180
181 pui_error
182 _ani_stop(pui_ani_t *ani, pui_bool force)
183 {
184         pui_int_error e = PUI_INT_ERROR_NONE;
185         pui_backend_ani_data *ani_data = NULL;
186
187         ani_data = pui_backend_ani_get_ani_data(ani);
188         default_ani_info *info = (default_ani_info *)ani_data->ani_info;
189
190         //TODO
191         (void) info;
192
193         pui_info("... info->id: %s, force=%d\n", info->id, force);
194
195         pui_backend_ani_remove_frame_cb(ani);
196
197         if (force)
198                 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_PAUSED);
199         else
200                 pui_backend_ani_status_update(ani, PUI_ANI_STATUS_STOPPED);
201
202         return e;
203 }
204
205 static char *
206 _read_json_file(const char *path, int *data_size)
207 {
208         FILE *fp = fopen(path, "rb");
209         int size;
210         char *buffer = NULL;
211         ERROR_CHECK(fp, return NULL, "Failed to open file: %s\n", path);
212
213         fseek(fp, 0, SEEK_END);
214         size = (long int)ftell(fp);
215         fseek(fp, 0, SEEK_SET);
216         ERROR_CHECK(0 < size && size < INT_MAX, goto error, "Invalid file: %d size\n", size);
217
218         buffer = (char *)calloc(sizeof(char), size + 1);
219         ERROR_CHECK(buffer, goto error, "Failed to allocate memory for buffer\n");
220
221         if (fread(buffer, size, 1, fp) < 1) {
222                 goto error;
223         }
224
225         *data_size = size;
226         fclose(fp);
227         return buffer;
228
229 error:
230         *data_size = 0;
231         if (buffer) free(buffer);
232         fclose(fp);
233         return NULL;
234 }
235
236 static default_ani_info *
237 _read_json(const char *path)
238 {
239         char *buffer, *type;
240         json_object *root_obj, *data_obj, *frame_obj, *frame_data_obj, *led_obj, *led_data_obj;
241         default_ani_info *ani_info = NULL;
242         int frame_id = 0, frame_len = 0, led_id = 0, led_len = 0;
243         int data_size = 0, i, j;
244
245         buffer = _read_json_file(path, &data_size);
246         ERROR_CHECK(buffer && data_size > 0, goto error, "File %s has no data\n", path);
247         root_obj = json_tokener_parse(buffer);
248         ERROR_CHECK(root_obj, goto error, "Failed to tokenize json object\n");
249
250         ani_info = (default_ani_info *)calloc(1, sizeof(default_ani_info));
251         ERROR_CHECK(ani_info, goto error, "Failed to alloc for animation info\n");
252
253         data_obj = json_object_object_get(root_obj, "type");
254         //printf("type: %s\n", json_object_get_string(data_obj));
255         type = (char *)json_object_get_string(data_obj);
256         ani_info->id = strndup(type, strlen(type));
257
258         data_obj = json_object_object_get(root_obj, "interval");
259         //printf("interval: %d\n", json_object_get_int(data_obj));
260         ani_info->interval = json_object_get_int(data_obj);
261
262         data_obj = json_object_object_get(root_obj, "frame");
263         frame_len = json_object_array_length(data_obj);
264
265         ani_info->num_key_frames = frame_len;
266         ani_info->frames = (default_frame_info_t *)calloc(sizeof(default_frame_info_t), frame_len);
267         ERROR_CHECK(ani_info->frames, goto error, "Failed to alloc for default_frame_info_t\n");
268
269         for (i = 0; i < frame_len; i++) {
270                 frame_obj = json_object_array_get_idx(data_obj, i);
271
272                 frame_data_obj = json_object_object_get(frame_obj, "frame_id");
273                 //printf("\tframe id: %d\n", json_object_get_int(frame_data_obj));
274                 frame_id = json_object_get_int(frame_data_obj);
275
276                 frame_data_obj = json_object_object_get(frame_obj, "frame_duration");
277                 if (frame_data_obj)
278                         ani_info->frames[frame_id - 1].frame_duration = json_object_get_int(frame_data_obj);
279                 else
280                         ani_info->frames[frame_id - 1].frame_duration = ani_info->interval;
281
282                 frame_data_obj = json_object_object_get(frame_obj, "led");
283                 led_len = json_object_array_length(frame_data_obj);
284
285                 ani_info->frames[frame_id - 1].num_led = led_len;
286                 ani_info->frames[frame_id - 1].leds = (default_led_info_t *)calloc(sizeof(default_led_info_t), led_len);
287                 ERROR_CHECK(ani_info->frames[frame_id - 1].leds, goto error, "Failed to alloc for default_led_info_t\n");
288
289                 for (j = 0; j < led_len; j++) {
290                         led_obj = json_object_array_get_idx(frame_data_obj, j);
291
292                         led_data_obj = json_object_object_get(led_obj, "id");
293                         //printf("\t\tid: %2d  ", json_object_get_int(led_data_obj));
294                         led_id = json_object_get_int(led_data_obj);
295
296                         led_data_obj = json_object_object_get(led_obj, "color");
297                         //printf("color: %s\n", json_object_get_string(led_data_obj));
298                         ani_info->frames[frame_id - 1].leds[led_id - 1].color =
299                                 strtol(json_object_get_string(led_data_obj), NULL, 16);
300                 }
301         }
302
303         free(buffer);
304         return ani_info;
305
306 error:
307         if (buffer) free(buffer);
308         if (ani_info) {
309                 if (ani_info->frames) {
310                         for (i = 0; i < ani_info->num_key_frames; i++) {
311                                 if (ani_info->frames[i].leds)
312                                         free(ani_info->frames[i].leds);
313                         }
314                         free(ani_info->frames);
315                 }
316                 free(ani_info->id);
317                 free(ani_info);
318         }
319         return NULL;
320 }
321
322 int
323 _find_directory(const char *path, Eina_List **json_list)
324 {
325         DIR *dir;
326         struct dirent *cur;
327         int count = 0, ret_cnt = 0;
328
329         dir = opendir(path);
330         if (!dir)
331         {
332                 pui_err("Failed to open %s.\n", path);
333                 return count;
334         }
335
336         while ((cur = readdir(dir)) != NULL)
337         {
338                 char next_path[MAX_STR] = {0, };
339                 if (cur->d_type == DT_DIR)
340                 {
341                         if (!strncmp(cur->d_name, ".", sizeof(".")) ||
342                                 !strncmp(cur->d_name, "..", sizeof("..")))
343                                 continue;
344
345                         snprintf(next_path, MAX_STR, "%s/%s", path, cur->d_name);
346                         ret_cnt = _find_directory(next_path, json_list);
347                         count += ret_cnt;
348                 }
349                 else
350                 {
351                         if (strstr(cur->d_name, ".json"))
352                         {
353                                 snprintf(next_path, MAX_STR, "%s/%s", path, cur->d_name);
354                                 *json_list = eina_list_append(*json_list, eina_stringshare_add(next_path));
355                                 count++;
356                         }
357                 }
358         }
359         closedir(dir);
360
361         return count;
362 }
363
364
365 pui_int_error
366 _create_ani_collection(void)
367 {
368         pui_int_error e = PUI_INT_ERROR_NONE;
369         default_ani_info *ani_info;
370         Eina_List *json_list = NULL;
371         Eina_List *l, *l_next;
372         Eina_Stringshare *path;
373
374         // load and store all of animation data
375
376         _find_directory(ANI_COLLECTION_DIR, &json_list);
377
378         EINA_LIST_FOREACH_SAFE(json_list, l, l_next, path)
379         {
380                 ani_info = _read_json(path);
381                 if (ani_info) {
382                         eina_hash_add(_animations_hash, ani_info->id, ani_info);
383                         pui_info("Success to load %s animation (id: %s)\n", path, ani_info->id);
384                 }
385                 eina_stringshare_del(path);
386                 json_list = eina_list_remove_list(json_list, l);
387         }
388
389         //TODO
390
391         return e;
392 }
393
394 pui_bool
395 _geometry_get(int *width, int *height)
396 {
397         if (!width || !height)
398                 return 0;
399
400         if (width)
401                 *width = DEFAULT_BACKEND_GEOM_WIDTH;
402         if (height)
403                 *height = DEFAULT_BACKEND_GEOM_HEIGHT;
404
405         return 1;
406 }
407
408 pui_int_error
409 _is_ani_supported(pui_id id)
410 {
411         pui_int_error e = PUI_INT_ERROR_NONE;
412         default_ani_info *ani_info;
413
414         //TODO
415         /* if the given id is not supported, return PUI_INT_ERROR_ID_NOT_SUPPORTED. */
416         if (!id) {
417                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
418                 return e;
419         }
420         ani_info = eina_hash_find(_animations_hash, id);
421
422         if (!ani_info)
423                 e = PUI_INT_ERROR_ID_NOT_SUPPORTED;
424
425         return e;
426 }
427
428 static void
429 _ani_info_cleanup(default_ani_info *ani_info)
430 {
431         int i;
432
433         if (!ani_info)
434                 return;
435
436         if (ani_info->frames)
437         {
438                 for (i = 0; i < ani_info->num_key_frames; i++)
439                 {
440                         if (ani_info->frames[i].leds)
441                                 free(ani_info->frames[i].leds);
442                 }
443
444                 free(ani_info->frames);
445         }
446
447         free(ani_info->id);
448 }
449
450 pui_backend_ani_data *
451 _ani_create(pui_id id)
452 {
453         pui_backend_ani_data *ani_data = NULL;
454         pui_backend_ani_func *ani_func = NULL;
455
456         /* backend's animation specific info */
457         default_ani_info *ani_info = NULL;
458
459         //TODO : return NULL if the animation correspond to the given id dones't exist.
460         if (PUI_INT_ERROR_NONE != _is_ani_supported(id))
461         {
462                 pui_err("The animation(%s) doesn't supported !\n", id);
463                 return NULL;
464         }
465
466         /* allocation of the structure of function pointers that will be called from pui_ani_control() */
467         ani_func = pui_backend_ani_alloc_ani_func();
468
469         if (!ani_func)
470         {
471                 pui_err("Failed to allocate memory ! (pui backend ani func)\n");
472                 return NULL;
473         }
474
475         /* get animation info associate with the given id from animation collection */
476         ani_info = get_ani_info_from_ani_collection(id);
477
478         if (!ani_info)
479         {
480                 pui_err("Failed to get ani info from animation collection !\n");
481                 goto err;
482         }
483
484         /* allocate backend ani_data and return it to pui ani core */
485         ani_data = (pui_backend_ani_data *)calloc(1, sizeof(pui_backend_ani_data));
486
487         if (!ani_data)
488         {
489                 pui_err("Failed to allocate memory for pui backend ani data !\n");
490                 goto err;
491         }
492
493         /* Assign each function pointer that corresponds to the given id if needed. */
494         if (!strncmp(ani_info->id, "system/easy_setup", sizeof("system/easy_setup")))
495         {
496                 pui_default_backend_ani_easysetup_func_set(ani_func);
497         }
498         else if (!strncmp(ani_info->id, "system/processing", sizeof("system/processing")))
499         {
500                 pui_default_backend_ani_system_processing_func_set(ani_func);
501         }
502         else if (!strncmp(ani_info->id, "system/sw_update_done", sizeof("system/sw_update_done")))
503         {
504                 pui_default_backend_ani_swupdatedone_func_set(ani_func);
505         }
506         else if (!strncmp(ani_info->id, "system/mic_off", sizeof("system/mic_off")))
507         {
508                 pui_default_backend_ani_micoff_func_set(ani_func);
509         }
510         else if (!strncmp(ani_info->id, "voice/listening", sizeof("voice/listening")))
511         {
512                 pui_default_backend_ani_listening_func_set(ani_func);
513         }
514         else if (!strncmp(ani_info->id, "voice/streaming", sizeof("voice/streaming")))
515         {
516                 pui_default_backend_ani_streaming_func_set(ani_func);
517         }
518         else if (!strncmp(ani_info->id, "voice/processing", sizeof("voice/processing")))
519         {
520                 pui_default_backend_ani_processing_func_set(ani_func);
521         }
522         else if (!strncmp(ani_info->id, "voice/speaking", sizeof("voice/speaking")))
523         {
524                 pui_default_backend_ani_speaking_func_set(ani_func);
525         }
526         else if (!strncmp(ani_info->id, "voice/timeout", sizeof("voice/timeout")))
527         {
528                 pui_default_backend_ani_timeout_func_set(ani_func);
529         }
530         else if (!strncmp(ani_info->id, "notification/normal", sizeof("notification/normal")))
531         {
532                 pui_default_backend_ani_normal_func_set(ani_func);
533         }
534         else if (!strncmp(ani_info->id, "notification/emergency", sizeof("notification/emergency")))
535         {
536                 pui_default_backend_ani_emergency_func_set(ani_func);
537         }
538         else if (!strncmp(ani_info->id, "notification/network_error", sizeof("notification/network_error")))
539         {
540                 pui_default_backend_ani_networkerror_func_set(ani_func);
541         }
542         else if (!strncmp(ani_info->id, "notification/error", sizeof("notification/error")))
543         {
544                 pui_default_backend_ani_error_func_set(ani_func);
545         }
546         else if (!strncmp(ani_info->id, "notification/alarm", sizeof("notification/alarm")))
547         {
548                 pui_default_backend_ani_alarm_func_set(ani_func);
549         }
550         else if (!strncmp(ani_info->id, "bt/pairing", sizeof("bt/pairing")))
551         {
552                 pui_default_backend_ani_pairing_func_set(ani_func);
553         }
554         else if (!strncmp(ani_info->id, "bt/connected", sizeof("bt/connected")))
555         {
556                 pui_default_backend_ani_connected_func_set(ani_func);
557         }
558         else
559         {
560                 pui_info("%s animation has no animation handler, using default handler\n", ani_info->id);
561                 /* Assign each function pointer that corresponds to the given id if needed. */
562                 ani_func->ani_start = _ani_start;
563                 ani_func->ani_stop = _ani_stop;
564         }
565
566         ani_data->ani_func = ani_func;
567         ani_data->ani_info = (pui_backend_ani_info *)ani_info;
568
569         g_ani_data = ani_data;
570
571         return ani_data;
572
573 err:
574         if (ani_func)
575         {
576                 pui_backend_ani_free_ani_func(ani_func);
577                 ani_func = NULL;
578         }
579
580         return NULL;
581 }
582
583 void
584 _ani_destroy(pui_backend_ani_data *ani_data)
585 {
586         if (!ani_data)
587                 return;
588
589         if (ani_data->ani_func)
590         {
591                 pui_backend_ani_free_ani_func(ani_data->ani_func);
592                 ani_data->ani_func = NULL;
593         }
594
595         ani_data->ani_info = NULL;
596         g_ani_data = NULL;
597 }
598
599 static void
600 _animation_data_free_cb(void *data)
601 {
602         default_ani_info *ani_info = (default_ani_info *)data;
603
604         _ani_info_cleanup(ani_info);
605 }
606
607 static pui_backend_module_data *
608 pui_default_backend_init(void)
609 {
610         pui_backend_module_data *backend_data = NULL;
611
612         backend_data = (pui_backend_module_data *)calloc(1, sizeof(pui_backend_module_data));
613
614         if (!backend_data)
615         {
616                 pui_err("Failed to allocate memory for pui backend module data !\n");
617                 return NULL;
618         }
619
620         backend_data->create_ani_collection = _create_ani_collection;
621         backend_data->geometry_get = _geometry_get;
622         backend_data->ani_create = _ani_create;
623         backend_data->ani_destroy = _ani_destroy;
624
625         /* Allocate backend specific data if needed. Now it will be empty. */
626         backend_data->data = NULL;
627         _animations_hash = eina_hash_string_superfast_new(NULL);
628
629         return backend_data;
630 }
631
632 static void
633 pui_default_backend_deinit(pui_backend_module_data *backend_data)
634 {
635         Eina_Iterator *it;
636         default_ani_info *ani_info = NULL;
637
638         if (!backend_data)
639                 return;
640
641         if (backend_data->data)
642         {
643                 //TODO : free variables of backend_data
644
645                 free(backend_data->data);
646         }
647
648         if (g_ani_data)
649         {
650                 if (g_ani_data->ani_func)
651                 {
652                         pui_backend_ani_free_ani_func(g_ani_data->ani_func);
653                         g_ani_data->ani_func = NULL;
654                 }
655
656                 g_ani_data->ani_info = NULL;
657         }
658
659         if (_animations_hash)
660         {
661                 it = eina_hash_iterator_data_new(_animations_hash);
662
663                 EINA_ITERATOR_FOREACH(it, ani_info)
664                 {
665                         _animation_data_free_cb(ani_info);
666                         free(ani_info);
667                 }
668
669                 eina_iterator_free(it);
670
671                 eina_hash_free(_animations_hash);
672                 _animations_hash = NULL;
673         }
674
675         backend_data->create_ani_collection = NULL;
676         backend_data->geometry_get = NULL;
677         backend_data->ani_create = NULL;
678         backend_data->ani_destroy = NULL;
679
680         free(backend_data);
681         backend_data = NULL;
682 }
683
684 pui_backend_module pui_backend_module_info = {
685         "Tizen Reference Speaker Backend",
686         "Samsung",
687         PUI_BACKEND_SET_ABI_VERSION(1, 0),
688         pui_default_backend_init,
689         pui_default_backend_deinit
690 };
691