Fix base fini sequence
[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         appcore_multiwindow_base_fini();
1114         g_list_free_full(__context.classes, __free_class);
1115         __context.classes = NULL;
1116 }
1117
1118 EXPORT_API int widget_base_context_window_bind(
1119                 widget_base_instance_h instance_h, const char *id,
1120                 Ecore_Wl_Window *wl_win)
1121 {
1122         struct wl_surface *surface;
1123
1124         surface = ecore_wl_window_surface_get(wl_win);
1125         if (surface == NULL) {
1126                 LOGE("failed to get surface"); /* LCOV_EXCL_LINE */
1127                 return WIDGET_BASE_ERROR_FAULT; /* LCOV_EXCL_LINE */
1128         }
1129
1130         screen_connector_provider_remote_enable(id, surface);
1131         appcore_multiwindow_base_window_bind(instance_h, wl_win);
1132
1133         return WIDGET_BASE_ERROR_NONE;
1134 }
1135
1136 static int __class_on_create(widget_base_instance_h instance_h, bundle *content,
1137                 int w, int h, void *class_data)
1138 {
1139         return widget_base_class_on_create(instance_h, content, w, h);
1140 }
1141
1142 static int __class_on_resume(widget_base_instance_h instance_h, void *class_data)
1143 {
1144         return widget_base_class_on_resume(instance_h);
1145 }
1146
1147 static int __class_on_pause(widget_base_instance_h instance_h,
1148                 void *class_data)
1149 {
1150         return widget_base_class_on_pause(instance_h);
1151 }
1152
1153 static int __class_on_resize(widget_base_instance_h instance_h, int w, int h,
1154                 void *class_data)
1155 {
1156         return widget_base_class_on_resize(instance_h, w, h);
1157 }
1158
1159 static int __class_on_update(widget_base_instance_h instance_h, bundle *content,
1160                 int force, void *class_data)
1161 {
1162         return widget_base_class_on_update(instance_h, content, force);
1163 }
1164
1165 static int __class_on_destroy(widget_base_instance_h instance_h,
1166                 widget_base_destroy_type_e reason, bundle *content,
1167                 void *class_data)
1168 {
1169         return widget_base_class_on_destroy(instance_h, reason, content);
1170 }
1171
1172 static void __multiwindow_instance_create(
1173                 appcore_multiwindow_base_instance_h instance_h,
1174                 void *class_data)
1175 {
1176         widget_base_instance_data *instance_data;
1177         bundle *b;
1178         bundle *content_info = NULL;
1179         char *id = NULL;
1180         char *class_id = NULL;
1181         char *operation = NULL;
1182         char *content = NULL;
1183         char *w_str = NULL;
1184         char *h_str = NULL;
1185         char *remain = NULL;
1186         int w = 0;
1187         int h = 0;
1188         int ret = -1;
1189         widget_base_class cls;
1190
1191         appcore_multiwindow_base_class_on_create(instance_h);
1192         instance_data = appcore_multiwindow_base_instance_get_extra(instance_h);
1193         b = instance_data->args;
1194
1195         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
1196         /* for previous version compatibility, use appid for default class id */
1197         if (class_id == NULL)
1198                 class_id = __appid;
1199
1200         cls = __get_class(class_id);
1201         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
1202         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1203
1204         if (!operation) {
1205                 LOGE("no operation provided");
1206                 return;
1207         }
1208
1209         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
1210         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
1211         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
1212
1213         if (w_str)
1214                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
1215
1216         if (h_str)
1217                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
1218
1219         if (content)
1220                 content_info = bundle_decode((const bundle_raw *)content,
1221                                 strlen(content));
1222
1223         if (cls.ops.create)
1224                 ret = cls.ops.create(instance_h, content_info, w, h, class_data);
1225
1226         if (ret < 0) {
1227                 LOGW("Create callback returns error(%d)", ret);
1228                 ret = __send_update_status(class_id, id,
1229                                 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL);
1230                 __instance_drop(instance_h);
1231         } else {
1232                 LOGD("%s is created", id);
1233                 ret = __send_update_status(class_id, id,
1234                         WIDGET_INSTANCE_EVENT_CREATE, NULL);
1235
1236                 aul_widget_instance_add(class_id, id);
1237         }
1238
1239         if (content_info)
1240                 bundle_free(content_info);
1241 }
1242
1243 static void __multiwindow_instance_resume(
1244                 appcore_multiwindow_base_instance_h instance_h,
1245                 void *class_data)
1246 {
1247         const char *id;
1248         const char *class_id;
1249         widget_base_class cls;
1250
1251         appcore_multiwindow_base_class_on_resume(instance_h);
1252         id = appcore_multiwindow_base_instance_get_id(instance_h);
1253         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1254         cls = __get_class(class_id);
1255
1256         if (cls.ops.resume)
1257                 cls.ops.resume(instance_h, class_data);
1258
1259         LOGD("%s is resumed", id);
1260         __send_update_status(class_id, id,
1261                 WIDGET_INSTANCE_EVENT_RESUME, NULL);
1262
1263         if (!__fg_signal) {
1264                 LOGD("Send fg signal to resourceD");
1265                 aul_send_app_status_change_signal(getpid(),
1266                                 __appid,
1267                                 __package_id,
1268                                 STATUS_FOREGROUND,
1269                                 APP_TYPE_WIDGET);
1270                 __fg_signal = true;
1271         }
1272 }
1273
1274 static void __multiwindow_instance_pause(
1275                 appcore_multiwindow_base_instance_h instance_h,
1276                 void *class_data)
1277 {
1278         const char *id;
1279         const char *class_id;
1280         widget_base_class cls;
1281
1282         appcore_multiwindow_base_class_on_pause(instance_h);
1283         id = appcore_multiwindow_base_instance_get_id(instance_h);
1284         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1285         cls = __get_class(class_id);
1286
1287         if (cls.ops.pause)
1288                 cls.ops.pause(instance_h, class_data);
1289
1290         LOGD("%s is paused", id);
1291         __send_update_status(class_id, id,
1292                 WIDGET_INSTANCE_EVENT_PAUSE, NULL);
1293
1294         if (__fg_signal) {
1295                 LOGD("Send bg signal to resourceD");
1296                 aul_send_app_status_change_signal(getpid(),
1297                                 __appid,
1298                                 __package_id,
1299                                 STATUS_BACKGROUND,
1300                                 APP_TYPE_WIDGET);
1301                 __fg_signal = false;
1302         }
1303 }
1304
1305 static void __multiwindow_instance_terminate(
1306                 appcore_multiwindow_base_instance_h instance_h,
1307                 void *class_data)
1308 {
1309         widget_base_instance_data *data;
1310         bundle *b;
1311         char *operation = NULL;
1312         bundle *content_info;
1313         widget_base_destroy_type_e reason = WIDGET_BASE_DESTROY_TYPE_TEMPORARY;
1314         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
1315         const char *id;
1316         const char *class_id;
1317         widget_base_class cls;
1318
1319         id = appcore_multiwindow_base_instance_get_id(instance_h);
1320         class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
1321         data  = appcore_multiwindow_base_instance_get_extra(
1322                         (appcore_multiwindow_base_instance_h)instance_h);
1323         b = data->args;
1324         cls = __get_class(class_id);
1325
1326         if (b) {
1327                 bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1328                 if (operation && strcmp(operation, "destroy") == 0)
1329                         reason = WIDGET_BASE_DESTROY_TYPE_PERMANENT;
1330         }
1331
1332         if (data->content)
1333                 content_info = bundle_decode((const bundle_raw *)data->content,
1334                                 strlen(data->content));
1335         else
1336                 content_info = bundle_create();
1337
1338         if (cls.ops.destroy)
1339                 cls.ops.destroy(instance_h, reason, content_info, class_data);
1340
1341         LOGD("%s is destroyed %d", id, reason);
1342         if (reason == WIDGET_BASE_DESTROY_TYPE_PERMANENT) {
1343                 event = WIDGET_INSTANCE_EVENT_DESTROY;
1344                 aul_widget_instance_del(class_id, id);
1345         } else {
1346                 __send_update_status(class_id, id,
1347                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED,
1348                                 content_info);
1349         }
1350
1351         if (content_info)
1352                 bundle_free(content_info);
1353
1354         __send_update_status(class_id, id, event, NULL);
1355         appcore_multiwindow_base_class_on_terminate(instance_h);
1356 }
1357
1358 EXPORT_API int widget_base_class_on_create(widget_base_instance_h instance_h,
1359                 bundle *content, int w, int h)
1360 {
1361         appcore_multiwindow_base_class_on_create(instance_h);
1362
1363         return 0;
1364 }
1365
1366 EXPORT_API int widget_base_class_on_pause(widget_base_instance_h instance_h)
1367 {
1368         appcore_multiwindow_base_class_on_pause(instance_h);
1369
1370         return 0;
1371 }
1372
1373 EXPORT_API int widget_base_class_on_resume(widget_base_instance_h instance_h)
1374 {
1375         appcore_multiwindow_base_class_on_resume(instance_h);
1376
1377         return 0;
1378 }
1379
1380 EXPORT_API int widget_base_class_on_resize(widget_base_instance_h instance_h,
1381                 int w, int h)
1382 {
1383         return 0;
1384 }
1385
1386 EXPORT_API int widget_base_class_on_update(widget_base_instance_h instance_h,
1387                 bundle *content, int force)
1388 {
1389         return 0;
1390 }
1391
1392 EXPORT_API int widget_base_class_on_destroy(widget_base_instance_h instance_h,
1393                 widget_base_destroy_type_e reason, bundle *content)
1394 {
1395         appcore_multiwindow_base_class_on_terminate(instance_h);
1396
1397         return 0;
1398 }
1399
1400 EXPORT_API widget_base_class widget_base_class_get_default(void)
1401 {
1402         widget_base_class cls;
1403
1404         cls.ops.create = __class_on_create;
1405         cls.ops.resize = __class_on_resize;
1406         cls.ops.update = __class_on_update;
1407         cls.ops.destroy = __class_on_destroy;
1408         cls.ops.pause = __class_on_pause;
1409         cls.ops.resume = __class_on_resume;
1410
1411         return cls;
1412 }
1413
1414 EXPORT_API widget_base_class *widget_base_class_add(widget_base_class cls,
1415                 const char *class_id, void *class_data)
1416 {
1417         widget_base_class *c;
1418         appcore_multiwindow_base_class raw_cls;
1419
1420         if (!__is_widget_feature_enabled()) {
1421                 LOGE("not supported");
1422                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1423                 return NULL;
1424         }
1425
1426         if (!class_id) {
1427                 LOGE("class is is NULL");
1428                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1429                 return NULL;
1430         }
1431
1432         raw_cls.id = strdup(class_id);
1433         raw_cls.data = class_data;
1434         raw_cls.create = __multiwindow_instance_create;
1435         raw_cls.terminate = __multiwindow_instance_terminate;
1436         raw_cls.pause = __multiwindow_instance_pause;
1437         raw_cls.resume = __multiwindow_instance_resume;
1438         appcore_multiwindow_base_class_add(raw_cls);
1439
1440         c = malloc(sizeof(widget_base_class));
1441         if (!c)
1442                 return NULL;
1443
1444         *c = cls;
1445         c->id = strdup(class_id);
1446         __context.classes = g_list_append(__context.classes, c);
1447
1448         return c;
1449 }