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