b3c18c5af2a084afa0ac94128e25af9cbab26637
[platform/core/appfw/appcore-widget.git] / src / widget_app.c
1 /*
2  * Copyright (c) 2015 - 2016 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
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 <app_control.h>
28 #include <app_control_internal.h>
29 #include <Elementary.h>
30 #include <widget_errno.h>
31 #include <widget_instance.h>
32 #include <widget_service.h>
33 #include <widget_service_internal.h>
34 #include <aul_app_com.h>
35 #include <Ecore_Wayland.h>
36 #include <system_info.h>
37 #include <vconf.h>
38 #include <vconf-internal-keys.h>
39 #include <screen_connector_provider.h>
40
41 #include "widget_app.h"
42 #include "widget-log.h"
43 #include "widget-private.h"
44 #include "widget_app_internal.h"
45
46 #ifdef LOG_TAG
47 #undef LOG_TAG
48 #endif
49
50 #define STR_MAX_BUF 128
51 #define LOG_TAG "CAPI_WIDGET_APPLICATION"
52 #define K_REASON    "__WC_K_REASON__"
53
54 typedef enum _widget_obj_state_e {
55         WC_READY = 0,
56         WC_RUNNING = 1,
57         WC_PAUSED = 2,
58         WC_TERMINATED = 3
59 } widget_obj_state_e;
60
61 enum {
62         UPDATE_LOCAL = 0,
63         UPDATE_ALL = 1,
64 };
65
66 struct app_event_handler {
67         app_event_type_e type;
68         app_event_cb cb;
69         void *data;
70 };
71
72 struct app_event_info {
73         app_event_type_e type;
74         void *value;
75 };
76
77 typedef struct _widget_class widget_class_s;
78
79 #define WIDGET_APP_EVENT_MAX 5
80 static GList *handler_list[WIDGET_APP_EVENT_MAX] = {NULL, };
81
82 static int caller_pid;
83 static widget_app_lifecycle_callback_s *app_ops;
84 static void *app_user_data;
85 static char *appid;
86 static widget_class_h class_provider;
87 static int exit_called;
88 static char *package_id;
89
90 static void _widget_core_set_appcore_event_cb(void);
91 static void _widget_core_unset_appcore_event_cb(void);
92
93 static void __free_handler_cb(gpointer data)
94 {
95         if (data)
96                 free(data);
97 }
98
99 static void __free_handler_list(void)
100 {
101         int i;
102
103         for (i = 0; i < WIDGET_APP_EVENT_MAX; i++) {
104                 g_list_free_full(handler_list[i], __free_handler_cb);
105                 handler_list[i] = NULL;
106         }
107 }
108
109 static inline bool _is_widget_feature_enabled(void)
110 {
111         static bool feature = false;
112         static bool retrieved = false;
113         int ret;
114
115         if (retrieved == true)
116                 return feature;
117
118         ret = system_info_get_platform_bool(
119                         "http://tizen.org/feature/shell.appwidget", &feature);
120         if (ret != SYSTEM_INFO_ERROR_NONE) {
121                 _E("failed to get system info"); /* LCOV_EXCL_LINE */
122                 return false; /* LCOV_EXCL_LINE */
123         }
124
125         retrieved = true;
126
127         return feature;
128 }
129
130 static gint __comp_by_id(gconstpointer a, gconstpointer b)
131 {
132         widget_context_s *wc = (widget_context_s *)a;
133
134         return strcmp(wc->id, (const char *)b);
135 }
136
137 static widget_context_s *__find_context_by_id(const char *id)
138 {
139         GList *ret;
140         GList *contexts = _widget_app_get_contexts();
141
142         if (id == NULL)
143                 return NULL;
144
145         ret = g_list_find_custom(contexts, id, __comp_by_id);
146         if (ret == NULL)
147                 return NULL;
148
149         return ret->data;
150 }
151
152 static gint __comp_by_win(gconstpointer a, gconstpointer b)
153 {
154         int win = GPOINTER_TO_INT(b);
155         widget_context_s *wc = (widget_context_s *)a;
156
157         return (wc && wc->win_id == win) ? 0 : -1;
158 }
159
160 static widget_context_s *__find_context_by_win(int win)
161 {
162         GList *contexts = _widget_app_get_contexts();
163         GList *ret = g_list_find_custom(contexts, GINT_TO_POINTER(win), __comp_by_win);
164
165         if (ret == NULL)
166                 return NULL;
167
168         return ret->data;
169 }
170
171 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
172         int status)
173 {
174         bundle *b = bundle_create();
175         char pkgid[256] = {0, };
176         int ret;
177
178         if (b == NULL) {
179                 _E("out of memory"); /* LCOV_EXCL_LINE */
180                 return -1; /* LCOV_EXCL_LINE */
181         }
182
183         if (package_id == NULL) {
184                 ret = aul_app_get_pkgid_bypid(getpid(), pkgid, sizeof(pkgid));
185                 if (ret == 0)
186                         package_id = strdup(pkgid);
187         }
188
189         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
190         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
191         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
192         if (package_id)
193                 bundle_add_str(b, AUL_K_PKGID, package_id);
194
195         _D("send lifecycle %s(%d)", instance_id, status);
196         ret = aul_app_com_send("widget.status", b);
197         if (ret < 0)
198                 _E("send lifecycle error:%d", ret); /* LCOV_EXCL_LINE */
199
200         bundle_free(b);
201
202         return ret;
203 }
204
205 static int __send_update_status(const char *class_id, const char *instance_id,
206         int status, bundle *extra)
207 {
208         bundle *b;
209         int lifecycle = -1;
210         bundle_raw *raw = NULL;
211         int len;
212         char *viewer_endpoint = _widget_app_get_viewer_endpoint();
213
214         b = bundle_create();
215         if (!b) {
216                 _E("out of memory"); /* LCOV_EXCL_LINE */
217                 return -1; /* LCOV_EXCL_LINE */
218         }
219
220         bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
221         bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
222         bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
223
224         if (extra) {
225                 bundle_encode(extra, &raw, &len);
226                 bundle_add_str(b, WIDGET_K_CONTENT_INFO, (const char *)raw);
227                 aul_widget_instance_add(class_id, instance_id);
228         }
229
230         _D("send update %s(%d) to %s", instance_id, status, viewer_endpoint);
231         aul_app_com_send(viewer_endpoint, b);
232
233         switch (status) {
234         case WIDGET_INSTANCE_EVENT_CREATE:
235                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_CREATE;
236                 break;
237         case WIDGET_INSTANCE_EVENT_DESTROY:
238                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_DESTROY;
239                 break;
240         case WIDGET_INSTANCE_EVENT_PAUSE:
241                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_PAUSE;
242                 break;
243         case WIDGET_INSTANCE_EVENT_RESUME:
244                 lifecycle = WIDGET_LIFE_CYCLE_EVENT_RESUME;
245                 break;
246         }
247
248         if (lifecycle > -1)
249                 __send_lifecycle_event(class_id, instance_id, lifecycle);
250
251         bundle_free(b);
252         if (raw)
253                 free(raw);
254
255         return 0;
256 }
257
258 static int __instance_resume(widget_class_h handle, const char *id, int send_update)
259 {
260         widget_context_s *wc = __find_context_by_id(id);
261         int ret;
262
263         if (!wc) {
264                 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
265                 return -1; /* LCOV_EXCL_LINE */
266         }
267
268         if (wc->state == WC_RUNNING) {
269                 _D("%s is already in running state", id); /* LCOV_EXCL_LINE */
270                 return 0; /* LCOV_EXCL_LINE */
271         }
272
273         if (wc->state == WC_TERMINATED) {
274                 _D("%s is in terminated state", id); /* LCOV_EXCL_LINE */
275                 return 0; /* LCOV_EXCL_LINE */
276         }
277
278         if (handle->ops.resume)
279                 handle->ops.resume(wc, handle->user_data);
280
281         wc->state = WC_RUNNING;
282         _D("%s is resumed", id);
283         if (send_update) {
284                 ret = __send_update_status(handle->classid, wc->id,
285                         WIDGET_INSTANCE_EVENT_RESUME, NULL);
286         } else {
287                 ret = 0;
288         }
289
290         return ret;
291 }
292
293 static int __instance_pause(widget_class_h handle, const char *id, int send_update)
294 {
295         widget_context_s *wc = __find_context_by_id(id);
296         int ret;
297
298         if (!wc) {
299                 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
300                 return -1; /* LCOV_EXCL_LINE */
301         }
302
303         if (wc->state == WC_PAUSED) {
304                 _D("%s is already in paused state", id); /* LCOV_EXCL_LINE */
305                 return 0; /* LCOV_EXCL_LINE */
306         }
307
308         if (wc->state == WC_TERMINATED) {
309                 _D("%s is in terminated state", id); /* LCOV_EXCL_LINE */
310                 return 0; /* LCOV_EXCL_LINE */
311         }
312
313         if (handle->ops.pause)
314                 handle->ops.pause(wc, handle->user_data);
315
316         wc->state = WC_PAUSED;
317         _D("%s is paused", id);
318         if (send_update) {
319                 ret = __send_update_status(handle->classid, wc->id,
320                         WIDGET_INSTANCE_EVENT_PAUSE, NULL);
321         } else {
322                 ret = 0;
323         }
324
325         return ret;
326 }
327
328 static int __instance_resize(widget_class_h handle, const char *id, int w, int h)
329 {
330         widget_context_s *wc = __find_context_by_id(id);
331         int ret;
332
333         if (!wc) {
334                 _E("context not found: %s", id); /* LCOV_EXCL_LINE */
335                 return -1; /* LCOV_EXCL_LINE */
336         }
337
338         if (handle->ops.resize)
339                 handle->ops.resize(wc, w, h, handle->user_data);
340
341         _D("%s is resized to %dx%d", id, w, h);
342         ret = __send_update_status(handle->classid, wc->id,
343                 WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL);
344
345         return ret;
346 }
347
348 /* LCOV_EXCL_START */
349 static int __instance_update_all(widget_class_h handle, int force, const char *content)
350 {
351         widget_context_s *wc;
352         int ret = 0;
353         bundle *b = NULL;
354         GList *context = _widget_app_get_contexts();
355
356         if (content)
357                 b = bundle_decode((const bundle_raw *)content, strlen(content));
358
359         if (handle->ops.update) {
360                 while (context) {
361                         wc = (widget_context_s *)context->data;
362                         handle->ops.update(wc, b, force, handle->user_data);
363                         ret = __send_update_status(handle->classid, wc->id,
364                                 WIDGET_INSTANCE_EVENT_UPDATE, NULL);
365                         _D("updated:%s", wc->id);
366                         context = context->next;
367                 }
368         }
369
370         if (b)
371                 bundle_free(b);
372
373         return ret;
374 }
375 /* LCOV_EXCL_STOP */
376
377 /* LCOV_EXCL_START */
378 static int __instance_update(widget_class_h handle, const char *id, int force, const char *content)
379 {
380         widget_context_s *wc = __find_context_by_id(id);
381         int ret = 0;
382         bundle *b = NULL;
383         if (!wc) {
384                 _E("context not found: %s", id);
385                 return -1;
386         }
387
388         if (content)
389                 b = bundle_decode((const bundle_raw *)content, strlen(content));
390
391         if (handle->ops.update) {
392                 handle->ops.update(wc, b, force, handle->user_data);
393                 ret = __send_update_status(handle->classid, wc->id,
394                         WIDGET_INSTANCE_EVENT_UPDATE, NULL);
395                 _D("updated:%s", id);
396         }
397
398         if (b)
399                 bundle_free(b);
400
401         return ret;
402 }
403 /* LCOV_EXCL_STOP */
404
405 static int __instance_create(widget_class_h handle, const char *id, const char *content, int w, int h)
406 {
407         widget_context_s *wc = NULL;
408         int ret = 0;
409         bundle *content_info = NULL;
410
411         wc = (widget_context_s *)calloc(1, sizeof(widget_context_s));
412         if (!wc)
413                 return WIDGET_ERROR_OUT_OF_MEMORY;
414
415         wc->state = WC_READY;
416         wc->id = strdup(id);
417         wc->provider = handle;
418         wc->win = NULL;
419         wc->win_id = -1;
420
421         if (content) {
422                 wc->content = strdup(content);
423                 content_info = bundle_decode((const bundle_raw *)content, strlen(content));
424         }
425
426         _widget_app_add_context(wc);
427
428         ret = handle->ops.create(wc, content_info, w, h, handle->user_data);
429         if (ret < 0) {
430                 /* TODO send abort */
431         } else {
432                 ret = __send_update_status(handle->classid, wc->id,
433                         WIDGET_INSTANCE_EVENT_CREATE, NULL);
434
435                 if (content == NULL)
436                         content = "NULL";
437
438                 aul_widget_instance_add(handle->classid, id);
439         }
440
441         if (content_info)
442                 bundle_free(content_info);
443
444         return ret;
445 }
446
447 static int __instance_destroy(widget_class_h handle, const char *id,
448                 widget_app_destroy_type_e reason, int send_update)
449 {
450         widget_context_s *wc = __find_context_by_id(id);
451         int ret = 0;
452         int event = WIDGET_INSTANCE_EVENT_TERMINATE;
453         bundle *content_info;
454
455         if (!wc) {
456                 _E("could not find widget obj: %s, clear amd info", id);        /* LCOV_EXCL_LINE */
457                 aul_widget_instance_del(handle->classid, id);                   /* LCOV_EXCL_LINE */
458                 return WIDGET_ERROR_NONE;                                       /* LCOV_EXCL_LINE */
459         }
460
461         wc->state = WC_TERMINATED;
462         if (wc->content)
463                 content_info = bundle_decode((const bundle_raw *)wc->content, strlen(wc->content));
464         else
465                 content_info = bundle_create();
466
467         handle->ops.destroy(wc, reason, content_info,
468                         handle->user_data);
469
470         if (reason == WIDGET_APP_DESTROY_TYPE_PERMANENT) {
471                 event = WIDGET_INSTANCE_EVENT_DESTROY;
472                 aul_widget_instance_del(handle->classid, id);
473         } else {
474                 ret = __send_update_status(handle->classid, id,
475                                 WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
476         }
477
478         if (content_info)
479                 bundle_free(content_info);
480
481         ret = __send_update_status(handle->classid, id, event, NULL);
482
483         _widget_app_remove_context(wc);
484
485         if (wc->id)
486                 free(wc->id);
487
488         if (wc->content)
489                 free(wc->content);
490
491         free(wc);
492
493         if (_widget_app_get_contexts() == NULL && !exit_called) /* all instance destroyed */
494                 widget_app_exit();
495
496         return ret;
497 }
498
499 static widget_class_h __find_class_handler(const char *class_id,
500                 widget_class_h handle)
501 {
502         if (!class_id || !handle)
503                 return NULL;
504
505         widget_class_h head = handle;
506
507         while (head) {
508                 if (head->classid && strcmp(head->classid, class_id) == 0)
509                         return head;
510
511                 head = head->next;
512         }
513
514         return NULL;
515 }
516
517 /* LCOV_EXCL_START */
518 static void __resize_window(char *id, int w, int h)
519 {
520         widget_context_s *wc = __find_context_by_id(id);
521
522         if (!wc) {
523                 _E("can not find instance: %s", id);
524                 return;
525         }
526
527         if (wc->win)
528                 evas_object_resize(wc->win, w, h);
529         else
530                 _E("unable to find window of %d", wc->id);
531 }
532 /* LCOV_EXCL_STOP */
533
534 static void __control(bundle *b)
535 {
536         char *class_id = NULL;
537         char *id = NULL;
538         char *operation = NULL;
539         char *content = NULL;
540         char *w_str = NULL;
541         char *h_str = NULL;
542         int w = 0;
543         int h = 0;
544         char *remain = NULL;
545         int force;
546         char *force_str = NULL;
547         widget_class_h handle = NULL;
548
549         bundle_get_str(b, WIDGET_K_CLASS, &class_id);
550         /* for previous version compatibility, use appid for default class id */
551         if (class_id == NULL)
552                 class_id = appid;
553
554         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
555         bundle_get_str(b, WIDGET_K_OPERATION, &operation);
556
557         handle = __find_class_handler(class_id, class_provider);
558         if (!handle) {
559                 _E("no handle provided: %s", class_id); /* LCOV_EXCL_LINE */
560                 goto error;
561         }
562
563         if (!operation) {
564                 _E("no operation provided");
565                 goto error;
566         }
567
568         bundle_get_str(b, WIDGET_K_FORCE, &force_str);
569
570         if (force_str && strcmp(force_str, "true") == 0)
571                 force = 1;
572         else
573                 force = 0;
574
575         bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content);
576         bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
577         bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
578         if (w_str)
579                 w = (int)g_ascii_strtoll(w_str, &remain, 10);
580
581         if (h_str)
582                 h = (int)g_ascii_strtoll(h_str, &remain, 10);
583
584         if (strcmp(operation, "create") == 0) {
585                 __instance_create(handle, id, content, w, h);
586         } else if (strcmp(operation, "resize") == 0) {
587                 __resize_window(id, w, h);
588         } else if (strcmp(operation, "update") == 0) {
589                 if (id)
590                         __instance_update(handle, id, force, content);
591                 else
592                         __instance_update_all(handle, force, content);
593
594         } else if (strcmp(operation, "destroy") == 0) {
595                 __instance_destroy(handle, id, WIDGET_APP_DESTROY_TYPE_PERMANENT, UPDATE_ALL);
596         } else if (strcmp(operation, "resume") == 0) {
597                 __instance_resume(handle, id, UPDATE_ALL);
598         } else if (strcmp(operation, "pause") == 0) {
599                 __instance_pause(handle, id, UPDATE_ALL);
600         } else if (strcmp(operation, "terminate") == 0) {
601                 __instance_destroy(handle, id, WIDGET_APP_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
602         }
603
604         return;
605 error:
606         LOGD("error on control");
607         return;
608 }
609
610 static void __pause_all(int send_update)
611 {
612         GList *contexts = _widget_app_get_contexts();
613         GList *iter = g_list_first(contexts);
614
615         while (iter != NULL) {
616                 widget_context_s *cxt = (widget_context_s *)iter->data;
617
618                 switch (cxt->state) {
619                 case WC_READY:
620                         __instance_resume(cxt->provider, cxt->id, send_update);
621                         __instance_pause(cxt->provider, cxt->id, send_update);
622                         break;
623                 case WC_RUNNING:
624                         __instance_pause(cxt->provider, cxt->id, send_update);
625                         break;
626                 }
627                 LOGD("pause %s", cxt->id);
628                 iter = g_list_next(iter);
629         }
630 }
631
632 /* LCOV_EXCL_START */
633 static void __resume_all(int send_update)
634 {
635         GList *contexts = _widget_app_get_contexts();
636         GList *iter = g_list_first(contexts);
637
638         while (iter != NULL) {
639                 widget_context_s *cxt = (widget_context_s *)iter->data;
640
641                 switch (cxt->state) {
642                 case WC_READY:
643                         __instance_resume(cxt->provider, cxt->id, send_update);
644                         break;
645                 case WC_PAUSED:
646                         __instance_resume(cxt->provider, cxt->id, send_update);
647                         break;
648                 }
649                 iter = g_list_next(iter);
650         }
651 }
652 /* LCOV_EXCL_STOP */
653
654 static void __destroy_all(int reason, int send_update)
655 {
656         GList *contexts = _widget_app_get_contexts();
657         GList *iter = g_list_first(contexts);
658
659         __pause_all(send_update);
660         while (iter != NULL) {
661                 widget_context_s *cxt = (widget_context_s *)iter->data;
662                 iter = g_list_next(iter);
663                 switch (cxt->state) {
664                 case WC_PAUSED:
665                         LOGD("destroy %d : %s", cxt->state, cxt->id);
666                         __instance_destroy(cxt->provider, cxt->id, reason, send_update);
667                         break;
668                 }
669         }
670 }
671
672
673 static Eina_Bool __show_cb(void *data, int type, void *event)
674 {
675         Ecore_Wl_Event_Window_Show *ev = event;
676         widget_context_s *cxt = __find_context_by_win(ev->win);
677
678         LOGD("show %d %d", (unsigned int)ev->win, (unsigned int)ev->data[0]);
679
680         if (cxt)
681                 __instance_resume(cxt->provider, cxt->id, UPDATE_ALL);
682         else
683                 LOGE("unknown window error: %d", ev->win); /* LCOV_EXCL_LINE */
684
685         return ECORE_CALLBACK_RENEW;
686 }
687
688 static Eina_Bool __hide_cb(void *data, int type, void *event)
689 {
690         Ecore_Wl_Event_Window_Hide *ev = event;
691         widget_context_s *cxt = __find_context_by_win(ev->win);
692
693
694         LOGD("hide %d", (unsigned int)ev->win);
695
696         if (cxt)
697                 __instance_pause(cxt->provider, cxt->id, UPDATE_ALL);
698         else
699                 LOGE("unknown window error: %d", ev->win); /* LCOV_EXCL_LINE */
700
701         return ECORE_CALLBACK_RENEW;
702 }
703
704 static Eina_Bool __visibility_cb(void *data, int type, void *event)
705 {
706         Ecore_Wl_Event_Window_Visibility_Change *ev = event;
707         widget_context_s *cxt = __find_context_by_win(ev->win);
708
709         LOGD("visiblity change: %d %d", (unsigned int)ev->win,  (unsigned int)ev->fully_obscured);
710
711         if (!cxt) {
712                 LOGE("unknown window error: %d", ev->win);
713                 return ECORE_CALLBACK_RENEW;
714         }
715
716         if (cxt->state == WC_PAUSED && ev->fully_obscured == 0) {
717                 __instance_resume(cxt->provider, cxt->id, UPDATE_ALL);
718         } else if (cxt->state == WC_RUNNING && ev->fully_obscured == 1) {
719                 __instance_pause(cxt->provider, cxt->id, UPDATE_ALL);
720         } else {
721                 LOGD("cxt:%s state:%d obscured:%d", cxt->id, cxt->state, ev->fully_obscured);
722         }
723
724         return ECORE_CALLBACK_RENEW;
725 }
726
727 /* LCOV_EXCL_START */
728 static Eina_Bool __lower_cb(void *data, int type, void *event)
729 {
730         LOGD("lower");
731         return ECORE_CALLBACK_RENEW;
732 }
733 /* LCOV_EXCL_STOP */
734
735 static Eina_Bool __configure_cb(void *data, int type, void *event)
736 {
737         Ecore_Wl_Event_Window_Configure *ev = event;
738         widget_context_s *cxt = __find_context_by_win(ev->win);
739
740         LOGD("configure: %d %d", ev->w, ev->h);
741
742         if (!cxt) {
743                 LOGE("unknown window error: %d", ev->win); /* LCOV_EXCL_LINE */
744                 return ECORE_CALLBACK_RENEW; /* LCOV_EXCL_LINE */
745         }
746
747         if (cxt->state == WC_PAUSED || cxt->state == WC_RUNNING)
748                 __instance_resize(cxt->provider, cxt->id, ev->w, ev->h);
749         LOGD("cxt:%s resized to %dx%d", cxt->id, ev->w, ev->h);
750
751         return ECORE_CALLBACK_RENEW;
752 }
753
754 static void __add_climsg()
755 {
756         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, NULL);
757         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, NULL);
758         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE, __visibility_cb, NULL);
759         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER, __lower_cb, NULL);
760         ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, __configure_cb, NULL);
761 }
762
763 static void __get_content(bundle *b)
764 {
765         char *instance_id = NULL;
766         widget_context_s *cxt = NULL;
767
768         bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &instance_id);
769         if (!instance_id)
770                 return;
771
772         cxt = __find_context_by_id(instance_id);
773         if (!cxt) {
774                 _E("can not find instance id:%s", instance_id);
775                 return;
776         }
777
778         if (cxt->content) {
779                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, cxt->content);
780                 _D("content info of %s found", cxt->id);
781         } else {
782                 bundle_add_str(b, AUL_K_WIDGET_CONTENT_INFO, "");
783                 _D("empty content info added");
784         }
785 }
786
787 static int __aul_handler(aul_type type, bundle *b, void *data)
788 {
789         char *caller = NULL;
790         char *remain = NULL;
791
792         switch (type) {
793         case AUL_START:
794                 if (b) {
795                         bundle_get_str(b, WIDGET_K_CALLER, &caller);
796                         if (caller) {
797                                 caller_pid = g_ascii_strtoll(caller, &remain,
798                                                 10);
799                         } else {
800                                 /* using caller appid and query pid using caller appid? */
801                                 _E("no caller pid");
802                         }
803                 }
804
805                 __control(b);
806                 break;
807         case AUL_RESUME:
808                 __resume_all(UPDATE_ALL);
809                 break;
810         case AUL_TERMINATE:
811                 widget_app_exit();
812                 break;
813         case AUL_WIDGET_CONTENT:
814                 __get_content(b);
815                 break;
816         default:
817                 break;
818         }
819
820         return 0;
821 }
822
823 static char *__get_domain_name(char *appid)
824 {
825         char *name_token;
826
827         if (appid == NULL) {
828                 _E("appid is NULL"); /* LCOV_EXCL_LINE */
829                 return NULL; /* LCOV_EXCL_LINE */
830         }
831
832         name_token = strrchr(appid, '.');
833
834         if (name_token == NULL) {
835                 _E("appid is invalid"); /* LCOV_EXCL_LINE */
836                 return appid; /* LCOV_EXCL_LINE */
837         }
838
839         name_token++;
840
841         return name_token;
842 }
843
844 /* LCOV_EXCL_START */
845 static void __on_poweroff(keynode_t *key, void *data)
846 {
847         int val;
848
849         val = vconf_keynode_get_int(key);
850         switch (val) {
851         case VCONFKEY_SYSMAN_POWER_OFF_DIRECT:
852         case VCONFKEY_SYSMAN_POWER_OFF_RESTART:
853                 _I("power off changed: %d", val);
854                 widget_app_exit();
855                 break;
856         case VCONFKEY_SYSMAN_POWER_OFF_NONE:
857         case VCONFKEY_SYSMAN_POWER_OFF_POPUP:
858         default:
859                 /* DO NOTHING */
860                 break;
861         }
862 }
863 /* LCOV_EXCL_STOP */
864
865 extern int _set_i18n(const char *name);
866
867 static int __before_loop(int argc, char **argv)
868 {
869         int r;
870         bundle *kb = NULL;
871         char *name;
872         char *viewer_endpoint = NULL;
873
874 #if !(GLIB_CHECK_VERSION(2, 36, 0))
875         g_type_init();
876 #endif
877
878         kb = bundle_import_from_argv(argc, argv);
879         if (kb) {
880                 bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
881                 if (viewer_endpoint) {
882                         _E("viewer endpoint :%s", viewer_endpoint);
883                         _widget_app_set_viewer_endpoint(viewer_endpoint);
884                 } else {
885                         _E("endpoint is missing");
886                 }
887
888                 bundle_free(kb);
889                 kb = NULL;
890         } else {
891                 _E("failed to get launch argv"); /* LCOV_EXCL_LINE */
892         }
893
894         screen_connector_provider_init();
895         elm_init(argc, argv);
896
897         r = aul_launch_init(__aul_handler, NULL);
898         if (r < 0) {
899                 /* LCOV_EXCL_START */
900                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
901                                 __FUNCTION__,
902                                 "Fail to call the aul_launch_init");
903                 /* LCOV_EXCL_STOP */
904         }
905
906         r = aul_launch_argv_handler(argc, argv);
907         if (r < 0) {
908                 /* LCOV_EXCL_START */
909                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
910                                 __FUNCTION__,
911                                 "Fail to call the aul_launch_argv_handler");
912                 /* LCOV_EXCL_STOP */
913         }
914
915         r = app_get_id(&appid);
916         if (r != APP_ERROR_NONE)
917                 return r;
918
919         name = __get_domain_name(appid);
920
921         if (name == NULL) {
922                 /* LCOV_EXCL_START */
923                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
924                                 __FUNCTION__,
925                                 "Fail to call __get_domain_name");
926                 /* LCOV_EXCL_STOP */
927         }
928
929         r = _set_i18n(name);
930
931         if (r < 0) {
932                 /* LCOV_EXCL_START */
933                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
934                                 __FUNCTION__,
935                                 "Fail to call _set_i18n");
936                 /* LCOV_EXCL_STOP */
937         }
938
939         __add_climsg();
940
941         _widget_core_set_appcore_event_cb();
942
943         class_provider = app_ops->create(app_user_data);
944         if (class_provider == NULL) {
945                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
946                                 __FUNCTION__, "widget_class is NULL");
947         }
948
949         vconf_notify_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff, NULL);
950
951         return WIDGET_ERROR_NONE;
952 }
953
954 static void __after_loop()
955 {
956         exit_called = 1;
957         vconf_ignore_key_changed(VCONFKEY_SYSMAN_POWER_OFF_STATUS, __on_poweroff);
958
959         __pause_all(UPDATE_LOCAL);
960         __destroy_all(WIDGET_APP_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
961
962         if (app_ops->terminate)
963                 app_ops->terminate(app_user_data);
964
965         screen_connector_provider_fini();
966
967         _widget_app_free_viewer_endpoint();
968         _widget_core_unset_appcore_event_cb();
969         __free_handler_list();
970
971         if (package_id) {
972                 free(package_id);
973                 package_id = NULL;
974         }
975
976         if (appid) {
977                 free(appid);
978                 appid = NULL;
979         }
980
981         elm_shutdown();
982 }
983
984 static void __on_low_memory(keynode_t *key, void *data)
985 {
986         int val;
987
988         val = vconf_keynode_get_int(key);
989         if (val == VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
990                 app_event_handler_h handler;
991                 struct app_event_info event;
992
993                 _I("widget_app_low_memory");
994
995                 event.type = APP_EVENT_LOW_MEMORY;
996                 event.value = (void *)&val;
997
998                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_MEMORY]);
999
1000                 while (iter) {
1001                         handler = (app_event_handler_h) iter->data;
1002                         handler->cb(&event, handler->data);
1003                         iter = g_list_next(iter);
1004                 }
1005         }
1006 }
1007
1008 static void __on_low_battery(keynode_t *key, void *data)
1009 {
1010         int val;
1011
1012         val = vconf_keynode_get_int(key);
1013         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) {
1014                 app_event_handler_h handler;
1015                 struct app_event_info event;
1016
1017                 _I("widget_app_low_battery");
1018
1019                 event.type = APP_EVENT_LOW_BATTERY;
1020                 event.value = (void *)&val;
1021
1022                 GList *iter = g_list_first(handler_list[APP_EVENT_LOW_BATTERY]);
1023
1024                 while (iter) {
1025                         handler = (app_event_handler_h) iter->data;
1026                         handler->cb(&event, handler->data);
1027                         iter = g_list_next(iter);
1028                 }
1029         }
1030 }
1031
1032 static void __on_lang_changed(keynode_t *key, void *data)
1033 {
1034         char *val;
1035
1036         _update_lang();
1037         val = vconf_keynode_get_str(key);
1038
1039         app_event_handler_h handler;
1040         struct app_event_info event;
1041
1042         _I("widget_app_lang_changed");
1043
1044         event.type = APP_EVENT_LANGUAGE_CHANGED;
1045         event.value = (void *)val;
1046
1047         GList *iter = g_list_first(handler_list[APP_EVENT_LANGUAGE_CHANGED]);
1048
1049         while (iter) {
1050                 handler = (app_event_handler_h) iter->data;
1051                 handler->cb(&event, handler->data);
1052                 iter = g_list_next(iter);
1053         }
1054 }
1055
1056 static void __on_region_changed(keynode_t *key, void *data)
1057 {
1058         char *val;
1059
1060         _update_region();
1061         val = vconf_keynode_get_str(key);
1062
1063         app_event_handler_h handler;
1064         struct app_event_info event;
1065
1066         _I("widget_app_region_changed");
1067
1068         event.type = APP_EVENT_REGION_FORMAT_CHANGED;
1069         event.value = (void *)val;
1070
1071         GList *iter = g_list_first(handler_list[APP_EVENT_REGION_FORMAT_CHANGED]);
1072
1073         while (iter) {
1074                 handler = (app_event_handler_h) iter->data;
1075                 handler->cb(&event, handler->data);
1076                 iter = g_list_next(iter);
1077         }
1078 }
1079
1080 static void __register_event(int event_type)
1081 {
1082         switch (event_type) {
1083         case APP_EVENT_LOW_MEMORY:
1084                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
1085                 break;
1086
1087         case APP_EVENT_LOW_BATTERY:
1088                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
1089                 break;
1090
1091         case APP_EVENT_LANGUAGE_CHANGED:
1092                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_lang_changed, NULL);
1093                 break;
1094
1095         case APP_EVENT_REGION_FORMAT_CHANGED:
1096                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed, NULL);
1097                 break;
1098         }
1099 }
1100
1101 static void __unregister_event(int event_type)
1102 {
1103         switch (event_type) {
1104         case APP_EVENT_LOW_MEMORY:
1105                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
1106                 break;
1107
1108         case APP_EVENT_LOW_BATTERY:
1109                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
1110                 break;
1111
1112         case APP_EVENT_LANGUAGE_CHANGED:
1113                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_lang_changed);
1114                 break;
1115
1116         case APP_EVENT_REGION_FORMAT_CHANGED:
1117                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_changed);
1118                 break;
1119         }
1120 }
1121
1122 static void _widget_core_set_appcore_event_cb(void)
1123 {
1124         __register_event(APP_EVENT_LANGUAGE_CHANGED);
1125         __register_event(APP_EVENT_REGION_FORMAT_CHANGED);
1126 }
1127
1128 static void _widget_core_unset_appcore_event_cb(void)
1129 {
1130         __unregister_event(APP_EVENT_LANGUAGE_CHANGED);
1131         __unregister_event(APP_EVENT_REGION_FORMAT_CHANGED);
1132 }
1133
1134 EXPORT_API int widget_app_main(int argc, char **argv,
1135                 widget_app_lifecycle_callback_s *callback, void *user_data)
1136 {
1137         int r;
1138
1139         if (!_is_widget_feature_enabled()) {
1140                 _E("not supported"); /* LCOV_EXCL_LINE */
1141                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1142         }
1143
1144         if (argc <= 0 || argv == NULL || callback == NULL)
1145                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1146                                 __FUNCTION__, NULL);
1147
1148         if (callback->create == NULL)
1149                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1150                                 __FUNCTION__,
1151                                 "widget_app_create_cb() callback must be "
1152                                 "registered");
1153         app_ops = callback;
1154         app_user_data = user_data;
1155         r = __before_loop(argc, argv);
1156         if (r < 0) {
1157                 if (appid) {
1158                         free(appid);
1159                         appid = NULL;
1160                 }
1161                 return r;
1162         }
1163
1164         ecore_main_loop_begin();
1165         aul_status_update(STATUS_DYING);
1166         __after_loop();
1167
1168         return WIDGET_ERROR_NONE;
1169 }
1170
1171 EXPORT_API int widget_app_exit(void)
1172 {
1173         if (!_is_widget_feature_enabled()) {
1174                 _E("not supported"); /* LCOV_EXCL_LINE */
1175                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1176         }
1177
1178         if (exit_called)
1179                 return WIDGET_ERROR_NONE;
1180
1181         exit_called = 1;
1182
1183         ecore_main_loop_quit();
1184
1185         return WIDGET_ERROR_NONE;
1186 }
1187
1188 /* LCOV_EXCL_START */
1189 static gboolean __finish_event_cb(gpointer user_data)
1190 {
1191         if (user_data == NULL)
1192                 return FALSE;
1193
1194         widget_context_s *wc = (widget_context_s *)user_data;
1195
1196         switch (wc->state) {
1197         case WC_READY:
1198                 __instance_resume(wc->provider, wc->id, UPDATE_LOCAL);
1199         case WC_RUNNING:
1200                 __instance_pause(wc->provider, wc->id, UPDATE_LOCAL);
1201         case WC_PAUSED:
1202                 __instance_destroy(wc->provider, wc->id,
1203                                 WIDGET_DESTROY_TYPE_TEMPORARY, UPDATE_ALL);
1204                 break;
1205         default:
1206                 break;
1207         }
1208
1209         return FALSE;
1210 }
1211 /* LCOV_EXCL_STOP */
1212
1213 EXPORT_API int widget_app_terminate_context(widget_context_h context)
1214 {
1215         if (!_is_widget_feature_enabled()) {
1216                 _E("not supported"); /* LCOV_EXCL_LINE */
1217                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1218         }
1219
1220         if (context == NULL)
1221                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1222                                 __FUNCTION__, NULL);
1223
1224         g_idle_add(__finish_event_cb, context);
1225         return WIDGET_ERROR_NONE;
1226 }
1227
1228 EXPORT_API int widget_app_foreach_context(widget_context_cb cb, void *data)
1229 {
1230         GList *contexts = _widget_app_get_contexts();
1231         GList *list;
1232         widget_context_s *wc;
1233
1234         if (!_is_widget_feature_enabled()) {
1235                 _E("not supported"); /* LCOV_EXCL_LINE */
1236                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1237         }
1238
1239         if (!cb)
1240                 return WIDGET_ERROR_INVALID_PARAMETER;
1241
1242         list = g_list_first(contexts);
1243
1244         while (list) {
1245                 wc = (widget_context_s *)list->data;
1246                 if (wc) {
1247                         if (!cb(wc, data))
1248                                 break;
1249                 }
1250                 list = list->next;
1251         }
1252
1253         return WIDGET_ERROR_NONE;
1254 }
1255
1256 EXPORT_API int widget_app_add_event_handler(app_event_handler_h *event_handler,
1257                                         app_event_type_e event_type, app_event_cb callback,
1258                                         void *user_data)
1259 {
1260         int r;
1261         bool feature;
1262
1263         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1264         if (r < 0)
1265                 return WIDGET_ERROR_FAULT;
1266
1267         if (!feature)
1268                 return WIDGET_ERROR_NOT_SUPPORTED;
1269
1270         app_event_handler_h handler;
1271
1272         if (event_handler == NULL || callback == NULL)
1273                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1274
1275         if (event_type < APP_EVENT_LOW_MEMORY
1276             || event_type > APP_EVENT_REGION_FORMAT_CHANGED)
1277                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1278
1279         if (event_type == APP_EVENT_DEVICE_ORIENTATION_CHANGED)
1280                 return widget_app_error(WIDGET_ERROR_NOT_SUPPORTED, __FUNCTION__, NULL);
1281
1282         GList *iter = g_list_first(handler_list[event_type]);
1283
1284         while (iter) {
1285                 handler = (app_event_handler_h) iter->data;
1286
1287                 if (handler->cb == callback)
1288                         return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1289
1290                 iter = g_list_next(iter);
1291         }
1292
1293         handler = calloc(1, sizeof(struct app_event_handler));
1294         if (!handler)
1295                 return widget_app_error(WIDGET_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL); /* LCOV_EXCL_LINE */
1296
1297         if (g_list_length(handler_list[event_type]) == 0)
1298                 __register_event(event_type);
1299
1300         handler->type = event_type;
1301         handler->cb = callback;
1302         handler->data = user_data;
1303         handler_list[event_type] = g_list_append(handler_list[event_type], handler);
1304
1305         *event_handler = handler;
1306
1307         return WIDGET_ERROR_NONE;
1308 }
1309
1310 EXPORT_API int widget_app_remove_event_handler(app_event_handler_h
1311                                                 event_handler)
1312 {
1313         int r;
1314         bool feature;
1315
1316         r = system_info_get_platform_bool(FEATURE_SHELL_APPWIDGET, &feature);
1317         if (r < 0)
1318                 return WIDGET_ERROR_FAULT;
1319
1320         if (!feature)
1321                 return WIDGET_ERROR_NOT_SUPPORTED;
1322
1323         app_event_type_e type;
1324
1325         if (event_handler == NULL)
1326                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1327
1328         type = event_handler->type;
1329         if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED)
1330                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
1331
1332         handler_list[type] = g_list_remove(handler_list[type], event_handler);
1333         free(event_handler);
1334
1335         if (g_list_length(handler_list[type]) == 0)
1336                 __unregister_event(type);
1337
1338         return WIDGET_ERROR_NONE;
1339 }
1340
1341 EXPORT_API const char *widget_app_get_id(widget_context_h context)
1342 {
1343         if (!_is_widget_feature_enabled()) {
1344                 _E("not supported"); /* LCOV_EXCL_LINE */
1345                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
1346                 return NULL; /* LCOV_EXCL_LINE */
1347         }
1348
1349         if (!context) {
1350                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1351                 return NULL;
1352         }
1353
1354         set_last_result(WIDGET_ERROR_NONE);
1355         return context->id;
1356 }
1357
1358 static void _win_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
1359 {
1360        /* Remove data used in accessibility */
1361         char *plug_id;
1362         plug_id = evas_object_data_del(obj, "___PLUGID");
1363         free(plug_id);
1364 }
1365
1366 EXPORT_API int widget_app_get_elm_win(widget_context_h context,
1367                                         Evas_Object **win)
1368 {
1369         widget_context_s *cxt = (widget_context_s *)context;
1370         Evas_Object *ret_win;
1371         Ecore_Wl_Window *wl_win;
1372         struct wl_surface *surface;
1373         char buffer[256];
1374         int rots[3] = {0};
1375
1376         if (!_is_widget_feature_enabled()) {
1377                 _E("not supported"); /* LCOV_EXCL_LINE */
1378                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1379         }
1380
1381         if (context == NULL || win == NULL)
1382                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1383                                 __FUNCTION__, NULL);
1384
1385         ret_win = elm_win_add(NULL, cxt->id, ELM_WIN_BASIC);
1386         if (ret_win == NULL) {
1387                 _E("failed to create window"); /* LCOV_EXCL_LINE */
1388                 goto fault; /* LCOV_EXCL_LINE */
1389         }
1390
1391         elm_win_wm_rotation_preferred_rotation_set(ret_win, -1);
1392         elm_win_wm_rotation_available_rotations_set(ret_win, rots, 1);
1393
1394         wl_win = elm_win_wl_window_get(ret_win);
1395         if (wl_win == NULL) {
1396                 _E("failed to get wayland window"); /* LCOV_EXCL_LINE */
1397                 goto fault;
1398         }
1399
1400         surface = ecore_wl_window_surface_get(wl_win);
1401         if (surface == NULL) {
1402                 _E("failed to get surface"); /* LCOV_EXCL_LINE */
1403                 goto fault; /* LCOV_EXCL_LINE */
1404         }
1405         screen_connector_provider_remote_enable(cxt->id, surface);
1406
1407         ecore_wl_window_class_name_set(wl_win, cxt->id);
1408         elm_win_aux_hint_add(ret_win, "wm.policy.win.user.geometry", "1");
1409
1410         *win = ret_win;
1411         cxt->win = ret_win;
1412         cxt->win_id = ecore_wl_window_id_get(wl_win);
1413
1414         /* Set data to use in accessibility */
1415         snprintf(buffer, sizeof(buffer), "%s:%d", cxt->id, getpid());
1416         evas_object_data_set(ret_win, "___PLUGID", strdup(buffer));
1417         evas_object_event_callback_add(ret_win, EVAS_CALLBACK_DEL, _win_del_cb, NULL);
1418
1419         _D("window created: %d", cxt->win_id);
1420
1421         return WIDGET_ERROR_NONE;
1422
1423 fault:
1424         if (ret_win)    /* LCOV_EXCL_LINE */
1425                 evas_object_del(ret_win); /* LCOV_EXCL_LINE */
1426
1427         return WIDGET_ERROR_FAULT; /* LCOV_EXCL_LINE */
1428
1429 }
1430
1431 widget_class_h _widget_class_create(widget_class_s *prev, const char *class_id,
1432                 widget_instance_lifecycle_callback_s callback, void *user_data)
1433 {
1434         widget_class_s *wc;
1435
1436         if (!_is_widget_feature_enabled()) {
1437                 _E("not supported"); /* LCOV_EXCL_LINE */
1438                 set_last_result(WIDGET_ERROR_NOT_SUPPORTED); /* LCOV_EXCL_LINE */
1439                 return NULL;
1440         }
1441
1442         if (class_id == NULL) {
1443                 set_last_result(WIDGET_ERROR_INVALID_PARAMETER);
1444                 return NULL;
1445         }
1446
1447         wc = (widget_class_s *)calloc(1, sizeof(widget_class_s));
1448         if (wc == NULL) {
1449                 _E("failed to calloc : %s", __FUNCTION__); /* LCOV_EXCL_LINE */
1450                 set_last_result(WIDGET_ERROR_OUT_OF_MEMORY); /* LCOV_EXCL_LINE */
1451                 return NULL; /* LCOV_EXCL_LINE */
1452         }
1453
1454         wc->classid = strdup(class_id);
1455         wc->user_data = user_data;
1456         wc->ops = callback;
1457         wc->next = prev;
1458         wc->prev = NULL;
1459
1460         set_last_result(WIDGET_ERROR_NONE);
1461
1462         if (prev)
1463                 prev->prev = wc;
1464
1465         return wc;
1466 }
1467
1468 EXPORT_API widget_class_h widget_app_class_add(widget_class_h widget_class,
1469                 const char *class_id,
1470                 widget_instance_lifecycle_callback_s callback, void *user_data)
1471 {
1472         return _widget_class_create(widget_class, class_id, callback,
1473                         user_data);
1474 }
1475
1476 EXPORT_API widget_class_h widget_app_class_create(
1477                 widget_instance_lifecycle_callback_s callback, void *user_data)
1478 {
1479         return _widget_class_create(class_provider, appid, callback, user_data);
1480 }
1481
1482 EXPORT_API int widget_app_context_set_tag(widget_context_h context, void *tag)
1483 {
1484         if (!_is_widget_feature_enabled()) {
1485                 _E("not supported"); /* LCOV_EXCL_LINE */
1486                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1487         }
1488
1489         if (context == NULL)
1490                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1491                                 __FUNCTION__, NULL);
1492
1493         context->tag = tag;
1494
1495         return WIDGET_ERROR_NONE;
1496 }
1497
1498 EXPORT_API int widget_app_context_get_tag(widget_context_h context, void **tag)
1499 {
1500         if (!_is_widget_feature_enabled()) {
1501                 _E("not supported"); /* LCOV_EXCL_LINE */
1502                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1503         }
1504
1505         if (context == NULL || tag == NULL)
1506                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1507                                 __FUNCTION__, NULL);
1508
1509         *tag = context->tag;
1510
1511         return WIDGET_ERROR_NONE;
1512 }
1513
1514 EXPORT_API int widget_app_context_set_content_info(widget_context_h context,
1515                 bundle *content_info)
1516 {
1517         const char *class_id = NULL;
1518         int ret = 0;
1519         bundle_raw *raw = NULL;
1520         int len;
1521
1522         if (!_is_widget_feature_enabled()) {
1523                 _E("not supported"); /* LCOV_EXCL_LINE */
1524                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1525         }
1526
1527         if (context == NULL || content_info == NULL)
1528                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1529                                 __FUNCTION__, NULL);
1530
1531         if (context->provider == NULL)
1532                 return widget_app_error(WIDGET_ERROR_INVALID_PARAMETER,
1533                                 __FUNCTION__, NULL);
1534
1535         class_id = context->provider->classid;
1536         if (class_id == NULL)
1537                 return widget_app_error(WIDGET_ERROR_FAULT, __FUNCTION__, NULL);
1538
1539         ret = __send_update_status(class_id, context->id,
1540                         WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
1541
1542         if (context->content)
1543                 free(context->content);
1544
1545         bundle_encode(content_info, &raw, &len);
1546         if (raw)
1547                 context->content = strdup((const char *)raw);
1548         else
1549                 context->content = NULL;
1550
1551         free(raw);
1552         if (ret < 0) {
1553                 /* LCOV_EXCL_START */
1554                 _E("failed to send content info: %s of %s (%d)", context->id,
1555                                 class_id, ret);
1556                 return widget_app_error(WIDGET_ERROR_IO_ERROR, __FUNCTION__,
1557                                 NULL);
1558                 /* LCOV_EXCL_STOP */
1559         }
1560
1561         return WIDGET_ERROR_NONE;
1562 }
1563
1564 EXPORT_API int widget_app_context_set_title(widget_context_h context,
1565                 const char *title)
1566 {
1567         if (!_is_widget_feature_enabled()) {
1568                 _E("not supported"); /* LCOV_EXCL_LINE */
1569                 return WIDGET_ERROR_NOT_SUPPORTED; /* LCOV_EXCL_LINE */
1570         }
1571
1572         if (!context || !title)
1573                 return WIDGET_ERROR_INVALID_PARAMETER;
1574
1575         if (context->win)
1576                 elm_win_title_set(context->win, title);
1577
1578         return WIDGET_ERROR_NONE;
1579 }