d0a8712e64de2d86eb5f575338db5c22d3769e5d
[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 EXPORT_API int widget_app_main(int argc, char **argv,
618                 widget_app_lifecycle_callback_s *callback, void *user_data)
619 {
620         bundle *kb;
621         char *viewer_endpoint = NULL;
622
623         if (!__is_widget_feature_enabled()) {
624                 _E("not supported"); /* LCOV_EXCL_LINE */
625                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
626         }
627
628         if (argc <= 0 || argv == NULL || callback == NULL)
629                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
630                                 __FUNCTION__, NULL);
631
632         if (__context.dirty) {
633                 _E("Already started");
634                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
635         }
636
637         if (callback->create == NULL)
638                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
639                                 __FUNCTION__,
640                                 "widget_app_create_cb() callback must be "
641                                 "registered");
642
643         appcore_multiwindow_base_ops ops = appcore_multiwindow_base_get_default_ops();
644
645         /* override methods */
646         ops.base.create = __widget_app_create;
647         ops.base.control = __widget_app_control;
648         ops.base.terminate = __widget_app_terminate;
649         ops.base.receive = __widget_app_receive;
650         __context.callback = *callback;
651         __context.data = user_data;
652         kb = bundle_import_from_argv(argc, argv);
653         if (kb) {
654                 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
655                 if (viewer_endpoint) {
656                         _D("viewer endpoint :%s", viewer_endpoint);
657                         _viewer_endpoint = strdup(viewer_endpoint);
658                 } else {
659                         _E("endpoint is missing");
660                 }
661
662                 bundle_free(kb);
663         } else {
664                 _E("failed to get launch argv"); /* LCOV_EXCL_LINE */
665                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
666         }
667
668         __context.dirty = true;
669         appcore_multiwindow_base_init(ops, argc, argv, NULL);
670         appcore_multiwindow_base_fini();
671         __context.dirty = false;
672
673         return WIDGET_ERROR_NONE;
674 }
675
676 EXPORT_API int widget_app_exit(void)
677 {
678         if (!__is_widget_feature_enabled()) {
679                 _E("not supported"); /* LCOV_EXCL_LINE */
680                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
681         }
682
683         appcore_multiwindow_base_exit();
684         return WIDGET_ERROR_NONE;
685 }
686
687 static gboolean __finish_event_cb(gpointer user_data)
688 {
689         appcore_multiwindow_base_instance_h cxt = user_data;
690         bundle *b;
691         const char *id;
692         const char *class_id;
693
694         if (!cxt) {
695                 _E("user_data is NULL");
696                 return FALSE;
697         }
698
699         id = appcore_multiwindow_base_instance_get_id(cxt);
700         class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
701         b = bundle_create();
702
703         if (!b) {
704                 _E("Out-of-memory");
705                 return FALSE;
706         }
707
708         bundle_add_str(b, WIDGET_K_OPERATION, "terminate");
709         __instance_destroy(class_id, id, b);
710         bundle_free(b);
711
712         return FALSE;
713 }
714
715 EXPORT_API int widget_app_terminate_context(widget_context_h context)
716 {
717         if (!__is_widget_feature_enabled()) {
718                 _E("not supported"); /* LCOV_EXCL_LINE */
719                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
720         }
721
722         if (context == NULL)
723                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
724                                 __FUNCTION__, NULL);
725
726         g_idle_add(__finish_event_cb, context);
727         return WIDGET_ERROR_NONE;
728 }
729
730 static void __inst_full_cb(const char *class_id, const char *id,
731                 appcore_multiwindow_base_instance_h cxt, void *data)
732 {
733         struct widget_foreach_context *foreach_context = data;
734
735         if (!data)
736                 return;
737
738         if (foreach_context->callback)
739                 foreach_context->callback(cxt, foreach_context->data);
740 }
741
742 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
743 {
744         struct widget_foreach_context foreach_context;
745
746         if (!__is_widget_feature_enabled()) {
747                 _E("not supported"); /* LCOV_EXCL_LINE */
748                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
749         }
750
751         if (!cb) {
752                 _E("callback is NULL");
753                 return WIDGET_ERROR_INVALID_PARAMETER;
754         }
755
756         foreach_context.callback = cb;
757         foreach_context.data = data;
758         appcore_multiwindow_base_instance_foreach_full(__inst_full_cb, &foreach_context);
759
760         return WIDGET_ERROR_NONE;
761 }
762
763 int __event_cb(void *event, void *data)
764 {
765         app_event_handler_h handler = data;
766
767         struct app_event_info app_event;
768
769         app_event.type = handler->type;
770         app_event.value = event;
771
772         if (handler->cb)
773                 handler->cb(&app_event, handler->data);
774
775         return 0;
776 }
777
778 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
779                                         app_event_type_e event_type, app_event_cb callback,
780                                         void *user_data)
781 {
782         int r;
783         bool feature;
784         app_event_handler_h handler;
785
786         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
787         if (r < 0)
788                 return WIDGET_ERROR_FAULT;
789
790         if (!feature)
791                 return WIDGET_ERROR_NOT_SUPPORTED;
792
793         if (event_handler == NULL || callback == NULL)
794                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
795
796         if (event_type < APP_EVENT_LOW_MEMORY
797             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
798                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
799
800         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
801                 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
802
803
804         handler = calloc(1, sizeof(struct app_event_handler));
805         if (!handler)
806                 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, "failed to create handler");
807
808         handler->type = event_type;
809         handler->cb = callback;
810         handler->data = user_data;
811         handler->raw = appcore_base_add_event(__app_event_converter[event_type], __event_cb, handler);
812         *event_handler = handler;
813
814         return WIDGET_ERROR_NONE;
815 }
816
817 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
818                                                 event_handler)
819 {
820         int r;
821         bool feature;
822
823         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
824         if (r < 0)
825                 return WIDGET_ERROR_FAULT;
826
827         if (!feature)
828                 return WIDGET_ERROR_NOT_SUPPORTED;
829
830         app_event_type_e type;
831
832         if (event_handler == NULL)
833                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
834
835         type = event_handler->type;
836         if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
837                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
838
839         r = appcore_base_remove_event(event_handler->raw);
840         if (r < 0)
841                 return widget_app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid raw handler");
842
843         free(event_handler);
844
845         return WIDGET_ERROR_NONE;
846 }
847
848 EXPORT_API const char *widget_app_get_id(widget_context_h context)
849 {
850         if (!__is_widget_feature_enabled()) {
851                 _E("not supported"); /* LCOV_EXCL_LINE */
852                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
853                 return NULL; /* LCOV_EXCL_LINE */
854         }
855
856         if (!context) {
857                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
858                 return NULL;
859         }
860
861         set_last_result(WIDGET_ERROR_NONE);
862         return appcore_multiwindow_base_instance_get_id(context);
863 }
864
865 static void __win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
866 {
867         char *plug_id;
868         plug_id = evas_object_data_del(obj, "___PLUGID");
869         free(plug_id);
870 }
871
872 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
873                                         Evas_Object **win)
874 {
875         Evas_Object *ret_win;
876         Ecore_Wl_Window *wl_win;
877         struct wl_surface *surface;
878         struct widget_extra *we;
879         char buffer[256];
880         int rots[3] = {0};
881         int win_id;
882         const char *id;
883         appcore_multiwindow_base_instance_h cxt;
884
885         if (!__is_widget_feature_enabled()) {
886                 _E("not supported"); /* LCOV_EXCL_LINE */
887                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
888         }
889
890         if (context == NULL || win == NULL)
891                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
892                                 __FUNCTION__, NULL);
893
894         cxt = (appcore_multiwindow_base_instance_h)context;
895         id = appcore_multiwindow_base_instance_get_id(cxt);
896         ret_win = elm_win_add(NULL, id, ELM_WIN_BASIC);
897         if (ret_win == NULL) {
898                 _E("failed to create window"); /* LCOV_EXCL_LINE */
899                 goto fault; /* LCOV_EXCL_LINE */
900         }
901
902         elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
903         elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
904
905         wl_win = elm_win_wl_window_get(ret_win);
906         if (wl_win == NULL) {
907                 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
908                 goto fault;
909         }
910
911         surface = ecore_wl_window_surface_get(wl_win);
912         if (surface == NULL) {
913                 _E("failed to get surface"); /* LCOV_EXCL_LINE */
914                 goto fault; /* LCOV_EXCL_LINE */
915         }
916         screen_connector_provider_remote_enable(id, surface);
917
918         ecore_wl_window_class_name_set(wl_win, id);
919         elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
920
921         *win = ret_win;
922         we  = appcore_multiwindow_base_instance_get_extra(cxt);
923         we->win = ret_win;
924         win_id = ecore_wl_window_id_get(wl_win);
925
926         /* Set data to use in accessibility */
927         snprintf(buffer, sizeof(buffer), "%s:%d", id, getpid());
928         evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
929         evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, __win_del_cb, NULL);
930         appcore_multiwindow_base_window_bind(cxt, ret_win);
931
932         _D("window created: %d", win_id);
933
934         return WIDGET_ERROR_NONE;
935
936 fault:
937         if (ret_win)    /* LCOV_EXCL_LINE */
938                 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
939
940         return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
941 }
942
943 static void __instance_drop(appcore_multiwindow_base_instance_h cxt)
944 {
945         struct widget_extra *we;
946
947         we = appcore_multiwindow_base_instance_get_extra(cxt);
948         appcore_multiwindow_base_instance_drop(cxt);
949         free(we->instance_id);
950         free(we->content);
951         free(we);
952         __check_empty_instance();
953 }
954
955 static void __stub_create(appcore_multiwindow_base_instance_h context, void *data)
956 {
957         struct widget_class_context *cxt  = data;
958         struct widget_extra *we;
959         bundle *b;
960         bundle *content_info = NULL;
961         char *id = NULL;
962         char *class_id = NULL;
963         char *operation = NULL;
964         char *content = NULL;
965         char *w_str = NULL;
966         char *h_str = NULL;
967         char *remain = NULL;
968         int w = 0;
969         int h = 0;
970         int ret = -1;
971
972         appcore_multiwindow_base_class_on_create(context);
973         we  = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
974         b = we->args;
975
976         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
977         /* for previous version compatibility, use appid for default class id */
978         if (class_id == NULL)
979                 class_id = __appid;
980
981         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
982         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
983
984         if (!operation) {
985                 _E("no operation provided");
986                 return;
987         }
988
989         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
990         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
991         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
992
993         if (w_str)
994                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
995
996         if (h_str)
997                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
998
999         if (content)
1000                 content_info = bundle_decode((const bundle_raw *)content, strlen(content));
1001
1002         if (cxt->callback.create)
1003                 ret = cxt->callback.create(context, content_info, w, h, cxt->data);
1004         _D("%s is created %d", id);
1005
1006         if (ret < 0) {
1007                 _W("Create callback returns error(%d)", ret);
1008                 ret = __send_update_status(class_id, id,
1009                                 WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL);
1010                 __instance_drop(context);
1011         } else {
1012                 ret = __send_update_status(class_id, id,
1013                         WIDGET_INSTANCE_EVENT_CREATE, NULL);
1014
1015                 aul_widget_instance_add(class_id, id);
1016         }
1017
1018         if (content_info)
1019                 bundle_free(content_info);
1020 }
1021
1022 static void __stub_terminate(appcore_multiwindow_base_instance_h context, void *data)
1023 {
1024         struct widget_class_context *class_cxt  = data;
1025         struct widget_extra *we;
1026         bundle *b;
1027         char *operation = NULL;
1028         bundle *content_info;
1029         widget_app_destroy_type_e reason = WIDGET_APP_DESTROY_TYPE_TEMPORARY;
1030         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
1031         const char *id;
1032         const char *class_id;
1033
1034         id = appcore_multiwindow_base_instance_get_id(context);
1035         class_id = appcore_multiwindow_base_instance_get_class_id(context);
1036         we  = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1037         b = we->args;
1038
1039         if (b) {
1040                 bundle_get_str(b, WIDGET_K_OPERATION, &operation);
1041                 if (operation && strcmp(operation, "destroy") == 0)
1042                         reason = WIDGET_APP_DESTROY_TYPE_PERMANENT;
1043         }
1044
1045         if (we->content)
1046                 content_info = bundle_decode((const bundle_raw *)we->content, strlen(we->content));
1047         else
1048                 content_info = bundle_create();
1049
1050         if (class_cxt->callback.destroy)
1051                 class_cxt->callback.destroy(context, reason, content_info, class_cxt->data);
1052         _D("%s is destroyed %d", id, reason);
1053
1054         if (reason == WIDGET_APP_DESTROY_TYPE_PERMANENT) {
1055                 event = WIDGET_INSTANCE_EVENT_DESTROY;
1056                 aul_widget_instance_del(class_id, id);
1057         } else {
1058                 __send_update_status(class_id, id,
1059                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
1060         }
1061
1062         if (content_info)
1063                 bundle_free(content_info);
1064
1065         __send_update_status(class_id, id, event, NULL);
1066         appcore_multiwindow_base_class_on_terminate(context);
1067 }
1068
1069 static void __stub_pause(appcore_multiwindow_base_instance_h context, void *data)
1070 {
1071         struct widget_class_context *class_cxt  = data;
1072         const char *id;
1073         const char *class_id;
1074
1075         appcore_multiwindow_base_class_on_pause(context);
1076         id = appcore_multiwindow_base_instance_get_id(context);
1077         class_id = appcore_multiwindow_base_instance_get_class_id(context);
1078
1079         if (!class_cxt) {
1080                 _E("class context is NULL");
1081                 return;
1082         }
1083
1084         if (class_cxt->callback.update)
1085                 class_cxt->callback.pause(context, class_cxt->data);
1086         _D("%s is paused", id);
1087         __send_update_status(class_id, id,
1088                 WIDGET_INSTANCE_EVENT_PAUSE, NULL);
1089 }
1090
1091 static void __stub_resume(appcore_multiwindow_base_instance_h context, void *data)
1092 {
1093         struct widget_class_context *class_cxt  = data;
1094         const char *id;
1095         const char *class_id;
1096
1097         appcore_multiwindow_base_class_on_resume(context);
1098         id = appcore_multiwindow_base_instance_get_id(context);
1099         class_id = appcore_multiwindow_base_instance_get_class_id(context);
1100
1101         if (!class_cxt) {
1102                 _E("class context is NULL");
1103                 return;
1104         }
1105
1106         if (class_cxt->callback.resume)
1107                 class_cxt->callback.resume(context, class_cxt->data);
1108         _D("%s is resumed", id);
1109         __send_update_status(class_id, id,
1110                 WIDGET_INSTANCE_EVENT_RESUME, NULL);
1111 }
1112
1113 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
1114                 const char *class_id,
1115                 widget_instance_lifecycle_callback_s callback, void *user_data)
1116 {
1117         appcore_multiwindow_base_class cls;
1118         struct widget_class_context *cxt;
1119
1120         if (!__is_widget_feature_enabled()) {
1121                 _E("not supported");
1122                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED);
1123                 return NULL;
1124         }
1125
1126         if (!class_id) {
1127                 _E("class is is NULL");
1128                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1129                 return NULL;
1130         }
1131
1132         cxt = calloc(1, sizeof(struct widget_class_context));
1133
1134         if (!cxt) {
1135                 _E("failed to calloc : %s", __FUNCTION__);
1136                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY);
1137                 return NULL;
1138         }
1139
1140         cxt->callback = callback;
1141         cxt->data = user_data;
1142
1143         cls.id = strdup(class_id);
1144         cls.data = cxt;
1145         cls.create = __stub_create;
1146         cls.terminate = __stub_terminate;
1147         cls.pause = __stub_pause;
1148         cls.resume = __stub_resume;
1149
1150         appcore_multiwindow_base_class_add(cls);
1151         set_last_result(WIDGET_ERROR_NONE);
1152
1153         return (widget_class_h)cxt;
1154 }
1155
1156 EXPORT_API widget_class_h widget_app_class_create(
1157                 widget_instance_lifecycle_callback_s callback, void *user_data)
1158 {
1159         return widget_app_class_add(NULL, __appid, callback, user_data);
1160 }
1161
1162 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
1163 {
1164         struct widget_extra *we;
1165
1166         if (!__is_widget_feature_enabled()) {
1167                 _E("not supported"); /* LCOV_EXCL_LINE */
1168                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1169         }
1170
1171         if (!context)
1172                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1173                                 __FUNCTION__, NULL);
1174
1175         we = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1176         we->extra = tag;
1177
1178         return WIDGET_ERROR_NONE;
1179 }
1180
1181 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
1182 {
1183         struct widget_extra *we;
1184
1185         if (!__is_widget_feature_enabled()) {
1186                 _E("not supported"); /* LCOV_EXCL_LINE */
1187                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1188         }
1189
1190         if (!context || !tag)
1191                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1192                                 __FUNCTION__, NULL);
1193
1194         we  = appcore_multiwindow_base_instance_get_extra((appcore_multiwindow_base_instance_h)context);
1195         if (we == NULL)
1196                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1197                                 __FUNCTION__, NULL);
1198         *tag = we->extra;
1199
1200         return WIDGET_ERROR_NONE;
1201 }
1202
1203 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
1204                 bundle *content_info)
1205 {
1206         int ret = 0;
1207         bundle_raw *raw = NULL;
1208         int len;
1209         const char *id;
1210         const char *class_id;
1211         struct widget_extra *we;
1212         appcore_multiwindow_base_instance_h cxt;
1213
1214         if (!__is_widget_feature_enabled()) {
1215                 _E("not supported"); /* LCOV_EXCL_LINE */
1216                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1217         }
1218
1219         if (!context || !content_info)
1220                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1221                                 __FUNCTION__, NULL);
1222
1223         cxt = (appcore_multiwindow_base_instance_h)context;
1224         id = appcore_multiwindow_base_instance_get_id(cxt);
1225         class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
1226         we  = appcore_multiwindow_base_instance_get_extra(cxt);
1227
1228         if (!class_id || !id || !we)
1229                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
1230
1231         ret = __send_update_status(class_id, id,
1232                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
1233
1234         if (we->content)
1235                 free(we->content);
1236
1237         bundle_encode(content_info, &raw, &len);
1238         if (raw)
1239                 we->content = strdup((const char *)raw);
1240         else
1241                 we->content = NULL;
1242
1243         free(raw);
1244         if (ret < 0) {
1245                 /* LCOV_EXCL_START */
1246                 _E("failed to send content info: %s of %s (%d)", id,
1247                                 class_id, ret);
1248                 return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__,
1249                                 NULL);
1250                 /* LCOV_EXCL_STOP */
1251         }
1252
1253         return WIDGET_ERROR_NONE;
1254 }
1255
1256 EXPORT_API int widget_app_context_set_title(widget_context_h context,
1257                 const char *title)
1258 {
1259         appcore_multiwindow_base_instance_h cxt;
1260         struct widget_extra *we;
1261
1262         if (!__is_widget_feature_enabled()) {
1263                 _E("not supported"); /* LCOV_EXCL_LINE */
1264                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1265         }
1266
1267         if (!context || !title) {
1268                 _E("Invalid parameter %p %p", context, title);
1269                 return WIDGET_ERROR_INVALID_PARAMETER;
1270         }
1271
1272         cxt = (appcore_multiwindow_base_instance_h)context;
1273         we  = appcore_multiwindow_base_instance_get_extra(cxt);
1274
1275         if (we->win)
1276                 elm_win_title_set(we->win, title);
1277
1278         return WIDGET_ERROR_NONE;
1279 }