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