Update the provider state.
[apps/native/widget/widget-provider.git] / widget_provider_app / src / client.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <strings.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include <widget_errno.h>
26 #include <widget_service.h>
27 #include <widget_conf.h>
28 #include <widget_abi.h>
29 #include <widget_util.h>
30
31 #include <app.h>
32 #include <dlog.h>
33 #include <pkgmgr-info.h>
34
35 #include <Ecore.h>
36 #include <Eina.h>
37
38 #include <packet.h>
39 #include <com-core_packet.h>
40
41 #include "widget_provider.h"
42 #include "widget_provider_buffer.h"
43 #include "debug.h"
44 #include "widget_provider_app.h"
45 #include "widget_provider_app_internal.h"
46 #include "client.h"
47 #include "util.h"
48 #include "connection.h"
49
50 #define PKGMGR_COMPONENT_TYPE_WATCH_APP "watchapp"
51 #define BUFFER_MAX 256
52
53 int errno;
54
55 enum state {
56         STATE_UNKNOWN = 0,
57         STATE_RESUMED = 1,
58         STATE_PAUSED = 2
59 };
60
61 struct item {
62         char *id;
63         void *update_timer;
64         struct widget_provider_event_callback *table;
65         enum state state;
66         void *data;
67         Eina_List *handle_list;
68 };
69
70 struct internal_item {
71         char *id;
72         void *data;
73 };
74
75 static struct info {
76         int secured;
77         char *abi;
78         char *name;
79         char *hw_acceleration;
80         Ecore_Timer *ping_timer;
81         Eina_List *inst_list;
82         enum state state;
83         int initialized;
84         Eina_List *internal_item_list;
85         Eina_List *widget_pre_callback_list[WIDGET_PRE_CALLBACK_COUNT];
86 } s_info = {
87         .secured = 0,
88         .abi = NULL,
89         .name = NULL,
90         .hw_acceleration = NULL,
91         .ping_timer = NULL,
92         .inst_list = NULL,
93         .state = STATE_UNKNOWN,
94         .initialized = 0,
95         .internal_item_list = NULL,
96         .widget_pre_callback_list = { NULL, },
97 };
98
99 struct pre_callback_item {
100         widget_pre_callback_t cb;
101         void *data;
102 };
103
104 static void invoke_pre_callback(widget_pre_callback_e type, const char *id)
105 {
106         Eina_List *l;
107         Eina_List *n;
108         struct pre_callback_item *item;
109
110         EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
111                 item->cb(id, item->data);
112         }
113 }
114
115 static inline char *package_get_pkgid(const char *appid)
116 {
117         int ret;
118         pkgmgrinfo_appinfo_h handle;
119         char *new_appid = NULL;
120         char *pkgid = NULL;
121
122         ret = pkgmgrinfo_appinfo_get_appinfo(appid, &handle);
123         if (ret != PMINFO_R_OK) {
124                 ErrPrint("Failed to get appinfo\n");
125                 return NULL;
126         }
127
128         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &new_appid);
129         if (ret != PMINFO_R_OK) {
130                 pkgmgrinfo_appinfo_destroy_appinfo(handle);
131                 ErrPrint("Failed to get pkgname for (%s)\n", appid);
132                 return NULL;
133         }
134
135         if (new_appid && new_appid[0] != '\0') {
136                 pkgid = strdup(new_appid);
137                 if (!pkgid) {
138                         ErrPrint("strdup: %s\n", strerror(errno));
139                 }
140         }
141         pkgmgrinfo_appinfo_destroy_appinfo(handle);
142
143         return pkgid;
144 }
145
146 char *widget_pkgname(void)
147 {
148         widget_list_h list_handle;
149         const char *abi_pkgname = NULL;
150         char *pkgid;
151         char *converted_provider_pkgname = NULL;
152         int verified;
153         char *widget_id;
154
155         pkgid = package_get_pkgid(provider_pkgname());
156         list_handle = widget_service_create_widget_list(pkgid, NULL);
157         abi_pkgname = s_info.abi ? widget_abi_get_pkgname_by_abi(s_info.abi) : NULL;
158         DbgFree(pkgid);
159         if (!abi_pkgname) {
160                 widget_service_destroy_widget_list(list_handle);
161                 ErrPrint("Failed to get pkgname[%s]", s_info.abi);
162                 return NULL;
163         }
164
165         verified = 0;
166         widget_id = NULL;
167         while (widget_service_get_item_from_widget_list(list_handle, NULL, &widget_id, NULL) == WIDGET_ERROR_NONE) {
168                 if (!widget_id) {
169                         ErrPrint("Invalid widget_id\n");
170                         continue;
171                 }
172
173                 // tmp == /APPID/.provider <<- PROVIDER UI-APP
174                 // widget_id == org.tizen.watch-hello <<-- WIDGET ID
175                 // provider_pkgname == org.tizen.watch-hello.provider
176                 converted_provider_pkgname = widget_util_replace_string(abi_pkgname, WIDGET_CONF_REPLACE_TAG_APPID, widget_id);
177                 if (!converted_provider_pkgname) {
178                         DbgFree(widget_id);
179                         widget_id = NULL;
180                         continue;
181                 }
182
183                 /* Verify the Package Name */
184                 verified = !strcmp(converted_provider_pkgname, provider_pkgname());
185                 DbgFree(converted_provider_pkgname);
186
187                 if (verified) {
188                         break;
189                 }
190
191                 DbgFree(widget_id);
192                 widget_id = NULL;
193         }
194
195         widget_service_destroy_widget_list(list_handle);
196         return widget_id;
197 }
198
199 static Eina_Bool periodic_updator(void *data)
200 {
201         struct item *item = data;
202
203         if (item->table->update) {
204                 int ret;
205                 ret = item->table->update(item->id, NULL, 0, item->table->data);
206                 if (ret < 0) {
207                         ErrPrint("Provider update: [%s] returns 0x%X\n", item->id, ret);
208                 }
209         }
210
211         return ECORE_CALLBACK_RENEW;
212 }
213
214 static struct method s_table[] = {
215         {
216                 .cmd = NULL,
217                 .handler = NULL,
218         },
219 };
220
221 static struct internal_item *internal_item_create(const char *uri)
222 {
223         struct internal_item *item;
224
225         item = malloc(sizeof(*item));
226         if (!item) {
227                 ErrPrint("Heap: %s\n", strerror(errno));
228                 return NULL;
229         }
230
231         item->id = strdup(uri);
232         if (!item->id) {
233                 ErrPrint("Heap: %s\n", strerror(errno));
234                 free(item);
235                 return NULL;
236         }
237
238         s_info.internal_item_list = eina_list_append(s_info.internal_item_list, item);
239
240         return item;
241 }
242
243 static void internal_item_destroy(struct internal_item *item)
244 {
245         s_info.internal_item_list = eina_list_remove(s_info.internal_item_list, item);
246
247         free(item->id);
248         free(item);
249 }
250
251 static struct internal_item *internal_item_find(const char *uri)
252 {
253         Eina_List *l;
254         struct internal_item *item;
255
256         EINA_LIST_FOREACH(s_info.internal_item_list, l, item) {
257                 if (!strcmp(item->id, uri)) {
258                         return item;
259                 }
260         }
261
262         return NULL;
263 }
264
265 static struct item *instance_create(const char *id, double period, struct widget_provider_event_callback *table, const char *direct_addr)
266 {
267         struct item *item;
268
269         item = calloc(1, sizeof(*item));
270         if (!item) {
271                 ErrPrint("Heap: %s\n", strerror(errno));
272                 return NULL;
273         }
274
275         item->id = strdup(id);
276         if (!item->id) {
277                 ErrPrint("Heap: %s\n", strerror(errno));
278                 free(item);
279                 return NULL;
280         }
281
282         /*
283          * If the "secured" flag is toggled,
284          * The master will send the update event to this provider app.
285          */
286         if (!s_info.secured && period > 0.0f) {
287                 item->update_timer = util_timer_add(period, periodic_updator, item);
288                 if (!item->update_timer) {
289                         ErrPrint("Failed to create a timer\n");
290                         free(item->id);
291                         free(item);
292                         return NULL;
293                 }
294         }
295
296         item->table = table;
297         if (direct_addr) {
298                 struct connection *conn_handle;
299
300                 conn_handle = connection_find_by_addr(direct_addr);
301                 if (!conn_handle) {
302                         conn_handle = connection_create(direct_addr, (void *)s_table);
303                         if (!conn_handle) {
304                                 ErrPrint("Failed to create a new connection\n");
305                         } else {
306                                 item->handle_list = eina_list_append(item->handle_list, conn_handle);
307                         }
308                 } else {
309                         item->handle_list = eina_list_append(item->handle_list, conn_handle);
310                         (void)connection_ref(conn_handle);
311                 }
312         }
313
314         item->state = STATE_UNKNOWN;
315         s_info.inst_list = eina_list_append(s_info.inst_list, item);
316
317         return item;
318 }
319
320 static void instance_destroy(struct item *item)
321 {
322         struct connection *conn_handle;
323         s_info.inst_list = eina_list_remove(s_info.inst_list, item);
324         if (item->update_timer) {
325                 util_timer_del(item->update_timer);
326         }
327         free(item->id);
328         EINA_LIST_FREE(item->handle_list, conn_handle) {
329                 (void)connection_unref(conn_handle);
330         }
331         free(item);
332 }
333
334 static struct item *instance_find(const char *id)
335 {
336         Eina_List *l;
337         struct item *item;
338
339         EINA_LIST_FOREACH(s_info.inst_list, l, item) {
340                 if (!strcmp(item->id, id)) {
341                         return item;
342                 }
343         }
344
345         return NULL;
346 }
347
348 static int method_new(struct widget_event_arg *arg, int *width, int *height, double *priority, void *data)
349 {
350         struct widget_provider_event_callback *table = data;
351         struct item *inst;
352         int ret;
353
354         DbgPrint("Create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], skip[%d], abi[%s], size: %dx%d\n",
355                         arg->pkgname, arg->id,
356                         arg->info.widget_create.content,
357                         arg->info.widget_create.timeout,
358                         arg->info.widget_create.has_script,
359                         arg->info.widget_create.period,
360                         arg->info.widget_create.cluster, arg->info.widget_create.category,
361                         arg->info.widget_create.skip_need_to_create,
362                         arg->info.widget_create.abi,
363                         arg->info.widget_create.width,
364                         arg->info.widget_create.height);
365
366         invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
367
368         if (!table->create) {
369                 ErrPrint("Function is not implemented\n");
370                 return WIDGET_ERROR_NOT_SUPPORTED;
371         }
372
373         inst = instance_create(arg->id, arg->info.widget_create.period, table, arg->info.widget_create.direct_addr);
374         if (!inst) {
375                 return WIDGET_ERROR_FAULT;
376         }
377
378         ret = table->create(widget_util_uri_to_path(arg->id), arg->info.widget_create.content, arg->info.widget_create.width, arg->info.widget_create.height, table->data);
379         if (ret != WIDGET_ERROR_NONE) {
380                 ErrPrint("Failed to create an instance\n");
381                 instance_destroy(inst);
382         } else {
383                 struct widget_buffer *buffer;
384
385                 buffer = widget_provider_buffer_find_buffer(WIDGET_TYPE_WIDGET, arg->pkgname, arg->id);
386                 if (buffer) {
387                         int bps;
388                         (void)widget_provider_buffer_get_size(buffer, width, height, &bps);
389                 }
390         }
391
392         return ret;
393 }
394
395 static int method_renew(struct widget_event_arg *arg, void *data)
396 {
397         struct widget_provider_event_callback *table = data;
398         struct item *inst;
399         int ret;
400
401         DbgPrint("Re-create: pkgname[%s], id[%s], content[%s], timeout[%d], has_script[%d], period[%lf], cluster[%s], category[%s], abi[%s], size: %dx%d\n",
402                         arg->pkgname, arg->id,
403                         arg->info.widget_recreate.content,
404                         arg->info.widget_recreate.timeout,
405                         arg->info.widget_recreate.has_script,
406                         arg->info.widget_recreate.period,
407                         arg->info.widget_recreate.cluster,
408                         arg->info.widget_recreate.category,
409                         arg->info.widget_recreate.abi,
410                         arg->info.widget_recreate.width,
411                         arg->info.widget_recreate.height);
412
413         invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
414
415         if (!table->create) {
416                 ErrPrint("Function is not implemented\n");
417                 return WIDGET_ERROR_NOT_SUPPORTED;
418         }
419
420         inst = instance_create(arg->id, arg->info.widget_recreate.period, table, arg->info.widget_recreate.direct_addr);
421         if (!inst) {
422                 return WIDGET_ERROR_FAULT;
423         }
424
425         ret = table->create(widget_util_uri_to_path(arg->id), arg->info.widget_recreate.content, arg->info.widget_recreate.width, arg->info.widget_recreate.height, table->data);
426         if (ret < 0) {
427                 instance_destroy(inst);
428         }
429
430         return ret;
431 }
432
433 static int method_delete(struct widget_event_arg *arg, void *data)
434 {
435         struct widget_provider_event_callback *table = data;
436         struct item *inst;
437         int ret;
438
439         DbgPrint("pkgname[%s] id[%s]\n", arg->pkgname, arg->id);
440
441         invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, arg->id);
442
443         if (!table->destroy) {
444                 ErrPrint("Function is not implemented\n");
445                 return WIDGET_ERROR_NOT_SUPPORTED;
446         }
447
448         inst = instance_find(arg->id);
449         if (!inst) {
450                 return WIDGET_ERROR_INVALID_PARAMETER;
451         }
452
453         ret = table->destroy(widget_util_uri_to_path(arg->id), arg->info.widget_destroy.type, table->data);
454         instance_destroy(inst);
455         return ret;
456 }
457
458 static int method_content_event(struct widget_event_arg *arg, void *data)
459 {
460         struct widget_provider_event_callback *table = data;
461         int ret;
462
463         if (!table->text_signal) {
464                 ErrPrint("Function is not implemented\n");
465                 return WIDGET_ERROR_NOT_SUPPORTED;
466         }
467
468         ret = table->text_signal(widget_util_uri_to_path(arg->id),
469                         arg->info.content_event.signal_name, arg->info.content_event.source,
470                         &arg->info.content_event.info,
471                         table->data);
472
473         return ret;
474 }
475
476 static int method_clicked(struct widget_event_arg *arg, void *data)
477 {
478         int ret = WIDGET_ERROR_NONE;
479 #ifdef WIDGET_FEATURE_HANDLE_CLICKED_EVENT
480         struct widget_provider_event_callback *table = data;
481
482         DbgPrint("pkgname[%s] id[%s] event[%s] timestamp[%lf] x[%lf] y[%lf]\n",
483                         arg->pkgname, arg->id,
484                         arg->info.clicked.event, arg->info.clicked.timestamp,
485                         arg->info.clicked.x, arg->info.clicked.y);
486
487         if (!table->clicked) {
488                 ErrPrint("Function is not implemented\n");
489                 return WIDGET_ERROR_NOT_SUPPORTED;
490         }
491
492         ret = table->clicked(widget_util_uri_to_path(arg->id), arg->info.clicked.event, arg->info.clicked.x, arg->info.clicked.y, arg->info.clicked.timestamp, table->data);
493 #endif /* WIDGET_FEATURE_HANDLE_CLICKED_EVENT */
494
495         return ret;
496 }
497
498 static int method_text_signal(struct widget_event_arg *arg, void *data)
499 {
500         struct widget_provider_event_callback *table = data;
501         int ret;
502
503         if (!table->text_signal) {
504                 ErrPrint("Function is not implemented\n");
505                 return WIDGET_ERROR_NOT_SUPPORTED;
506         }
507
508         ret = table->text_signal(widget_util_uri_to_path(arg->id),
509                         arg->info.text_signal.signal_name, arg->info.text_signal.source,
510                         &arg->info.text_signal.info, table->data);
511
512         return ret;
513 }
514
515 static int method_resize(struct widget_event_arg *arg, void *data)
516 {
517         struct widget_provider_event_callback *table = data;
518         int ret;
519
520         invoke_pre_callback(WIDGET_PRE_RESIZE_CALLBACK, arg->id);
521
522         if (!table->resize) {
523                 ErrPrint("Function is not implemented\n");
524                 return WIDGET_ERROR_NOT_SUPPORTED;
525         }
526
527         DbgPrint("pkgname[%s] id[%s] w[%d] h[%d]\n", arg->pkgname, arg->id, arg->info.resize.w, arg->info.resize.h);
528         ret = table->resize(widget_util_uri_to_path(arg->id), arg->info.resize.w, arg->info.resize.h, table->data);
529         return ret;
530 }
531
532 static int method_set_period(struct widget_event_arg *arg, void *data)
533 {
534         struct item *inst;
535
536         DbgPrint("pkgname[%s] id[%s] period[%lf]\n", arg->pkgname, arg->id, arg->info.set_period.period);
537         inst = instance_find(arg->id);
538         if (!inst) {
539                 return WIDGET_ERROR_INVALID_PARAMETER;
540         }
541
542         if (inst->update_timer) {
543                 util_timer_interval_set(inst->update_timer, arg->info.set_period.period);
544         }
545
546         return WIDGET_ERROR_NONE;
547 }
548
549 static int method_change_group(struct widget_event_arg *arg, void *data)
550 {
551         return WIDGET_ERROR_NOT_SUPPORTED;
552 }
553
554 static int method_pinup(struct widget_event_arg *arg, void *data)
555 {
556         return WIDGET_ERROR_NOT_SUPPORTED;
557 }
558
559 static int method_update_content(struct widget_event_arg *arg, void *data)
560 {
561         struct widget_provider_event_callback *table = data;
562         int ret;
563
564         if (!table->update) {
565                 return WIDGET_ERROR_NOT_SUPPORTED;
566         }
567
568         ret = table->update(widget_util_uri_to_path(arg->id), arg->info.update_content.content, arg->info.update_content.force, table->data);
569         return ret;
570 }
571
572 static int method_pause(struct widget_event_arg *arg, void *data)
573 {
574         struct widget_provider_event_callback *table = data;
575         Eina_List *l;
576         struct item *inst;
577
578         if (s_info.state == STATE_PAUSED) {
579                 DbgPrint("Already paused\n");
580                 return WIDGET_ERROR_NONE;
581         }
582
583         s_info.state = STATE_PAUSED;
584
585         EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
586                 if (inst->state != STATE_RESUMED) {
587                         continue;
588                 }
589
590                 if (inst->update_timer) {
591                         util_timer_freeze(inst->update_timer);
592                 }
593
594                 if (table->pause) {
595                         table->pause(widget_util_uri_to_path(inst->id), table->data);
596                 }
597         }
598
599         if (s_info.ping_timer) {
600                 ecore_timer_freeze(s_info.ping_timer);
601         }
602
603         return WIDGET_ERROR_NONE;
604 }
605
606 static int method_resume(struct widget_event_arg *arg, void *data)
607 {
608         struct widget_provider_event_callback *table = data;
609         Eina_List *l;
610         struct item *inst;
611
612         if (s_info.state == STATE_RESUMED) {
613                 DbgPrint("Already resumed\n");
614                 return WIDGET_ERROR_NONE;
615         }
616
617         s_info.state = STATE_RESUMED;
618
619         EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
620                 if (inst->state != STATE_RESUMED) {
621                         continue;
622                 }
623
624                 if (inst->update_timer) {
625                         util_timer_thaw(inst->update_timer);
626                 }
627
628                 if (table->resume) {
629                         table->resume(widget_util_uri_to_path(inst->id), table->data);
630                 }
631         }
632
633         if (s_info.ping_timer) {
634                 ecore_timer_thaw(s_info.ping_timer);
635         }
636
637         return WIDGET_ERROR_NONE;
638 }
639
640 static Eina_Bool send_ping_cb(void *data)
641 {
642         widget_provider_send_ping();
643
644         return ECORE_CALLBACK_RENEW;
645 }
646
647 static int method_disconnected(struct widget_event_arg *arg, void *data)
648 {
649         struct widget_provider_event_callback *table = data;
650         struct item *item;
651         Eina_List *l;
652         Eina_List *n;
653
654         /* arg == NULL */
655
656         if (s_info.ping_timer) {
657                 ecore_timer_del(s_info.ping_timer);
658                 s_info.ping_timer = NULL;
659         }
660
661         /**
662          * After clean up all connections to master, (why?)
663          * invoke destroy callback for every instances.
664          */
665         EINA_LIST_FOREACH_SAFE(s_info.inst_list, l, n, item) {
666                 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, item->id);
667
668                 if (table->destroy) {
669                         (void)table->destroy(widget_util_uri_to_path(item->id), WIDGET_DESTROY_TYPE_FAULT, item->table->data);
670                 }
671
672                 /**
673                  * instance_destroy will remove the "item" from this "inst_list"
674                  */
675                 instance_destroy(item);
676         }
677
678         if (table->disconnected) {
679                 table->disconnected(table->data);
680         }
681
682         client_fini();
683
684         return WIDGET_ERROR_NONE;
685 }
686
687 static int method_connected(struct widget_event_arg *arg, void *data)
688 {
689         int ret;
690         struct widget_provider_event_callback *table = data;
691
692         ret = widget_provider_send_hello();
693         if (ret == 0) {
694                 s_info.ping_timer = ecore_timer_add(WIDGET_CONF_DEFAULT_PING_TIME / 2.0f, send_ping_cb, NULL);
695                 if (!s_info.ping_timer) {
696                         ErrPrint("Failed to add a ping timer\n");
697                 }
698         }
699
700         if (table->connected) {
701                 table->connected(table->data);
702         }
703
704         return WIDGET_ERROR_NONE;
705 }
706
707 static int method_viewer_connected(struct widget_event_arg *arg, void *data)
708 {
709         struct item *item;
710
711         item = instance_find(arg->id);
712         if (!item) {
713                 return WIDGET_ERROR_INVALID_PARAMETER;
714         }
715
716         if (arg->info.viewer_connected.direct_addr && arg->info.viewer_connected.direct_addr[0]) {
717                 struct connection *handle;
718                 /**
719                  * \TODO: Create a new connection if the direct_addr is valid
720                  */
721                 handle = connection_find_by_addr(arg->info.viewer_connected.direct_addr);
722                 if (handle) {
723                         (void)connection_ref(handle);
724                 } else {
725                         handle = connection_create(arg->info.viewer_connected.direct_addr, (void *)s_table);
726                 }
727
728                 item->handle_list = eina_list_append(item->handle_list, handle);
729         } else {
730                 DbgPrint("Newly comming connection has no valid direct_addr\n");
731         }
732
733         return WIDGET_ERROR_NOT_SUPPORTED;
734 }
735
736 static int method_viewer_disconnected(struct widget_event_arg *arg, void *data)
737 {
738         struct item *item;
739
740         item = instance_find(arg->id);
741         if (!item) {
742                 return WIDGET_ERROR_INVALID_PARAMETER;
743         }
744
745         if (arg->info.viewer_disconnected.direct_addr && arg->info.viewer_disconnected.direct_addr[0]) {
746                 struct connection *handle;
747                 /**
748                  * \TODO: Create a new connection if the direct_addr is valid
749                  */
750                 handle = connection_find_by_addr(arg->info.viewer_disconnected.direct_addr);
751                 if (handle) {
752                         if (eina_list_data_find(item->handle_list, handle)) {
753                                 item->handle_list = eina_list_remove(item->handle_list, handle);
754                                 (void)connection_unref(handle);
755                         }
756                 } else {
757                         ErrPrint("There is no valid connection object: %s\n", arg->info.viewer_disconnected.direct_addr);
758                 }
759         } else {
760                 DbgPrint("Disconnected connection has no valid direct_addr\n");
761         }
762
763         return WIDGET_ERROR_NOT_SUPPORTED;
764 }
765
766 static int method_gbar_created(struct widget_event_arg *arg, void *data)
767 {
768         int ret = WIDGET_ERROR_NONE;
769 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
770         struct widget_provider_event_callback *table = data;
771
772         if (!table->gbar.create) {
773                 return WIDGET_ERROR_NOT_SUPPORTED;
774         }
775
776         ret = table->gbar.create(widget_util_uri_to_path(arg->id), arg->info.gbar_create.w, arg->info.gbar_create.h, arg->info.gbar_create.x, arg->info.gbar_create.y, table->data);
777 #else
778         ret = WIDGET_ERROR_NOT_SUPPORTED;
779 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
780         return ret;
781 }
782
783 static int method_gbar_destroyed(struct widget_event_arg *arg, void *data)
784 {
785         int ret = WIDGET_ERROR_NONE;
786 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
787         struct widget_provider_event_callback *table = data;
788
789         if (!table->gbar.destroy) {
790                 return WIDGET_ERROR_NOT_SUPPORTED;
791         }
792
793         ret = table->gbar.destroy(widget_util_uri_to_path(arg->id), arg->info.gbar_destroy.reason, table->data)
794 #else
795         ret = WIDGET_ERROR_NOT_SUPPORTED;
796 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
797         return ret;
798 }
799
800 static int method_gbar_moved(struct widget_event_arg *arg, void *data)
801 {
802         int ret = WIDGET_ERROR_NONE;
803 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
804         struct widget_provider_event_callback *table = data;
805         if (!table->gbar.resize_move) {
806                 return WIDGET_ERROR_NOT_SUPPORTED;
807         }
808
809         ret = table->gbar.resize_move(widget_util_uri_to_path(arg->id), arg->info.gbar_move.w, arg->info.gbar_move.h, arg->info.gbar_move.x, arg->info.gbar_move.y, table->data);
810 #else
811         ret = WIDGET_ERROR_NOT_SUPPORTED;
812 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
813         return ret;
814 }
815
816 static int method_widget_pause(struct widget_event_arg *arg, void *data)
817 {
818         struct widget_provider_event_callback *table = data;
819         int ret;
820         struct item *inst;
821
822         inst = instance_find(arg->id);
823         if (!inst) {
824                 return WIDGET_ERROR_INVALID_PARAMETER;
825         }
826
827         if (inst->state == STATE_PAUSED) {
828                 DbgPrint("Already paused\n");
829                 return WIDGET_ERROR_ALREADY_EXIST;
830         }
831
832         inst->state = STATE_PAUSED;
833
834         if (s_info.state != STATE_RESUMED) {
835                 return WIDGET_ERROR_NONE;
836         }
837
838         if (inst->update_timer) {
839                 util_timer_freeze(inst->update_timer);
840         }
841
842         if (!table->pause) {
843                 return WIDGET_ERROR_NOT_SUPPORTED;
844         }
845
846         ret = table->pause(widget_util_uri_to_path(arg->id), table->data);
847         return ret;
848 }
849
850 static int method_widget_resume(struct widget_event_arg *arg, void *data)
851 {
852         struct widget_provider_event_callback *table = data;
853         struct item *inst;
854         int ret;
855
856         inst = instance_find(arg->id);
857         if (!inst) {
858                 return WIDGET_ERROR_INVALID_PARAMETER;
859         }
860
861         if (inst->state == STATE_RESUMED) {
862                 return WIDGET_ERROR_ALREADY_EXIST;
863         }
864
865         inst->state = STATE_RESUMED;
866
867         if (s_info.state != STATE_RESUMED) {
868                 return WIDGET_ERROR_NONE;
869         }
870
871         if (inst->update_timer) {
872                 util_timer_thaw(inst->update_timer);
873         }
874
875         if (!table->resume) {
876                 return WIDGET_ERROR_NOT_SUPPORTED;
877         }
878
879         ret = table->resume(widget_util_uri_to_path(arg->id), table->data);
880         return ret;
881 }
882
883 static int connection_disconnected_cb(int handle, void *data)
884 {
885         struct connection *connection;
886         struct connection *conn_handle;
887         struct item *inst;
888         Eina_List *l;
889         Eina_List *k;
890         Eina_List *n;
891
892         connection = connection_find_by_fd(handle);
893         if (!connection) {
894                 return 0;
895         }
896
897         EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
898                 EINA_LIST_FOREACH_SAFE(inst->handle_list, k, n, conn_handle) {
899                         if (conn_handle == connection) {
900                                 /**
901                                  * @note
902                                  * This instance has connection to client
903                                  * but now it is lost.
904                                  * by reset "handle",
905                                  * the provider_app_send_updated function will send event to the master.
906                                  */
907                                 DbgPrint("Disconnected: %s\n", inst->id);
908
909                                 /**
910                                  * To prevent from nested callback call.
911                                  * reset handle first.
912                                  */
913                                 inst->handle_list = eina_list_remove(inst->handle_list, conn_handle);
914
915                                 (void)connection_unref(conn_handle);
916                         }
917                 }
918         }
919
920         return 0;
921 }
922
923 void client_fini(void)
924 {
925         struct internal_item *item;
926
927         if (!s_info.initialized) {
928                 LOGE("Provider is not initialized\n");
929                 return;
930         }
931
932         DbgPrint("Finalize the Provider App Connection\n");
933         s_info.initialized = 0;
934
935         widget_provider_fini();
936
937         DbgPrint("Provider is disconnected(%s)\n", s_info.abi);
938         free(s_info.name);
939         free(s_info.abi);
940         free(s_info.hw_acceleration);
941
942         widget_conf_reset();
943         widget_abi_fini();
944
945         s_info.name = NULL;
946         s_info.abi = NULL;
947         s_info.hw_acceleration = NULL;
948
949         connection_del_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb);
950
951         EINA_LIST_FREE(s_info.internal_item_list, item) {
952                 DbgPrint("Internal item[%s] destroyed\n", item->id);
953                 free(item->id);
954                 free(item);
955         }
956 }
957
958 int client_is_initialized(void)
959 {
960         return s_info.initialized;
961 }
962
963 static int method_connected_sync(struct widget_event_arg *arg, void *data)
964 {
965         int ret;
966         struct widget_provider_event_callback *table = data;
967
968         /**
969          * @note
970          *
971          * hello_sync will invoke the widget_create funcion from its inside.
972          * So we should to call the connected event callback first.
973          * We should keep callback sequence.
974          *
975          * connected -> widget_created
976          */
977
978         if (table->connected) {
979                 table->connected(table->data);
980         }
981
982         ret = widget_provider_send_hello_sync(provider_pkgname());
983
984         if (ret == 0) {
985                 s_info.ping_timer = ecore_timer_add(WIDGET_CONF_DEFAULT_PING_TIME / 2.0f, send_ping_cb, NULL);
986                 if (!s_info.ping_timer) {
987                         ErrPrint("Failed to add a ping timer\n");
988                 }
989         }
990
991         return WIDGET_ERROR_NONE;
992 }
993
994 static int is_watchapp(void)
995 {
996         int result = 0;
997         pkgmgrinfo_appinfo_h handle = NULL;
998         char *value;
999
1000         if (pkgmgrinfo_appinfo_get_appinfo(provider_pkgname(), &handle) != PMINFO_R_OK) {
1001                 ErrPrint("appid[%s] is invalid\n", provider_pkgname());
1002                 return 0;
1003         }
1004
1005         if (pkgmgrinfo_appinfo_get_component_type(handle, &value) == PMINFO_R_OK) {
1006                 if (value) {
1007                         DbgPrint("component type: %s\n", value);
1008                 }
1009
1010                 if (!strcmp(value, PKGMGR_COMPONENT_TYPE_WATCH_APP)) {
1011                         result = 1;
1012                         DbgPrint("this app is watch app");
1013                 }
1014         }
1015
1016         pkgmgrinfo_appinfo_destroy_appinfo(handle);
1017
1018         return result;
1019 }
1020
1021 int client_init_sync(struct widget_provider_event_callback *table)
1022 {
1023         int ret;
1024         char *name = NULL;
1025         char *abi = NULL;
1026         char *hw_acceleration = NULL;
1027
1028         struct widget_event_table method_table = {
1029                 .widget_create = method_new,
1030                 .widget_recreate = method_renew,
1031                 .widget_destroy = method_delete,
1032                 .resize = method_resize,
1033                 .update_content = method_update_content,
1034                 .content_event = method_content_event,
1035                 .clicked = method_clicked,
1036                 .text_signal = method_text_signal,
1037                 .set_period = method_set_period,
1038                 .change_group = method_change_group,
1039                 .pinup = method_pinup,
1040                 .pause = method_pause,
1041                 .resume = method_resume,
1042                 .widget_pause = method_widget_pause,
1043                 .widget_resume = method_widget_resume,
1044                 .disconnected = method_disconnected,
1045                 .connected = method_connected_sync,
1046                 .viewer_connected = method_viewer_connected,
1047                 .viewer_disconnected = method_viewer_disconnected,
1048
1049                 /**
1050                  * Glance Bar
1051                  */
1052                 .gbar_create = method_gbar_created,
1053                 .gbar_destroy = method_gbar_destroyed,
1054                 .gbar_move = method_gbar_moved,
1055         };
1056
1057         if (s_info.initialized == 1) {
1058                 DbgPrint("Provider App is already initialized\n");
1059                 return WIDGET_ERROR_NONE;
1060         }
1061
1062         widget_abi_init();
1063
1064         if (s_info.name && s_info.abi) {
1065                 DbgPrint("Name and ABI is assigned already\n");
1066                 widget_abi_fini();
1067                 return WIDGET_ERROR_NONE;
1068         }
1069
1070         if (!widget_conf_is_loaded()) {
1071                 widget_conf_reset();
1072                 if (widget_conf_load() < 0) {
1073                         ErrPrint("Failed to load conf\n");
1074                 }
1075         }
1076
1077         if (!is_watchapp()) {
1078                 ErrPrint("This Provider is not watch app\n");
1079                 widget_conf_reset();
1080                 widget_abi_fini();
1081                 return WIDGET_ERROR_NONE;
1082         }
1083
1084         name = malloc(BUFFER_MAX);
1085         if (!name) {
1086                 widget_conf_reset();
1087                 widget_abi_fini();
1088                 return WIDGET_ERROR_OUT_OF_MEMORY;
1089         }
1090
1091         snprintf(name, BUFFER_MAX - 1, "%d.%lf", getpid(), util_timestamp());
1092
1093         abi = strdup("app");
1094         if (!abi) {
1095                 free(name);
1096                 widget_conf_reset();
1097                 widget_abi_fini();
1098                 return WIDGET_ERROR_OUT_OF_MEMORY;
1099         }
1100
1101         hw_acceleration = strdup("use-sw");
1102         if (!hw_acceleration) {
1103                 free(name);
1104                 free(abi);
1105                 widget_conf_reset();
1106                 widget_abi_fini();
1107                 return WIDGET_ERROR_OUT_OF_MEMORY;
1108         }
1109
1110         DbgPrint("Name assigned: %s (%s)\n", name, abi);
1111         DbgPrint("Secured: %s\n", "true");
1112         DbgPrint("hw-acceleration: %s\n", hw_acceleration);
1113
1114         widget_provider_prepare_init(abi, hw_acceleration, 1);
1115         ret = widget_provider_init(util_screen_get(), name, &method_table, table, 1, 1);
1116         ErrPrint("widget_provider_init return [%d]\n", ret);
1117         if (ret < 0) {
1118                 free(hw_acceleration);
1119                 free(name);
1120                 free(abi);
1121                 widget_conf_reset();
1122                 widget_abi_fini();
1123         } else {
1124                 s_info.initialized = 1;
1125                 s_info.name = name;
1126                 s_info.abi = abi;
1127                 s_info.secured = 1;
1128                 s_info.hw_acceleration = hw_acceleration;
1129
1130                 if (connection_add_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb, NULL) < 0) {
1131                         ErrPrint("Failed to add a disconnected event callback\n");
1132                 }
1133         }
1134
1135         return WIDGET_ERROR_NONE;
1136 }
1137
1138 int client_init(app_control_h service, struct widget_provider_event_callback *table)
1139 {
1140         int ret;
1141         char *secured = NULL;
1142         char *name = NULL;
1143         char *abi = NULL;
1144         char *hw_acceleration = NULL;
1145         struct widget_event_table method_table = {
1146                 .widget_create = method_new,
1147                 .widget_recreate = method_renew,
1148                 .widget_destroy = method_delete,
1149                 .gbar_create = method_gbar_created,
1150                 .gbar_destroy = method_gbar_destroyed,
1151                 .gbar_move = method_gbar_moved,
1152                 .resize = method_resize,
1153                 .update_content = method_update_content,
1154                 .content_event = method_content_event,
1155                 .clicked = method_clicked,
1156                 .text_signal = method_text_signal,
1157                 .set_period = method_set_period,
1158                 .change_group = method_change_group,
1159                 .pinup = method_pinup,
1160                 .pause = method_pause,
1161                 .resume = method_resume,
1162                 .widget_pause = method_widget_pause,
1163                 .widget_resume = method_widget_resume,
1164                 .disconnected = method_disconnected,
1165                 .connected = method_connected,
1166                 .viewer_connected = method_viewer_connected,
1167                 .viewer_disconnected = method_viewer_disconnected,
1168         };
1169
1170         if (s_info.initialized == 1) {
1171                 DbgPrint("Provider App is already initialized\n");
1172                 return WIDGET_ERROR_NONE;
1173         }
1174
1175         widget_abi_init();
1176
1177         if (s_info.name && s_info.abi) {
1178                 DbgPrint("Name and ABI is assigned already\n");
1179                 widget_abi_fini();
1180                 return WIDGET_ERROR_NONE;
1181         }
1182
1183         if (!widget_conf_is_loaded()) {
1184                 widget_conf_reset();
1185                 if (widget_conf_load() < 0) {
1186                         ErrPrint("Failed to load conf\n");
1187                 }
1188         }
1189
1190         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_NAME, &name);
1191         if (ret != APP_CONTROL_ERROR_NONE) {
1192                 ErrPrint("Name is not valid\n");
1193                 widget_conf_reset();
1194                 widget_abi_fini();
1195                 return WIDGET_ERROR_INVALID_PARAMETER;
1196         }
1197
1198         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_SECURED, &secured);
1199         if (ret != APP_CONTROL_ERROR_NONE) {
1200                 free(name);
1201                 ErrPrint("Secured is not valid\n");
1202                 widget_conf_reset();
1203                 widget_abi_fini();
1204                 return WIDGET_ERROR_INVALID_PARAMETER;
1205         }
1206
1207         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_ABI, &abi);
1208         if (ret != APP_CONTROL_ERROR_NONE) {
1209                 free(name);
1210                 free(secured);
1211                 widget_conf_reset();
1212                 widget_abi_fini();
1213                 return WIDGET_ERROR_INVALID_PARAMETER;
1214         }
1215
1216         ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_HW_ACCELERATION, &hw_acceleration);
1217         if (ret != APP_CONTROL_ERROR_NONE) {
1218                 DbgPrint("hw-acceleration is not set\n");
1219         }
1220
1221         if (name && abi && secured) {
1222                 DbgPrint("Name assigned: %s (%s)\n", name, abi);
1223                 DbgPrint("Secured: %s\n", s_info.secured);
1224                 DbgPrint("hw-acceleration: %s\n", hw_acceleration);
1225
1226                 widget_provider_prepare_init(abi, hw_acceleration, !strcmp(secured, "true"));
1227                 ret = widget_provider_init(util_screen_get(), name, &method_table, table, 1, 1);
1228                 if (ret < 0) {
1229                         free(name);
1230                         free(abi);
1231                         widget_conf_reset();
1232                         widget_abi_fini();
1233                 } else {
1234                         s_info.initialized = 1;
1235                         s_info.name = name;
1236                         s_info.abi = abi;
1237                         s_info.secured = !strcasecmp(secured, "true");
1238                         s_info.hw_acceleration = hw_acceleration;
1239
1240                         if (connection_add_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb, NULL) < 0) {
1241                                 ErrPrint("Failed to add a disconnected event callback\n");
1242                         }
1243                 }
1244                 free(secured);
1245         } else {
1246                 free(name);
1247                 free(abi);
1248                 free(secured);
1249                 free(hw_acceleration);
1250                 widget_conf_reset();
1251                 widget_abi_fini();
1252                 ret = WIDGET_ERROR_INVALID_PARAMETER;
1253         }
1254
1255         return ret;
1256 }
1257
1258 PAPI int widget_provider_app_send_updated_event(const char *id, int idx, int x, int y, int w, int h, int for_gbar)
1259 {
1260         struct item *inst;
1261         char *uri;
1262         int ret = WIDGET_ERROR_DISABLED;
1263         char *desc_name = NULL;
1264         widget_damage_region_s region = {
1265                 .x = x,
1266                 .y = y,
1267                 .w = w,
1268                 .h = h,
1269         };
1270
1271         if (!id) {
1272                 return WIDGET_ERROR_INVALID_PARAMETER;
1273         }
1274
1275         uri = util_path_to_uri(id);
1276         if (!uri) {
1277                 return WIDGET_ERROR_OUT_OF_MEMORY;
1278         }
1279
1280         if (for_gbar) {
1281                 int len;
1282
1283                 len = strlen(id) + strlen(".desc") + 3;
1284                 desc_name = malloc(len);
1285                 if (!len) {
1286                         free(uri);
1287                         return WIDGET_ERROR_OUT_OF_MEMORY;
1288                 }
1289                 snprintf(desc_name, len, "%s.desc", id);
1290         }
1291
1292         /**
1293          * Do we have to search instance in this function?
1294          * This function is very frequently called one.
1295          * So we have to do not heavy operation in here!!!
1296          * Keep it in mind.
1297          */
1298         inst = instance_find(uri);
1299         if (inst && inst->handle_list) {
1300                 Eina_List *l;
1301                 struct connection *conn_handle;
1302
1303                 EINA_LIST_FOREACH(inst->handle_list, l, conn_handle) {
1304                         ret = widget_provider_send_direct_updated(connection_handle(conn_handle), provider_pkgname(), uri, idx, &region, for_gbar, desc_name);
1305                 }
1306         }
1307
1308         /**
1309          * by this logic,
1310          * Even if we lost direct connection to the viewer,
1311          * we will send this to the master again.
1312          */
1313         if (ret != WIDGET_ERROR_NONE) {
1314                 ret = widget_provider_send_updated(provider_pkgname(), uri, idx, &region, for_gbar, desc_name);
1315         }
1316
1317         free(desc_name);
1318         free(uri);
1319
1320         return ret;
1321 }
1322
1323 PAPI int widget_provider_app_send_buffer_updated_event(widget_buffer_h handle, int idx, int x, int y, int w, int h, int for_gbar)
1324 {
1325         struct item *inst;
1326         int ret = WIDGET_ERROR_DISABLED;
1327         char *desc_name = NULL;
1328         const char *uri;
1329         widget_damage_region_s region = {
1330                 .x = x,
1331                 .y = y,
1332                 .w = w,
1333                 .h = h,
1334         };
1335
1336         if (!handle) {
1337                 return WIDGET_ERROR_INVALID_PARAMETER;
1338         }
1339
1340         uri = widget_provider_buffer_id(handle);
1341         if (!uri) {
1342                 return WIDGET_ERROR_INVALID_PARAMETER;
1343         }
1344
1345         if (for_gbar) {
1346                 int len;
1347                 const char *id;
1348
1349                 id = widget_util_uri_to_path(uri);
1350                 if (!id) {
1351                         return WIDGET_ERROR_FAULT;
1352                 }
1353
1354                 len = strlen(id) + strlen(".desc") + 3;
1355                 desc_name = malloc(len);
1356                 if (!len) {
1357                         return WIDGET_ERROR_OUT_OF_MEMORY;
1358                 }
1359                 snprintf(desc_name, len, "%s.desc", id);
1360         }
1361
1362         /**
1363          * Do we have to search instance in this function?
1364          * This function is very frequently called one.
1365          * So we have to do not heavy operation in here!!!
1366          * Keep it in mind.
1367          */
1368         inst = instance_find(uri);
1369         if (inst && inst->handle_list) {
1370                 Eina_List *l;
1371                 struct connection *conn_handle;
1372
1373                 EINA_LIST_FOREACH(inst->handle_list, l, conn_handle) {
1374                         ret = widget_provider_send_direct_buffer_updated(connection_handle(conn_handle), handle, idx, &region, for_gbar, desc_name);
1375                 }
1376         }
1377
1378         /**
1379          * by this logic,
1380          * Even if we lost direct connection to the viewer,
1381          * we will send this to the master again.
1382          */
1383         if (ret != WIDGET_ERROR_NONE) {
1384                 ret = widget_provider_send_buffer_updated(handle, idx, &region, for_gbar, desc_name);
1385         }
1386
1387         free(desc_name);
1388
1389         return ret;
1390 }
1391
1392 PAPI int widget_provider_app_send_extra_info(const char *id, const char *content_info, const char *title)
1393 {
1394         char *uri;
1395         int ret;
1396
1397         if (!id) {
1398                 return WIDGET_ERROR_INVALID_PARAMETER;
1399         }
1400
1401         uri = util_path_to_uri(id);
1402         if (!uri) {
1403                 return WIDGET_ERROR_OUT_OF_MEMORY;
1404         }
1405
1406         ret = widget_provider_send_extra_info(provider_pkgname(), uri, 1.0f, content_info, title, NULL, NULL);
1407         free(uri);
1408
1409         return ret;
1410 }
1411
1412 PAPI int widget_provider_app_set_data(const char *id, void *data)
1413 {
1414         char *uri;
1415
1416         if (!id) {
1417                 return WIDGET_ERROR_INVALID_PARAMETER;
1418         }
1419
1420         uri = util_path_to_uri(id);
1421         if (!uri) {
1422                 return WIDGET_ERROR_OUT_OF_MEMORY;
1423         }
1424
1425         if (!strncmp(uri, SCHEMA_INTERNAL, strlen(SCHEMA_INTERNAL))) {
1426                 struct internal_item *item;
1427
1428                 item = internal_item_find(uri);
1429                 if (!item) {
1430                         if (!data) {
1431                                 free(uri);
1432                                 return WIDGET_ERROR_NOT_EXIST;
1433                         }
1434
1435                         item = internal_item_create(uri);
1436                         if (!item) {
1437                                 free(uri);
1438                                 return WIDGET_ERROR_FAULT;
1439                         }
1440                         free(uri);
1441                 } else {
1442                         free(uri);
1443                         if (!data) {
1444                                 internal_item_destroy(item);
1445                                 return WIDGET_ERROR_NONE;
1446                         }
1447                 }
1448
1449                 item->data = data;
1450         } else {
1451                 struct item *item;
1452
1453                 item = instance_find(uri);
1454                 free(uri);
1455                 if (!item) {
1456                         return WIDGET_ERROR_ALREADY_EXIST;
1457                 }
1458
1459                 item->data = data;
1460         }
1461
1462         return WIDGET_ERROR_NONE;
1463 }
1464
1465 PAPI void *widget_provider_app_get_data(const char *id)
1466 {
1467         char *uri;
1468         void *data = NULL;
1469
1470         if (!id) {
1471                 return NULL;
1472         }
1473
1474         uri = util_path_to_uri(id);
1475         if (!uri) {
1476                 return NULL;
1477         }
1478
1479         if (!strncmp(uri, SCHEMA_INTERNAL, strlen(SCHEMA_INTERNAL))) {
1480                 struct internal_item *item;
1481
1482                 item = internal_item_find(uri);
1483                 free(uri);
1484                 if (!item) {
1485                         return NULL;
1486                 }
1487                 data = item->data;
1488         } else {
1489                 struct item *item;
1490
1491                 item = instance_find(uri);
1492                 free(uri);
1493                 if (!item) {
1494                         return NULL;
1495                 }
1496                 data = item->data;
1497         }
1498
1499         return data;
1500 }
1501
1502 PAPI void *widget_provider_app_get_data_list(void)
1503 {
1504         struct item *item;
1505         Eina_List *return_list = NULL;
1506         Eina_List *l;
1507
1508         EINA_LIST_FOREACH(s_info.inst_list, l, item) {
1509                 return_list = eina_list_append(return_list, item->data);
1510         }
1511
1512         return return_list;
1513 }
1514
1515 PAPI int widget_provider_app_create_app(void)
1516 {
1517         return WIDGET_ERROR_NONE;
1518 }
1519
1520 PAPI int widget_provider_app_terminate_app(widget_destroy_type_e reason, int destroy_instances)
1521 {
1522         struct widget_provider_event_callback *table;
1523         struct item *item;
1524         Eina_List *l;
1525         Eina_List *n;
1526         int ret = 0;
1527
1528         DbgPrint("Reason: %d, %d\n", reason, destroy_instances);
1529
1530         if (!destroy_instances) {
1531                 DbgPrint("Do not destroy instances\n");
1532                 return WIDGET_ERROR_NONE;
1533         }
1534
1535         table = widget_provider_callback_data();
1536         if (!table) {
1537                 ErrPrint("Provider App is not initialized\n");
1538                 return WIDGET_ERROR_FAULT;
1539         }
1540
1541         EINA_LIST_FOREACH_SAFE(s_info.inst_list, l, n, item) {
1542                 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, item->id);
1543
1544                 if (table->destroy) {
1545                         (void)table->destroy(widget_util_uri_to_path(item->id), reason, table->data);
1546                 }
1547
1548                 instance_destroy(item);
1549                 ret++;
1550         }
1551
1552         DbgPrint("%d instances are destroyed\n", ret);
1553
1554         return ret ? WIDGET_ERROR_NONE : WIDGET_ERROR_NOT_EXIST;
1555 }
1556
1557 EAPI int widget_provider_app_add_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
1558 {
1559         struct pre_callback_item *item;
1560         Eina_List *l;
1561
1562         if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
1563                 return WIDGET_ERROR_INVALID_PARAMETER;
1564         }
1565
1566         EINA_LIST_FOREACH(s_info.widget_pre_callback_list[type], l, item) {
1567                 if (item->cb == cb && item->data == data) {
1568                         return WIDGET_ERROR_ALREADY_EXIST;
1569                 }
1570         }
1571
1572         item = malloc(sizeof(*item));
1573         if (!item) {
1574                 ErrPrint("malloc: %s\n", strerror(errno));
1575                 return WIDGET_ERROR_OUT_OF_MEMORY;
1576         }
1577
1578         item->cb = cb;
1579         item->data = data;
1580
1581         s_info.widget_pre_callback_list[type] = eina_list_append(s_info.widget_pre_callback_list[type], item);
1582         return 0;
1583 }
1584
1585 EAPI int widget_provider_app_del_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
1586 {
1587         Eina_List *l;
1588         Eina_List *n;
1589         struct pre_callback_item *item;
1590
1591         if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
1592                 ErrPrint("Invalid parameter\n");
1593                 return WIDGET_ERROR_INVALID_PARAMETER;
1594         }
1595
1596         EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
1597                 if (item->cb == cb && item->data == data) {
1598                         s_info.widget_pre_callback_list[type] = eina_list_remove_list(s_info.widget_pre_callback_list[type], l);
1599                         free(item);
1600                         return WIDGET_ERROR_NONE;
1601                 }
1602         }
1603
1604         return WIDGET_ERROR_NOT_EXIST;
1605 }
1606
1607 /**
1608  * } End of a file
1609  */