Create widget base API set
[platform/core/appfw/appcore-widget.git] / src / base / widget_base.c
1 /*
2  * Copyright (c) 2017 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 #include <stdlib.h>
18 #include <stdbool.h>
19
20 #include <bundle.h>
21 #include <bundle_internal.h>
22 #include <aul.h>
23 #include <dlog.h>
24 #include <glib.h>
25 #include <glib-object.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <widget_errno.h>
29 #include <widget_instance.h>
30 #include <aul_app_com.h>
31 #include <Ecore_Wayland.h>
32 #include <system_info.h>
33 #include <vconf.h>
34 #include <vconf-internal-keys.h>
35 #include <screen_connector_provider.h>
36 #include <appcore_multiwindow_base.h>
37
38 #include "widget_base.h"
39
40 #ifdef LOG_TAG
41 #undef LOG_TAG
42 #endif
43
44 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
45 #define APP_TYPE_WIDGET "widgetapp"
46 #define STATUS_FOREGROUND "fg"
47 #define STATUS_BACKGROUND "bg"
48
49 static int __app_event_converter[APPCORE_BASE_EVENT_MAX] = {
50         [APP_EVENT_LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY,
51         [APP_EVENT_LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY,
52         [APP_EVENT_LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE,
53         [APP_EVENT_DEVICE_ORIENTATION_CHANGED]
54                         = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
55         [APP_EVENT_REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE,
56         [APP_EVENT_SUSPENDED_STATE_CHANGED]
57                         = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
58 };
59
60 struct app_event_info {
61         app_event_type_e type;
62         void *value;
63 };
64
65 struct app_event_handler {
66         app_event_type_e type;
67         app_event_cb cb;
68         void *data;
69         void *raw;
70 };
71
72 struct widget_foreach_context {
73         widget_base_instance_cb callback;
74         void *data;
75 };
76
77 typedef struct _widget_base_context {
78         widget_base_ops ops;
79         void *data;
80         int argc;
81         char **argv;
82         GList *classes;
83 } widget_base_context;
84
85 typedef struct _widget_base_instance_data {
86         bundle *args;
87         char *content;
88         void *tag;
89         void *user_data;
90 } widget_base_instance_data;
91
92 static widget_base_context __context;
93 static char *__appid;
94 static char *__package_id;
95 static bool __fg_signal;
96 static char *__viewer_endpoint;
97
98 static bool __is_widget_feature_enabled(void)
99 {
100         static bool feature = false;
101         static bool retrieved = false;
102         int ret;
103
104         if (retrieved == true)
105                 return feature;
106
107         ret = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
108         if (ret != SYSTEM_INFO_ERROR_NONE) {
109                 LOGE("failed to get system info"); /* LCOV_EXCL_LINE */
110                 return false; /* LCOV_EXCL_LINE */
111         }
112
113         retrieved = true;
114
115         return feature;
116 }
117
118 /* LCOV_EXCL_START */
119 static void __on_poweroff(keynode_t *key, void *data)
120 {
121         int val;
122
123         val = vconf_keynode_get_int(key);
124         switch (val) {
125         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
126         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
127                 LOGI("power off changed: %d", val);
128                 widget_base_exit();
129                 break;
130         case VCONFKEY_SYSMAN_POWER_OFF_NONE:
131         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
132         default:
133                 /* DO NOTHING */
134                 break;
135         }
136 }
137 /* LCOV_EXCL_STOP */
138
139 static void __check_empty_instance(void)
140 {
141         int cnt = appcore_multiwindow_base_instance_get_cnt();
142
143         if (cnt == 0)
144                 widget_base_exit();
145 }
146
147 static void __instance_drop(appcore_multiwindow_base_instance_h instance_h)
148 {
149         widget_base_instance_data *data;
150
151         data = appcore_multiwindow_base_instance_get_extra(instance_h);
152         appcore_multiwindow_base_instance_drop(instance_h);
153         free(data->content);
154         free(data);
155         __check_empty_instance();
156 }
157
158 static gint __comp_class(gconstpointer a, gconstpointer b)
159 {
160         const widget_base_class *cls = a;
161
162         return strcmp(cls->id, b);
163 }
164
165 static widget_base_class __get_class(const char *class_id)
166 {
167         widget_base_class *cls;
168         GList *class_node;
169
170         class_node = g_list_find_custom(__context.classes, class_id,
171                         __comp_class);
172         cls = (widget_base_class *)class_node->data;
173
174         return *cls;
175 }
176
177 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
178         int status)
179 {
180         bundle *b = bundle_create();
181         int ret;
182
183         if (b == NULL) {
184                 LOGE("out of memory"); /* LCOV_EXCL_LINE */
185                 return -1; /* LCOV_EXCL_LINE */
186         }
187
188         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
189         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
190         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
191         bundle_add_str(b, AUL_K_PKGID, __package_id);
192
193         LOGD("send lifecycle %s(%d)", instance_id, status);
194         ret = aul_app_com_send("widget.status", b);
195         if (ret < 0)
196                 LOGE("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */
197
198         bundle_free(b);
199
200         return ret;
201 }
202
203 static int __send_update_status(const char *class_id, const char *instance_id,
204         int status, bundle *extra)
205 {
206         bundle *b;
207         int lifecycle = -1;
208         bundle_raw *raw = NULL;
209         int len;
210
211         b = bundle_create();
212         if (!b) {
213                 LOGE("out of memory"); /* LCOV_EXCL_LINE */
214                 return -1; /* LCOV_EXCL_LINE */
215         }
216
217         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
218         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
219         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
220
221         if (extra) {
222                 bundle_encode(extra, &raw, &len);
223                 bundle_add_str(b, WIDGET_K_CONTENT_INFO, (const char *)raw);
224                 aul_widget_instance_add(class_id, instance_id);
225         }
226
227         LOGD("send update %s(%d) to %s", instance_id, status, __viewer_endpoint);
228         aul_app_com_send(__viewer_endpoint, b);
229
230         switch (status) {
231         case WIDGET_INSTANCE_EVENT_CREATE:
232                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE;
233                 break;
234         case WIDGET_INSTANCE_EVENT_DESTROY:
235                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY;
236                 break;
237         case WIDGET_INSTANCE_EVENT_PAUSE:
238                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE;
239                 break;
240         case WIDGET_INSTANCE_EVENT_RESUME:
241                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME;
242                 break;
243         }
244
245         if (lifecycle > -1)
246                 __send_lifecycle_event(class_id, instance_id, lifecycle);
247
248         bundle_free(b);
249         if (raw)
250                 free(raw);
251
252         return 0;
253 }
254
255 static void __control_create(const char *class_id, const char *id, bundle *b)
256 {
257         widget_base_instance_data *data;
258         char *content = NULL;
259
260         data = (widget_base_instance_data *)
261                         calloc(1, sizeof(widget_base_instance_data));
262         if (!data) {
263                 LOGE("Out of memory");
264                 return;
265         }
266
267         data->args = b;
268
269         /* call stub create */
270         appcore_multiwindow_base_instance_run(class_id, id, data);
271         data->args = NULL;
272         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
273         if (content)
274                 data->content = strdup(content);
275
276 }
277
278 static void __control_resume(const char *class_id, const char *id, bundle *b)
279 {
280         appcore_multiwindow_base_instance_h cxt;
281
282         cxt = appcore_multiwindow_base_instance_find(id);
283         if (!cxt) {
284                 LOGE("context not found: %s", id);
285                 return;
286         }
287
288         /* call stub resume */
289         appcore_multiwindow_base_instance_resume(cxt);
290 }
291
292 static void __control_pause(const char *class_id, const char *id, bundle *b)
293 {
294         appcore_multiwindow_base_instance_h instance_h;
295
296         instance_h = appcore_multiwindow_base_instance_find(id);
297
298         if (!instance_h) {
299                 LOGE("instance not found: %s", id);
300                 return;
301         }
302
303         /* call stub pause */
304         appcore_multiwindow_base_instance_pause(instance_h);
305 }
306
307 static void __control_resize(const char *class_id, const char *id, bundle *b)
308 {
309         appcore_multiwindow_base_instance_h instance_h;
310         char *remain = NULL;
311         char *w_str = NULL;
312         char *h_str = NULL;
313         int w = 0;
314         int h = 0;
315         void *class_data;
316         widget_base_class cls;
317         const appcore_multiwindow_base_class *raw_cls;
318
319         instance_h = appcore_multiwindow_base_instance_find(id);
320         if (!instance_h) {
321                 LOGE("context not found: %s", id);
322                 return;
323         }
324
325         raw_cls = appcore_multiwindow_base_instance_get_class(instance_h);
326         if (!raw_cls)
327                 return;
328
329         cls = __get_class(class_id);
330         class_data = raw_cls->data;
331         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
332         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
333
334         if (w_str)
335                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
336
337         if (h_str)
338                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
339
340         if (cls.ops.resize)
341                 cls.ops.resize(instance_h, w, h, class_data);
342
343         LOGD("%s is resized to %dx%d", id, w, h);
344         __send_update_status(class_id, id,
345                 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL);
346 }
347
348 static void __update_cb(const char *class_id, const char *id,
349                 appcore_multiwindow_base_instance_h instance_h, void *data)
350 {
351         void *class_data;
352         const appcore_multiwindow_base_class *raw_cls;
353         bundle *content = NULL;
354         char *content_raw = NULL;
355         char *force_str = NULL;
356         int force;
357         bundle *b = data;
358         widget_base_class cls;
359
360         if (!b) {
361                 LOGE("bundle is NULL");
362                 return;
363         }
364
365         raw_cls = appcore_multiwindow_base_instance_get_class(instance_h);
366         if (!raw_cls) {
367                 LOGE("class is NULL");
368                 return;
369         }
370
371         class_data = raw_cls->data;
372         cls = __get_class(class_id);
373
374         if (!cls.ops.update) {
375                 LOGE("update callback is NULL");
376                 return;
377         }
378
379         bundle_get_str(b, WIDGET_K_FORCE, &force_str);
380
381         if (force_str && strcmp(force_str, "true") == 0)
382                 force = 1;
383         else
384                 force = 0;
385
386         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content_raw);
387
388         if (content_raw) {
389                 content = bundle_decode((const bundle_raw *)content_raw,
390                                 strlen(content_raw));
391         }
392
393         if (cls.ops.update)
394                 cls.ops.update(instance_h, content, force, class_data);
395
396         __send_update_status(class_id, id,
397                 WIDGET_INSTANCE_EVENT_UPDATE, NULL);
398         LOGD("updated:%s", id);
399
400         if (content)
401                 bundle_free(content);
402 }
403
404 static void __control_update(const char *class_id, const char *id, bundle *b)
405 {
406         appcore_multiwindow_base_instance_h instance_h;
407
408         if (!id) {
409                 appcore_multiwindow_base_instance_foreach(class_id,
410                                 __update_cb, b);
411                 return;
412         }
413
414         instance_h = appcore_multiwindow_base_instance_find(id);
415         if (!instance_h) {
416                 LOGE("context not found: %s", id);
417                 return;
418         }
419
420         __update_cb(class_id, id, instance_h, b);
421 }
422
423 static void __control_destroy(const char *class_id, const char *id, bundle *b)
424 {
425         appcore_multiwindow_base_instance_h instance_h;
426         widget_base_instance_data *data;
427
428         instance_h = appcore_multiwindow_base_instance_find(id);
429         if (!instance_h) {
430                 LOGE("could not find widget obj: %s, clear amd info", id);
431                 aul_widget_instance_del(class_id, id);
432                 return;
433         }
434
435         data = (widget_base_instance_data *)
436                         appcore_multiwindow_base_instance_get_extra(instance_h);
437         data->args = b;
438
439         /* call stub terminate */
440         appcore_multiwindow_base_instance_exit(instance_h);
441         free(data->content);
442         free(data);
443         __check_empty_instance();
444 }
445
446 static int __multiwindow_create(void *data)
447 {
448         char pkgid[256] = {0, };
449         int ret = 0;
450
451         appcore_multiwindow_base_on_create();
452         app_get_id(&__appid);
453         if (aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid)) == 0)
454                 __package_id = strdup(pkgid);
455
456         if (!__package_id || !__appid) {
457                 LOGE("__package_id is NULL");
458                 return -1;
459         }
460
461         screen_connector_provider_init();
462         vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
463                         __on_poweroff, NULL);
464
465
466         if (__context.ops.create)
467                 ret = __context.ops.create(data);
468
469         LOGD("widget base is created");
470         return ret;
471 }
472
473 static int __multiwindow_terminate(void *data)
474 {
475         if (__context.ops.terminate)
476                 __context.ops.terminate(data);
477
478         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS,
479                         __on_poweroff);
480         screen_connector_provider_fini();
481
482         if (__viewer_endpoint) {
483                 free(__viewer_endpoint);
484                 __viewer_endpoint = NULL;
485         }
486
487         if (__package_id) {
488                 free(__package_id);
489                 __package_id = NULL;
490         }
491
492         if (__appid) {
493                 free(__appid);
494                 __appid = NULL;
495         }
496
497         appcore_multiwindow_base_on_terminate();
498
499         LOGD("widget base is terminated");
500         return 0;
501 }
502
503 static int __multiwindow_control(bundle *b, void *data)
504 {
505         char *class_id = NULL;
506         char *id = NULL;
507         char *operation = NULL;
508
509         appcore_multiwindow_base_on_control(b);
510         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
511         /* for previous version compatibility, use appid for default class id */
512         if (class_id == NULL)
513                 class_id = __appid;
514
515         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
516         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
517
518         if (!operation) {
519                 LOGE("operation is NULL");
520                 return 0;
521         }
522
523         if (strcmp(operation, "create") == 0)
524                 __control_create(class_id, id, b);
525         else if (strcmp(operation, "resize") == 0)
526                 __control_resize(class_id, id, b);
527         else if (strcmp(operation, "update") == 0)
528                 __control_update(class_id, id, b);
529         else if (strcmp(operation, "destroy") == 0)
530                 __control_destroy(class_id, id, b);
531         else if (strcmp(operation, "resume") == 0)
532                 __control_resume(class_id, id, b);
533         else if (strcmp(operation, "pause") == 0)
534                 __control_pause(class_id, id, b);
535         else if (strcmp(operation, "terminate") == 0)
536                 __control_destroy(class_id, id, b);
537
538         return 0;
539 }
540
541 static void __inst_resume_cb(const char *class_id, const char *id,
542                 appcore_multiwindow_base_instance_h cxt, void *data)
543 {
544         __control_resume(class_id, id, data);
545 }
546
547 static void __get_content(bundle *b)
548 {
549         char *instance_id = NULL;
550         appcore_multiwindow_base_instance_h cxt;
551         widget_base_instance_data * we;
552
553         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
554         if (!instance_id) {
555                 LOGE("instance id is NULL");
556                 return;
557         }
558
559         cxt = appcore_multiwindow_base_instance_find(instance_id);
560         if (!cxt) {
561                 LOGE("could not find widget obj: %s", instance_id);
562                 return;
563         }
564
565         we = appcore_multiwindow_base_instance_get_extra(cxt);
566         if (!we) {
567                 LOGE("widget extra is NULL");
568                 return;
569         }
570
571         if (we->content) {
572                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, we->content);
573                 LOGD("content info of %s found", instance_id);
574         } else {
575                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, "");
576                 LOGD("empty content info added");
577         }
578 }
579
580 static int __multiwindow_receive(aul_type type, bundle *b, void *data)
581 {
582         appcore_multiwindow_base_on_receive(type, b);
583
584         switch (type) {
585         case AUL_RESUME:
586                 appcore_multiwindow_base_instance_foreach_full(
587                                 __inst_resume_cb, b);
588                 break;
589         case AUL_TERMINATE:
590                 widget_base_exit();
591                 break;
592         case AUL_WIDGET_CONTENT:
593                 __get_content(b);
594                 break;
595         default:
596                 break;
597         }
598
599         return 0;
600 }
601
602 static void __multiwindow_init(int argc, char **argv, void *data)
603 {
604         if (__context.ops.init)
605                 __context.ops.init(argc, argv, data);
606 }
607
608 static void __multiwindow_finish(void)
609 {
610         if (__context.ops.finish) {
611                 __context.ops.finish();
612                 /* Check Loader case */
613                 if (getenv("AUL_LOADER_INIT")) {
614                         unsetenv("AUL_LOADER_INIT");
615                         __context.ops.finish();
616                 }
617         }
618 }
619
620 static void __multiwindow_run(void *data)
621 {
622         if (__context.ops.run)
623                 __context.ops.run(data);
624 }
625
626 static void __multiwindow_exit(void *data)
627 {
628         if (__context.ops.exit)
629                 __context.ops.exit(data);
630 }
631
632 EXPORT_API int widget_base_exit(void)
633 {
634         appcore_multiwindow_base_exit();
635         aul_widget_notify_exit();
636
637         return 0;
638 }
639
640 static gboolean __finish_event_cb(gpointer user_data)
641 {
642         appcore_multiwindow_base_instance_h cxt = user_data;
643         bundle *b;
644         const char *id;
645         const char *class_id;
646
647         if (!cxt) {
648                 LOGE("user_data is NULL");
649                 return FALSE;
650         }
651
652         id = appcore_multiwindow_base_instance_get_id(cxt);
653         class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
654         b = bundle_create();
655
656         if (!b) {
657                 LOGE("Out-of-memory");
658                 return FALSE;
659         }
660
661         bundle_add_str(b, WIDGET_K_OPERATION, "terminate");
662         __control_destroy(class_id, id, b);
663         bundle_free(b);
664
665         return FALSE;
666 }
667
668 EXPORT_API int widget_base_terminate_context(widget_base_instance_h context)
669 {
670         if (!__is_widget_feature_enabled()) {
671                 LOGE("not supported"); /* LCOV_EXCL_LINE */
672                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
673         }
674
675         if (!context) {
676                 LOGE("context is null");
677                 return WIDGET_ERROR_INVALID_PARAMETER;
678         }
679
680         g_idle_add(__finish_event_cb, context);
681
682         return WIDGET_ERROR_NONE;
683 }
684
685 static void __inst_full_cb(const char *class_id, const char *id,
686                 appcore_multiwindow_base_instance_h cxt, void *data)
687 {
688         struct widget_foreach_context *foreach_context = data;
689
690         if (!data)
691                 return;
692
693         if (foreach_context->callback)
694                 foreach_context->callback(cxt, foreach_context->data);
695 }
696
697 EXPORT_API int widget_base_foreach_context(widget_base_instance_cb cb, void *data)
698 {
699         struct widget_foreach_context foreach_context;
700
701         if (!__is_widget_feature_enabled()) {
702                 LOGE("not supported"); /* LCOV_EXCL_LINE */
703                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
704         }
705
706         if (!cb) {
707                 LOGE("callback is NULL");
708                 return WIDGET_ERROR_INVALID_PARAMETER;
709         }
710
711         foreach_context.callback = cb;
712         foreach_context.data = data;
713         appcore_multiwindow_base_instance_foreach_full(__inst_full_cb, &foreach_context);
714
715         return WIDGET_ERROR_NONE;
716 }
717
718 static int __event_cb(void *event, void *data)
719 {
720         app_event_handler_h handler = data;
721
722         struct app_event_info app_event;
723
724         app_event.type = handler->type;
725         app_event.value = event;
726
727         if (handler->cb)
728                 handler->cb(&app_event, handler->data);
729
730         return 0;
731 }
732
733 EXPORT_API int widget_base_add_event_handler(app_event_handler_h *event_handler,
734                                         app_event_type_e event_type,
735                                         app_event_cb callback,
736                                         void *user_data)
737 {
738         int r;
739         bool feature;
740         app_event_handler_h handler;
741
742         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
743         if (r < 0)
744                 return WIDGET_BASE_ERROR_FAULT;
745
746         if (!feature)
747                 return WIDGET_BASE_ERROR_NOT_SUPPORTED;
748
749         if (event_handler == NULL || callback == NULL)
750                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
751
752         if (event_type < APP_EVENT_LOW_MEMORY
753             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
754                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
755
756         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
757                 return WIDGET_BASE_ERROR_NOT_SUPPORTED;
758
759
760         handler = calloc(1, sizeof(struct app_event_handler));
761         if (!handler)
762                 return WIDGET_BASE_ERROR_OUT_OF_MEMORY;
763
764         handler->type = event_type;
765         handler->cb = callback;
766         handler->data = user_data;
767         handler->raw = appcore_base_add_event(
768                         __app_event_converter[event_type], __event_cb, handler);
769         *event_handler = handler;
770
771         return WIDGET_BASE_ERROR_NONE;
772 }
773
774 EXPORT_API int widget_base_remove_event_handler(app_event_handler_h
775                                                 event_handler)
776 {
777         int r;
778         bool feature;
779         app_event_type_e type;
780
781         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
782         if (r < 0)
783                 return WIDGET_BASE_ERROR_FAULT;
784
785         if (!feature)
786                 return WIDGET_BASE_ERROR_NOT_SUPPORTED;
787
788         if (event_handler == NULL)
789                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
790
791         type = event_handler->type;
792         if (type < APP_EVENT_LOW_MEMORY ||
793                         type > APP_EVENT_REGION_FORMAT_CHANGED)
794                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
795
796         r = appcore_base_remove_event(event_handler->raw);
797         if (r < 0)
798                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
799
800         free(event_handler);
801
802         return WIDGET_BASE_ERROR_NONE;
803 }
804
805 EXPORT_API int widget_base_context_set_content_info(
806                 widget_base_instance_h context,
807                 bundle *content_info)
808 {
809         int ret = 0;
810         bundle_raw *raw = NULL;
811         int len;
812         const char *id;
813         const char *class_id;
814         widget_base_instance_data *data;
815         appcore_multiwindow_base_instance_h instance_h;
816
817         if (!__is_widget_feature_enabled()) {
818                 LOGE("not supported"); /* LCOV_EXCL_LINE */
819                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
820         }
821
822         if (!context || !content_info)
823                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
824
825         instance_h = (appcore_multiwindow_base_instance_h)context;
826         id = appcore_multiwindow_base_instance_get_id(instance_h);
827         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
828         data = appcore_multiwindow_base_instance_get_extra(instance_h);
829
830         if (!class_id || !id || !data)
831                 return WIDGET_BASE_ERROR_FAULT;
832
833         ret = __send_update_status(class_id, id,
834                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
835
836         if (data->content)
837                 free(data->content);
838
839         bundle_encode(content_info, &raw, &len);
840         if (raw)
841                 data->content = strdup((const char *)raw);
842         else
843                 data->content = NULL;
844
845         free(raw);
846         if (ret < 0) {
847                 /* LCOV_EXCL_START */
848                 LOGE("failed to send content info: %s of %s (%d)", id,
849                                 class_id, ret);
850                 return WIDGET_BASE_ERROR_IO_ERROR;
851                 /* LCOV_EXCL_STOP */
852         }
853
854         return WIDGET_BASE_ERROR_NONE;
855 }
856
857 EXPORT_API int widget_base_context_get_tag(widget_base_instance_h context, void **tag)
858 {
859         appcore_multiwindow_base_instance_h instance_h;
860         widget_base_instance_data *data;
861
862         if (!__is_widget_feature_enabled()) {
863                 LOGE("not supported"); /* LCOV_EXCL_LINE */
864                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
865         }
866
867         if (!context || !tag) {
868                 LOGE("Invalid parameter");
869                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
870         }
871
872         instance_h = (appcore_multiwindow_base_instance_h)context;
873         data = (widget_base_instance_data *)
874                         appcore_multiwindow_base_instance_get_extra(instance_h);
875
876         if (!data) {
877                 LOGE("Invalid parameter");
878                 return WIDGET_ERROR_INVALID_PARAMETER;
879         }
880
881         *tag = data->tag;
882
883         return WIDGET_BASE_ERROR_NONE;
884 }
885
886 EXPORT_API int widget_base_context_set_tag(widget_base_instance_h context, void *tag)
887 {
888         appcore_multiwindow_base_instance_h instance_h;
889         widget_base_instance_data *data;
890
891         if (!__is_widget_feature_enabled()) {
892                 LOGE("not supported"); /* LCOV_EXCL_LINE */
893                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
894         }
895
896         if (!context) {
897                 LOGE("Invalid parameter");
898                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
899         }
900
901         instance_h = (appcore_multiwindow_base_instance_h)context;
902         data = (widget_base_instance_data *)
903                         appcore_multiwindow_base_instance_get_extra(instance_h);
904         data->tag = tag;
905
906         return WIDGET_BASE_ERROR_NONE;
907 }
908
909 EXPORT_API void *widget_base_context_get_user_data(
910                 widget_base_instance_h context)
911 {
912         appcore_multiwindow_base_instance_h instance_h;
913         widget_base_instance_data *data;
914
915         if (!__is_widget_feature_enabled()) {
916                 LOGE("not supported"); /* LCOV_EXCL_LINE */
917                 return NULL; /* LCOV_EXCL_LINE */
918         }
919
920         if (!context) {
921                 LOGE("Invalid parameter");
922                 return NULL;
923         }
924
925         instance_h = (appcore_multiwindow_base_instance_h)context;
926         data = (widget_base_instance_data *)
927                         appcore_multiwindow_base_instance_get_extra(instance_h);
928
929         return data->user_data;
930 }
931
932
933 EXPORT_API int widget_base_context_set_user_data(
934                 widget_base_instance_h context, void *user_data)
935 {
936         appcore_multiwindow_base_instance_h instance_h;
937         widget_base_instance_data *data;
938
939         if (!__is_widget_feature_enabled()) {
940                 LOGE("not supported"); /* LCOV_EXCL_LINE */
941                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
942         }
943
944         if (!context) {
945                 LOGE("Invalid parameter");
946                 return WIDGET_BASE_ERROR_INVALID_PARAMETER;
947         }
948
949         instance_h = (appcore_multiwindow_base_instance_h)context;
950         data = (widget_base_instance_data *)
951                         appcore_multiwindow_base_instance_get_extra(instance_h);
952         data->user_data = user_data;
953
954         return WIDGET_BASE_ERROR_NONE;
955 }
956
957 EXPORT_API int widget_base_context_get_id(widget_base_instance_h context, char **id)
958 {
959         appcore_multiwindow_base_instance_h instance_h;
960
961         if (!__is_widget_feature_enabled()) {
962                 LOGE("not supported"); /* LCOV_EXCL_LINE */
963                 return WIDGET_BASE_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
964         }
965
966         instance_h = (appcore_multiwindow_base_instance_h)context;
967         *id = (char *)appcore_multiwindow_base_instance_get_id(instance_h);
968
969         return WIDGET_BASE_ERROR_NONE;
970 }
971
972 EXPORT_API const char *widget_base_get_viewer_endpoint()
973 {
974         return __viewer_endpoint;
975 }
976
977 EXPORT_API int widget_base_init(widget_base_ops ops, int argc, char **argv,
978                 void *data)
979 {
980         bundle *kb;
981         char *viewer_endpoint = NULL;
982         appcore_multiwindow_base_ops raw_ops
983                         = appcore_multiwindow_base_get_default_ops();
984
985         __context.ops = ops;
986         __context.argc = argc;
987         __context.argv = argv;
988         __context.data = data;
989
990         /* override methods */
991         raw_ops.base.create = __multiwindow_create;
992         raw_ops.base.control = __multiwindow_control;
993         raw_ops.base.terminate = __multiwindow_terminate;
994         raw_ops.base.receive = __multiwindow_receive;
995         raw_ops.base.init = __multiwindow_init;
996         raw_ops.base.finish = __multiwindow_finish;
997         raw_ops.base.run = __multiwindow_run;
998         raw_ops.base.exit = __multiwindow_exit;
999
1000         if (!__is_widget_feature_enabled()) {
1001                 LOGE("not supported"); /* LCOV_EXCL_LINE */
1002                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1003         }
1004
1005         kb = bundle_import_from_argv(argc, argv);
1006         if (kb) {
1007                 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
1008                 if (viewer_endpoint) {
1009                         LOGD("viewer endpoint :%s", viewer_endpoint);
1010                         __viewer_endpoint = strdup(viewer_endpoint);
1011                 } else {
1012                         LOGE("endpoint is missing");
1013                 }
1014
1015                 bundle_free(kb);
1016         } else {
1017                 LOGE("failed to get launch argv"); /* LCOV_EXCL_LINE */
1018                 return WIDGET_ERROR_FAULT;
1019         }
1020
1021         if (appcore_multiwindow_base_init(raw_ops, argc, argv, data) < 0)
1022                return WIDGET_ERROR_FAULT;
1023
1024         return WIDGET_ERROR_NONE;
1025 }
1026
1027 static int __on_create(void *data)
1028 {
1029         return widget_base_on_create();
1030 }
1031
1032 static int __on_terminate(void *data)
1033 {
1034         return widget_base_on_terminate();
1035 }
1036
1037 static void __on_init(int argc, char **argv, void *data)
1038 {
1039         widget_base_on_init(argc, argv);
1040 }
1041
1042 static void __on_finish(void)
1043 {
1044         widget_base_on_finish();
1045 }
1046
1047 static void __on_run(void *data)
1048 {
1049         widget_base_on_run();
1050 }
1051
1052 static void __on_exit(void *data)
1053 {
1054         widget_base_on_exit();
1055 }
1056
1057 EXPORT_API int widget_base_on_create(void)
1058 {
1059         appcore_multiwindow_base_on_create();
1060
1061         return 0;
1062 }
1063
1064 EXPORT_API int widget_base_on_terminate(void)
1065 {
1066         appcore_multiwindow_base_on_terminate();
1067
1068         return 0;
1069 }
1070
1071 EXPORT_API int widget_base_on_init(int argc, char **argv)
1072 {
1073         return 0;
1074 }
1075
1076 EXPORT_API void widget_base_on_finish(void)
1077 {
1078 }
1079
1080 EXPORT_API void widget_base_on_run(void)
1081 {
1082 }
1083
1084 EXPORT_API void widget_base_on_exit(void)
1085 {
1086 }
1087
1088 EXPORT_API widget_base_ops widget_base_get_default_ops(void)
1089 {
1090         widget_base_ops ops;
1091
1092         /* override methods */
1093         ops.create = __on_create;
1094         ops.terminate = __on_terminate;
1095         ops.init = __on_init;
1096         ops.finish = __on_finish;
1097         ops.run = __on_run;
1098         ops.exit = __on_exit;
1099
1100         return ops;
1101 }
1102
1103 static void __free_class(gpointer data)
1104 {
1105         widget_base_class *cls = data;
1106
1107         free(cls->id);
1108         free(cls);
1109 }
1110
1111 EXPORT_API void widget_base_fini(void)
1112 {
1113         g_list_free_full(__context.classes, __free_class);
1114         __context.classes = NULL;
1115
1116         appcore_multiwindow_base_fini();
1117 }
1118
1119 EXPORT_API int widget_base_context_window_bind(
1120                 widget_base_instance_h instance_h, const char *id,
1121                 Ecore_Wl_Window *wl_win)
1122 {
1123         struct wl_surface *surface;
1124
1125         surface = ecore_wl_window_surface_get(wl_win);
1126         if (surface == NULL) {
1127                 LOGE("failed to get surface"); /* LCOV_EXCL_LINE */
1128                 return WIDGET_BASE_ERROR_FAULT; /* LCOV_EXCL_LINE */
1129         }
1130
1131         screen_connector_provider_remote_enable(id, surface);
1132         appcore_multiwindow_base_window_bind(instance_h, wl_win);
1133
1134         return WIDGET_BASE_ERROR_NONE;
1135 }
1136
1137 static int __class_on_create(widget_base_instance_h instance_h, bundle *content,
1138                 int w, int h, void *class_data)
1139 {
1140         return widget_base_class_on_create(instance_h, content, w, h);
1141 }
1142
1143 static int __class_on_resume(widget_base_instance_h instance_h, void *class_data)
1144 {
1145         return widget_base_class_on_resume(instance_h);
1146 }
1147
1148 static int __class_on_pause(widget_base_instance_h instance_h,
1149                 void *class_data)
1150 {
1151         return widget_base_class_on_pause(instance_h);
1152 }
1153
1154 static int __class_on_resize(widget_base_instance_h instance_h, int w, int h,
1155                 void *class_data)
1156 {
1157         return widget_base_class_on_resize(instance_h, w, h);
1158 }
1159
1160 static int __class_on_update(widget_base_instance_h instance_h, bundle *content,
1161                 int force, void *class_data)
1162 {
1163         return widget_base_class_on_update(instance_h, content, force);
1164 }
1165
1166 static int __class_on_destroy(widget_base_instance_h instance_h,
1167                 widget_base_destroy_type_e reason, bundle *content,
1168                 void *class_data)
1169 {
1170         return widget_base_class_on_destroy(instance_h, reason, content);
1171 }
1172
1173 static void __multiwindow_instance_create(
1174                 appcore_multiwindow_base_instance_h instance_h,
1175                 void *class_data)
1176 {
1177         widget_base_instance_data *instance_data;
1178         bundle *b;
1179         bundle *content_info = NULL;
1180         char *id = NULL;
1181         char *class_id = NULL;
1182         char *operation = NULL;
1183         char *content = NULL;
1184         char *w_str = NULL;
1185         char *h_str = NULL;
1186         char *remain = NULL;
1187         int w = 0;
1188         int h = 0;
1189         int ret = -1;
1190         widget_base_class cls;
1191
1192         appcore_multiwindow_base_class_on_create(instance_h);
1193         instance_data = appcore_multiwindow_base_instance_get_extra(instance_h);
1194         b = instance_data->args;
1195
1196         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
1197         /* for previous version compatibility, use appid for default class id */
1198         if (class_id == NULL)
1199                 class_id = __appid;
1200
1201         cls = __get_class(class_id);
1202         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
1203         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1204
1205         if (!operation) {
1206                 LOGE("no operation provided");
1207                 return;
1208         }
1209
1210         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
1211         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
1212         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
1213
1214         if (w_str)
1215                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
1216
1217         if (h_str)
1218                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
1219
1220         if (content)
1221                 content_info = bundle_decode((const bundle_raw *)content,
1222                                 strlen(content));
1223
1224         if (cls.ops.create)
1225                 ret = cls.ops.create(instance_h, content_info, w, h, class_data);
1226
1227         if (ret < 0) {
1228                 LOGW("Create callback returns error(%d)", ret);
1229                 ret = __send_update_status(class_id, id,
1230                                 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL);
1231                 __instance_drop(instance_h);
1232         } else {
1233                 LOGD("%s is created", id);
1234                 ret = __send_update_status(class_id, id,
1235                         WIDGET_INSTANCE_EVENT_CREATE, NULL);
1236
1237                 aul_widget_instance_add(class_id, id);
1238         }
1239
1240         if (content_info)
1241                 bundle_free(content_info);
1242 }
1243
1244 static void __multiwindow_instance_resume(
1245                 appcore_multiwindow_base_instance_h instance_h,
1246                 void *class_data)
1247 {
1248         const char *id;
1249         const char *class_id;
1250         widget_base_class cls;
1251
1252         appcore_multiwindow_base_class_on_resume(instance_h);
1253         id = appcore_multiwindow_base_instance_get_id(instance_h);
1254         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1255         cls = __get_class(class_id);
1256
1257         if (cls.ops.resume)
1258                 cls.ops.resume(instance_h, class_data);
1259
1260         LOGD("%s is resumed", id);
1261         __send_update_status(class_id, id,
1262                 WIDGET_INSTANCE_EVENT_RESUME, NULL);
1263
1264         if (!__fg_signal) {
1265                 LOGD("Send fg signal to resourceD");
1266                 aul_send_app_status_change_signal(getpid(),
1267                                 __appid,
1268                                 __package_id,
1269                                 STATUS_FOREGROUND,
1270                                 APP_TYPE_WIDGET);
1271                 __fg_signal = true;
1272         }
1273 }
1274
1275 static void __multiwindow_instance_pause(
1276                 appcore_multiwindow_base_instance_h instance_h,
1277                 void *class_data)
1278 {
1279         const char *id;
1280         const char *class_id;
1281         widget_base_class cls;
1282
1283         appcore_multiwindow_base_class_on_pause(instance_h);
1284         id = appcore_multiwindow_base_instance_get_id(instance_h);
1285         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1286         cls = __get_class(class_id);
1287
1288         if (cls.ops.pause)
1289                 cls.ops.pause(instance_h, class_data);
1290
1291         LOGD("%s is paused", id);
1292         __send_update_status(class_id, id,
1293                 WIDGET_INSTANCE_EVENT_PAUSE, NULL);
1294
1295         if (__fg_signal) {
1296                 LOGD("Send bg signal to resourceD");
1297                 aul_send_app_status_change_signal(getpid(),
1298                                 __appid,
1299                                 __package_id,
1300                                 STATUS_BACKGROUND,
1301                                 APP_TYPE_WIDGET);
1302                 __fg_signal = false;
1303         }
1304 }
1305
1306 static void __multiwindow_instance_terminate(
1307                 appcore_multiwindow_base_instance_h instance_h,
1308                 void *class_data)
1309 {
1310         widget_base_instance_data *data;
1311         bundle *b;
1312         char *operation = NULL;
1313         bundle *content_info;
1314         widget_base_destroy_type_e reason = WIDGET_BASE_DESTROY_TYPE_TEMPORARY;
1315         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
1316         const char *id;
1317         const char *class_id;
1318         widget_base_class cls;
1319
1320         id = appcore_multiwindow_base_instance_get_id(instance_h);
1321         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1322         data  = appcore_multiwindow_base_instance_get_extra(
1323                         (appcore_multiwindow_base_instance_h)instance_h);
1324         b = data->args;
1325         cls = __get_class(class_id);
1326
1327         if (b) {
1328                 bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1329                 if (operation && strcmp(operation, "destroy") == 0)
1330                         reason = WIDGET_BASE_DESTROY_TYPE_PERMANENT;
1331         }
1332
1333         if (data->content)
1334                 content_info = bundle_decode((const bundle_raw *)data->content,
1335                                 strlen(data->content));
1336         else
1337                 content_info = bundle_create();
1338
1339         if (cls.ops.destroy)
1340                 cls.ops.destroy(instance_h, reason, content_info, class_data);
1341
1342         LOGD("%s is destroyed %d", id, reason);
1343         if (reason == WIDGET_BASE_DESTROY_TYPE_PERMANENT) {
1344                 event = WIDGET_INSTANCE_EVENT_DESTROY;
1345                 aul_widget_instance_del(class_id, id);
1346         } else {
1347                 __send_update_status(class_id, id,
1348                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED,
1349                                 content_info);
1350         }
1351
1352         if (content_info)
1353                 bundle_free(content_info);
1354
1355         __send_update_status(class_id, id, event, NULL);
1356         appcore_multiwindow_base_class_on_terminate(instance_h);
1357 }
1358
1359 EXPORT_API int widget_base_class_on_create(widget_base_instance_h instance_h,
1360                 bundle *content, int w, int h)
1361 {
1362         appcore_multiwindow_base_class_on_create(instance_h);
1363
1364         return 0;
1365 }
1366
1367 EXPORT_API int widget_base_class_on_pause(widget_base_instance_h instance_h)
1368 {
1369         appcore_multiwindow_base_class_on_pause(instance_h);
1370
1371         return 0;
1372 }
1373
1374 EXPORT_API int widget_base_class_on_resume(widget_base_instance_h instance_h)
1375 {
1376         appcore_multiwindow_base_class_on_resume(instance_h);
1377
1378         return 0;
1379 }
1380
1381 EXPORT_API int widget_base_class_on_resize(widget_base_instance_h instance_h,
1382                 int w, int h)
1383 {
1384         return 0;
1385 }
1386
1387 EXPORT_API int widget_base_class_on_update(widget_base_instance_h instance_h,
1388                 bundle *content, int force)
1389 {
1390         return 0;
1391 }
1392
1393 EXPORT_API int widget_base_class_on_destroy(widget_base_instance_h instance_h,
1394                 widget_base_destroy_type_e reason, bundle *content)
1395 {
1396         appcore_multiwindow_base_class_on_terminate(instance_h);
1397
1398         return 0;
1399 }
1400
1401 EXPORT_API widget_base_class widget_base_class_get_default(void)
1402 {
1403         widget_base_class cls;
1404
1405         cls.ops.create = __class_on_create;
1406         cls.ops.resize = __class_on_resize;
1407         cls.ops.update = __class_on_update;
1408         cls.ops.destroy = __class_on_destroy;
1409         cls.ops.pause = __class_on_pause;
1410         cls.ops.resume = __class_on_resume;
1411
1412         return cls;
1413 }
1414
1415 EXPORT_API widget_base_class *widget_base_class_add(widget_base_class cls,
1416                 const char *class_id, void *class_data)
1417 {
1418         widget_base_class *c;
1419         appcore_multiwindow_base_class raw_cls;
1420
1421         if (!__is_widget_feature_enabled()) {
1422                 LOGE("not supported");
1423                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1424                 return NULL;
1425         }
1426
1427         if (!class_id) {
1428                 LOGE("class is is NULL");
1429                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1430                 return NULL;
1431         }
1432
1433         raw_cls.id = strdup(class_id);
1434         raw_cls.data = class_data;
1435         raw_cls.create = __multiwindow_instance_create;
1436         raw_cls.terminate = __multiwindow_instance_terminate;
1437         raw_cls.pause = __multiwindow_instance_pause;
1438         raw_cls.resume = __multiwindow_instance_resume;
1439         appcore_multiwindow_base_class_add(raw_cls);
1440
1441         c = malloc(sizeof(widget_base_class));
1442         if (!c)
1443                 return NULL;
1444
1445         *c = cls;
1446         c->id = strdup(class_id);
1447         __context.classes = g_list_append(__context.classes, c);
1448
1449         return c;
1450 }