2 * Copyright 2013 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
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>
33 #include <pkgmgr-info.h>
39 #include <com-core_packet.h>
41 #include "widget_provider.h"
42 #include "widget_provider_buffer.h"
44 #include "widget_provider_app.h"
45 #include "widget_provider_app_internal.h"
48 #include "connection.h"
50 #define PKGMGR_COMPONENT_TYPE_WATCH_APP "watchapp"
51 #define BUFFER_MAX 256
64 struct widget_provider_event_callback *table;
67 Eina_List *handle_list;
70 struct internal_item {
79 char *hw_acceleration;
80 Ecore_Timer *ping_timer;
84 Eina_List *internal_item_list;
85 Eina_List *widget_pre_callback_list[WIDGET_PRE_CALLBACK_COUNT];
90 .hw_acceleration = NULL,
93 .state = STATE_UNKNOWN,
95 .internal_item_list = NULL,
96 .widget_pre_callback_list = { NULL, },
99 struct pre_callback_item {
100 widget_pre_callback_t cb;
104 static void invoke_pre_callback(widget_pre_callback_e type, const char *id)
108 struct pre_callback_item *item;
110 EINA_LIST_FOREACH_SAFE(s_info.widget_pre_callback_list[type], l, n, item) {
111 item->cb(id, item->data);
115 static inline char *package_get_pkgid(const char *appid)
118 pkgmgrinfo_appinfo_h handle;
119 char *new_appid = NULL;
122 ret = pkgmgrinfo_appinfo_get_appinfo(appid, &handle);
123 if (ret != PMINFO_R_OK) {
124 ErrPrint("Failed to get appinfo\n");
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);
135 if (new_appid && new_appid[0] != '\0') {
136 pkgid = strdup(new_appid);
138 ErrPrint("strdup: %s\n", strerror(errno));
141 pkgmgrinfo_appinfo_destroy_appinfo(handle);
146 char *widget_pkgname(void)
148 widget_list_h list_handle;
149 const char *abi_pkgname = NULL;
151 char *converted_provider_pkgname = NULL;
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;
160 widget_service_destroy_widget_list(list_handle);
161 ErrPrint("Failed to get pkgname[%s]", s_info.abi);
167 while (widget_service_get_item_from_widget_list(list_handle, NULL, &widget_id, NULL) == WIDGET_ERROR_NONE) {
169 ErrPrint("Invalid widget_id\n");
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) {
183 /* Verify the Package Name */
184 verified = !strcmp(converted_provider_pkgname, provider_pkgname());
185 DbgFree(converted_provider_pkgname);
195 widget_service_destroy_widget_list(list_handle);
199 static Eina_Bool periodic_updator(void *data)
201 struct item *item = data;
203 if (item->table->update) {
205 ret = item->table->update(item->id, NULL, 0, item->table->data);
207 ErrPrint("Provider update: [%s] returns 0x%X\n", item->id, ret);
211 return ECORE_CALLBACK_RENEW;
214 static struct method s_table[] = {
221 static struct internal_item *internal_item_create(const char *uri)
223 struct internal_item *item;
225 item = malloc(sizeof(*item));
227 ErrPrint("Heap: %s\n", strerror(errno));
231 item->id = strdup(uri);
233 ErrPrint("Heap: %s\n", strerror(errno));
238 s_info.internal_item_list = eina_list_append(s_info.internal_item_list, item);
243 static void internal_item_destroy(struct internal_item *item)
245 s_info.internal_item_list = eina_list_remove(s_info.internal_item_list, item);
251 static struct internal_item *internal_item_find(const char *uri)
254 struct internal_item *item;
256 EINA_LIST_FOREACH(s_info.internal_item_list, l, item) {
257 if (!strcmp(item->id, uri)) {
265 static struct item *instance_create(const char *id, double period, struct widget_provider_event_callback *table, const char *direct_addr)
269 item = calloc(1, sizeof(*item));
271 ErrPrint("Heap: %s\n", strerror(errno));
275 item->id = strdup(id);
277 ErrPrint("Heap: %s\n", strerror(errno));
283 * If the "secured" flag is toggled,
284 * The master will send the update event to this provider app.
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");
298 struct connection *conn_handle;
300 conn_handle = connection_find_by_addr(direct_addr);
302 conn_handle = connection_create(direct_addr, (void *)s_table);
304 ErrPrint("Failed to create a new connection\n");
306 item->handle_list = eina_list_append(item->handle_list, conn_handle);
309 item->handle_list = eina_list_append(item->handle_list, conn_handle);
310 (void)connection_ref(conn_handle);
314 item->state = STATE_UNKNOWN;
315 s_info.inst_list = eina_list_append(s_info.inst_list, item);
320 static void instance_destroy(struct item *item)
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);
328 EINA_LIST_FREE(item->handle_list, conn_handle) {
329 (void)connection_unref(conn_handle);
334 static struct item *instance_find(const char *id)
339 EINA_LIST_FOREACH(s_info.inst_list, l, item) {
340 if (!strcmp(item->id, id)) {
348 static int method_new(struct widget_event_arg *arg, int *width, int *height, double *priority, void *data)
350 struct widget_provider_event_callback *table = data;
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);
366 invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
368 if (!table->create) {
369 ErrPrint("Function is not implemented\n");
370 return WIDGET_ERROR_NOT_SUPPORTED;
373 inst = instance_create(arg->id, arg->info.widget_create.period, table, arg->info.widget_create.direct_addr);
375 return WIDGET_ERROR_FAULT;
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);
383 struct widget_buffer *buffer;
385 buffer = widget_provider_buffer_find_buffer(WIDGET_TYPE_WIDGET, arg->pkgname, arg->id);
388 (void)widget_provider_buffer_get_size(buffer, width, height, &bps);
395 static int method_renew(struct widget_event_arg *arg, void *data)
397 struct widget_provider_event_callback *table = data;
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);
413 invoke_pre_callback(WIDGET_PRE_CREATE_CALLBACK, arg->id);
415 if (!table->create) {
416 ErrPrint("Function is not implemented\n");
417 return WIDGET_ERROR_NOT_SUPPORTED;
420 inst = instance_create(arg->id, arg->info.widget_recreate.period, table, arg->info.widget_recreate.direct_addr);
422 return WIDGET_ERROR_FAULT;
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);
427 instance_destroy(inst);
433 static int method_delete(struct widget_event_arg *arg, void *data)
435 struct widget_provider_event_callback *table = data;
439 DbgPrint("pkgname[%s] id[%s]\n", arg->pkgname, arg->id);
441 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, arg->id);
443 if (!table->destroy) {
444 ErrPrint("Function is not implemented\n");
445 return WIDGET_ERROR_NOT_SUPPORTED;
448 inst = instance_find(arg->id);
450 return WIDGET_ERROR_INVALID_PARAMETER;
453 ret = table->destroy(widget_util_uri_to_path(arg->id), arg->info.widget_destroy.type, table->data);
454 instance_destroy(inst);
458 static int method_content_event(struct widget_event_arg *arg, void *data)
460 struct widget_provider_event_callback *table = data;
463 if (!table->text_signal) {
464 ErrPrint("Function is not implemented\n");
465 return WIDGET_ERROR_NOT_SUPPORTED;
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,
476 static int method_clicked(struct widget_event_arg *arg, void *data)
478 int ret = WIDGET_ERROR_NONE;
479 #ifdef WIDGET_FEATURE_HANDLE_CLICKED_EVENT
480 struct widget_provider_event_callback *table = data;
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);
487 if (!table->clicked) {
488 ErrPrint("Function is not implemented\n");
489 return WIDGET_ERROR_NOT_SUPPORTED;
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 */
498 static int method_text_signal(struct widget_event_arg *arg, void *data)
500 struct widget_provider_event_callback *table = data;
503 if (!table->text_signal) {
504 ErrPrint("Function is not implemented\n");
505 return WIDGET_ERROR_NOT_SUPPORTED;
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);
515 static int method_resize(struct widget_event_arg *arg, void *data)
517 struct widget_provider_event_callback *table = data;
520 invoke_pre_callback(WIDGET_PRE_RESIZE_CALLBACK, arg->id);
522 if (!table->resize) {
523 ErrPrint("Function is not implemented\n");
524 return WIDGET_ERROR_NOT_SUPPORTED;
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);
532 static int method_set_period(struct widget_event_arg *arg, void *data)
536 DbgPrint("pkgname[%s] id[%s] period[%lf]\n", arg->pkgname, arg->id, arg->info.set_period.period);
537 inst = instance_find(arg->id);
539 return WIDGET_ERROR_INVALID_PARAMETER;
542 if (inst->update_timer) {
543 util_timer_interval_set(inst->update_timer, arg->info.set_period.period);
546 return WIDGET_ERROR_NONE;
549 static int method_change_group(struct widget_event_arg *arg, void *data)
551 return WIDGET_ERROR_NOT_SUPPORTED;
554 static int method_pinup(struct widget_event_arg *arg, void *data)
556 return WIDGET_ERROR_NOT_SUPPORTED;
559 static int method_update_content(struct widget_event_arg *arg, void *data)
561 struct widget_provider_event_callback *table = data;
564 if (!table->update) {
565 return WIDGET_ERROR_NOT_SUPPORTED;
568 ret = table->update(widget_util_uri_to_path(arg->id), arg->info.update_content.content, arg->info.update_content.force, table->data);
572 static int method_pause(struct widget_event_arg *arg, void *data)
574 struct widget_provider_event_callback *table = data;
578 if (s_info.state == STATE_PAUSED) {
579 DbgPrint("Already paused\n");
580 return WIDGET_ERROR_NONE;
583 s_info.state = STATE_PAUSED;
585 EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
586 if (inst->state != STATE_RESUMED) {
590 if (inst->update_timer) {
591 util_timer_freeze(inst->update_timer);
595 table->pause(widget_util_uri_to_path(inst->id), table->data);
599 if (s_info.ping_timer) {
600 ecore_timer_freeze(s_info.ping_timer);
603 return WIDGET_ERROR_NONE;
606 static int method_resume(struct widget_event_arg *arg, void *data)
608 struct widget_provider_event_callback *table = data;
612 if (s_info.state == STATE_RESUMED) {
613 DbgPrint("Already resumed\n");
614 return WIDGET_ERROR_NONE;
617 s_info.state = STATE_RESUMED;
619 EINA_LIST_FOREACH(s_info.inst_list, l, inst) {
620 if (inst->state != STATE_RESUMED) {
624 if (inst->update_timer) {
625 util_timer_thaw(inst->update_timer);
629 table->resume(widget_util_uri_to_path(inst->id), table->data);
633 if (s_info.ping_timer) {
634 ecore_timer_thaw(s_info.ping_timer);
637 return WIDGET_ERROR_NONE;
640 static Eina_Bool send_ping_cb(void *data)
642 widget_provider_send_ping();
644 return ECORE_CALLBACK_RENEW;
647 static int method_disconnected(struct widget_event_arg *arg, void *data)
649 struct widget_provider_event_callback *table = data;
656 if (s_info.ping_timer) {
657 ecore_timer_del(s_info.ping_timer);
658 s_info.ping_timer = NULL;
662 * After clean up all connections to master, (why?)
663 * invoke destroy callback for every instances.
665 EINA_LIST_FOREACH_SAFE(s_info.inst_list, l, n, item) {
666 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, item->id);
668 if (table->destroy) {
669 (void)table->destroy(widget_util_uri_to_path(item->id), WIDGET_DESTROY_TYPE_FAULT, item->table->data);
673 * instance_destroy will remove the "item" from this "inst_list"
675 instance_destroy(item);
678 if (table->disconnected) {
679 table->disconnected(table->data);
684 return WIDGET_ERROR_NONE;
687 static int method_connected(struct widget_event_arg *arg, void *data)
690 struct widget_provider_event_callback *table = data;
692 ret = widget_provider_send_hello();
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");
700 if (table->connected) {
701 table->connected(table->data);
704 return WIDGET_ERROR_NONE;
707 static int method_viewer_connected(struct widget_event_arg *arg, void *data)
711 item = instance_find(arg->id);
713 return WIDGET_ERROR_INVALID_PARAMETER;
716 if (arg->info.viewer_connected.direct_addr && arg->info.viewer_connected.direct_addr[0]) {
717 struct connection *handle;
719 * \TODO: Create a new connection if the direct_addr is valid
721 handle = connection_find_by_addr(arg->info.viewer_connected.direct_addr);
723 (void)connection_ref(handle);
725 handle = connection_create(arg->info.viewer_connected.direct_addr, (void *)s_table);
728 item->handle_list = eina_list_append(item->handle_list, handle);
730 DbgPrint("Newly comming connection has no valid direct_addr\n");
733 return WIDGET_ERROR_NOT_SUPPORTED;
736 static int method_viewer_disconnected(struct widget_event_arg *arg, void *data)
740 item = instance_find(arg->id);
742 return WIDGET_ERROR_INVALID_PARAMETER;
745 if (arg->info.viewer_disconnected.direct_addr && arg->info.viewer_disconnected.direct_addr[0]) {
746 struct connection *handle;
748 * \TODO: Create a new connection if the direct_addr is valid
750 handle = connection_find_by_addr(arg->info.viewer_disconnected.direct_addr);
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);
757 ErrPrint("There is no valid connection object: %s\n", arg->info.viewer_disconnected.direct_addr);
760 DbgPrint("Disconnected connection has no valid direct_addr\n");
763 return WIDGET_ERROR_NOT_SUPPORTED;
766 static int method_gbar_created(struct widget_event_arg *arg, void *data)
768 int ret = WIDGET_ERROR_NONE;
769 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
770 struct widget_provider_event_callback *table = data;
772 if (!table->gbar.create) {
773 return WIDGET_ERROR_NOT_SUPPORTED;
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);
778 ret = WIDGET_ERROR_NOT_SUPPORTED;
779 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
783 static int method_gbar_destroyed(struct widget_event_arg *arg, void *data)
785 int ret = WIDGET_ERROR_NONE;
786 #ifdef WIDGET_FEATURE_GBAR_SUPPORTED
787 struct widget_provider_event_callback *table = data;
789 if (!table->gbar.destroy) {
790 return WIDGET_ERROR_NOT_SUPPORTED;
793 ret = table->gbar.destroy(widget_util_uri_to_path(arg->id), arg->info.gbar_destroy.reason, table->data)
795 ret = WIDGET_ERROR_NOT_SUPPORTED;
796 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
800 static int method_gbar_moved(struct widget_event_arg *arg, void *data)
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;
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);
811 ret = WIDGET_ERROR_NOT_SUPPORTED;
812 #endif /* WIDGET_FEATURE_GBAR_SUPPORTED */
816 static int method_widget_pause(struct widget_event_arg *arg, void *data)
818 struct widget_provider_event_callback *table = data;
822 inst = instance_find(arg->id);
824 return WIDGET_ERROR_INVALID_PARAMETER;
827 if (inst->state == STATE_PAUSED) {
828 DbgPrint("Already paused\n");
829 return WIDGET_ERROR_ALREADY_EXIST;
832 inst->state = STATE_PAUSED;
834 if (s_info.state != STATE_RESUMED) {
835 return WIDGET_ERROR_NONE;
838 if (inst->update_timer) {
839 util_timer_freeze(inst->update_timer);
843 return WIDGET_ERROR_NOT_SUPPORTED;
846 ret = table->pause(widget_util_uri_to_path(arg->id), table->data);
850 static int method_widget_resume(struct widget_event_arg *arg, void *data)
852 struct widget_provider_event_callback *table = data;
856 inst = instance_find(arg->id);
858 return WIDGET_ERROR_INVALID_PARAMETER;
861 if (inst->state == STATE_RESUMED) {
862 return WIDGET_ERROR_ALREADY_EXIST;
865 inst->state = STATE_RESUMED;
867 if (s_info.state != STATE_RESUMED) {
868 return WIDGET_ERROR_NONE;
871 if (inst->update_timer) {
872 util_timer_thaw(inst->update_timer);
875 if (!table->resume) {
876 return WIDGET_ERROR_NOT_SUPPORTED;
879 ret = table->resume(widget_util_uri_to_path(arg->id), table->data);
883 static int connection_disconnected_cb(int handle, void *data)
885 struct connection *connection;
886 struct connection *conn_handle;
892 connection = connection_find_by_fd(handle);
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) {
902 * This instance has connection to client
903 * but now it is lost.
905 * the provider_app_send_updated function will send event to the master.
907 DbgPrint("Disconnected: %s\n", inst->id);
910 * To prevent from nested callback call.
911 * reset handle first.
913 inst->handle_list = eina_list_remove(inst->handle_list, conn_handle);
915 (void)connection_unref(conn_handle);
923 void client_fini(void)
925 struct internal_item *item;
927 if (!s_info.initialized) {
928 LOGE("Provider is not initialized\n");
932 DbgPrint("Finalize the Provider App Connection\n");
933 s_info.initialized = 0;
935 widget_provider_fini();
937 DbgPrint("Provider is disconnected(%s)\n", s_info.abi);
940 free(s_info.hw_acceleration);
947 s_info.hw_acceleration = NULL;
949 connection_del_event_handler(CONNECTION_EVENT_TYPE_DISCONNECTED, connection_disconnected_cb);
951 EINA_LIST_FREE(s_info.internal_item_list, item) {
952 DbgPrint("Internal item[%s] destroyed\n", item->id);
958 int client_is_initialized(void)
960 return s_info.initialized;
963 static int method_connected_sync(struct widget_event_arg *arg, void *data)
966 struct widget_provider_event_callback *table = data;
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.
975 * connected -> widget_created
978 if (table->connected) {
979 table->connected(table->data);
982 ret = widget_provider_send_hello_sync(provider_pkgname());
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");
991 return WIDGET_ERROR_NONE;
994 static int is_watchapp(void)
997 pkgmgrinfo_appinfo_h handle = NULL;
1000 if (pkgmgrinfo_appinfo_get_appinfo(provider_pkgname(), &handle) != PMINFO_R_OK) {
1001 ErrPrint("appid[%s] is invalid\n", provider_pkgname());
1005 if (pkgmgrinfo_appinfo_get_component_type(handle, &value) == PMINFO_R_OK) {
1007 DbgPrint("component type: %s\n", value);
1010 if (!strcmp(value, PKGMGR_COMPONENT_TYPE_WATCH_APP)) {
1012 DbgPrint("this app is watch app");
1016 pkgmgrinfo_appinfo_destroy_appinfo(handle);
1021 int client_init_sync(struct widget_provider_event_callback *table)
1026 char *hw_acceleration = NULL;
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,
1052 .gbar_create = method_gbar_created,
1053 .gbar_destroy = method_gbar_destroyed,
1054 .gbar_move = method_gbar_moved,
1057 if (s_info.initialized == 1) {
1058 DbgPrint("Provider App is already initialized\n");
1059 return WIDGET_ERROR_NONE;
1064 if (s_info.name && s_info.abi) {
1065 DbgPrint("Name and ABI is assigned already\n");
1067 return WIDGET_ERROR_NONE;
1070 if (!widget_conf_is_loaded()) {
1071 widget_conf_reset();
1072 if (widget_conf_load() < 0) {
1073 ErrPrint("Failed to load conf\n");
1077 if (!is_watchapp()) {
1078 ErrPrint("This Provider is not watch app\n");
1079 widget_conf_reset();
1081 return WIDGET_ERROR_NONE;
1084 name = malloc(BUFFER_MAX);
1086 widget_conf_reset();
1088 return WIDGET_ERROR_OUT_OF_MEMORY;
1091 snprintf(name, BUFFER_MAX - 1, "%d.%lf", getpid(), util_timestamp());
1093 abi = strdup("app");
1096 widget_conf_reset();
1098 return WIDGET_ERROR_OUT_OF_MEMORY;
1101 hw_acceleration = strdup("use-sw");
1102 if (!hw_acceleration) {
1105 widget_conf_reset();
1107 return WIDGET_ERROR_OUT_OF_MEMORY;
1110 DbgPrint("Name assigned: %s (%s)\n", name, abi);
1111 DbgPrint("Secured: %s\n", "true");
1112 DbgPrint("hw-acceleration: %s\n", hw_acceleration);
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);
1118 free(hw_acceleration);
1121 widget_conf_reset();
1124 s_info.initialized = 1;
1128 s_info.hw_acceleration = hw_acceleration;
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");
1135 return WIDGET_ERROR_NONE;
1138 int client_init(app_control_h service, struct widget_provider_event_callback *table)
1141 char *secured = 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,
1170 if (s_info.initialized == 1) {
1171 DbgPrint("Provider App is already initialized\n");
1172 return WIDGET_ERROR_NONE;
1177 if (s_info.name && s_info.abi) {
1178 DbgPrint("Name and ABI is assigned already\n");
1180 return WIDGET_ERROR_NONE;
1183 if (!widget_conf_is_loaded()) {
1184 widget_conf_reset();
1185 if (widget_conf_load() < 0) {
1186 ErrPrint("Failed to load conf\n");
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();
1195 return WIDGET_ERROR_INVALID_PARAMETER;
1198 ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_SECURED, &secured);
1199 if (ret != APP_CONTROL_ERROR_NONE) {
1201 ErrPrint("Secured is not valid\n");
1202 widget_conf_reset();
1204 return WIDGET_ERROR_INVALID_PARAMETER;
1207 ret = app_control_get_extra_data(service, WIDGET_CONF_BUNDLE_SLAVE_ABI, &abi);
1208 if (ret != APP_CONTROL_ERROR_NONE) {
1211 widget_conf_reset();
1213 return WIDGET_ERROR_INVALID_PARAMETER;
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");
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);
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);
1231 widget_conf_reset();
1234 s_info.initialized = 1;
1237 s_info.secured = !strcasecmp(secured, "true");
1238 s_info.hw_acceleration = hw_acceleration;
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");
1249 free(hw_acceleration);
1250 widget_conf_reset();
1252 ret = WIDGET_ERROR_INVALID_PARAMETER;
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)
1262 int ret = WIDGET_ERROR_DISABLED;
1263 char *desc_name = NULL;
1264 widget_damage_region_s region = {
1272 return WIDGET_ERROR_INVALID_PARAMETER;
1275 uri = util_path_to_uri(id);
1277 return WIDGET_ERROR_OUT_OF_MEMORY;
1283 len = strlen(id) + strlen(".desc") + 3;
1284 desc_name = malloc(len);
1287 return WIDGET_ERROR_OUT_OF_MEMORY;
1289 snprintf(desc_name, len, "%s.desc", id);
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!!!
1298 inst = instance_find(uri);
1299 if (inst && inst->handle_list) {
1301 struct connection *conn_handle;
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, ®ion, for_gbar, desc_name);
1310 * Even if we lost direct connection to the viewer,
1311 * we will send this to the master again.
1313 if (ret != WIDGET_ERROR_NONE) {
1314 ret = widget_provider_send_updated(provider_pkgname(), uri, idx, ®ion, for_gbar, desc_name);
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)
1326 int ret = WIDGET_ERROR_DISABLED;
1327 char *desc_name = NULL;
1329 widget_damage_region_s region = {
1337 return WIDGET_ERROR_INVALID_PARAMETER;
1340 uri = widget_provider_buffer_id(handle);
1342 return WIDGET_ERROR_INVALID_PARAMETER;
1349 id = widget_util_uri_to_path(uri);
1351 return WIDGET_ERROR_FAULT;
1354 len = strlen(id) + strlen(".desc") + 3;
1355 desc_name = malloc(len);
1357 return WIDGET_ERROR_OUT_OF_MEMORY;
1359 snprintf(desc_name, len, "%s.desc", id);
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!!!
1368 inst = instance_find(uri);
1369 if (inst && inst->handle_list) {
1371 struct connection *conn_handle;
1373 EINA_LIST_FOREACH(inst->handle_list, l, conn_handle) {
1374 ret = widget_provider_send_direct_buffer_updated(connection_handle(conn_handle), handle, idx, ®ion, for_gbar, desc_name);
1380 * Even if we lost direct connection to the viewer,
1381 * we will send this to the master again.
1383 if (ret != WIDGET_ERROR_NONE) {
1384 ret = widget_provider_send_buffer_updated(handle, idx, ®ion, for_gbar, desc_name);
1392 PAPI int widget_provider_app_send_extra_info(const char *id, const char *content_info, const char *title)
1398 return WIDGET_ERROR_INVALID_PARAMETER;
1401 uri = util_path_to_uri(id);
1403 return WIDGET_ERROR_OUT_OF_MEMORY;
1406 ret = widget_provider_send_extra_info(provider_pkgname(), uri, 1.0f, content_info, title, NULL, NULL);
1412 PAPI int widget_provider_app_set_data(const char *id, void *data)
1417 return WIDGET_ERROR_INVALID_PARAMETER;
1420 uri = util_path_to_uri(id);
1422 return WIDGET_ERROR_OUT_OF_MEMORY;
1425 if (!strncmp(uri, SCHEMA_INTERNAL, strlen(SCHEMA_INTERNAL))) {
1426 struct internal_item *item;
1428 item = internal_item_find(uri);
1432 return WIDGET_ERROR_NOT_EXIST;
1435 item = internal_item_create(uri);
1438 return WIDGET_ERROR_FAULT;
1444 internal_item_destroy(item);
1445 return WIDGET_ERROR_NONE;
1453 item = instance_find(uri);
1456 return WIDGET_ERROR_ALREADY_EXIST;
1462 return WIDGET_ERROR_NONE;
1465 PAPI void *widget_provider_app_get_data(const char *id)
1474 uri = util_path_to_uri(id);
1479 if (!strncmp(uri, SCHEMA_INTERNAL, strlen(SCHEMA_INTERNAL))) {
1480 struct internal_item *item;
1482 item = internal_item_find(uri);
1491 item = instance_find(uri);
1502 PAPI void *widget_provider_app_get_data_list(void)
1505 Eina_List *return_list = NULL;
1508 EINA_LIST_FOREACH(s_info.inst_list, l, item) {
1509 return_list = eina_list_append(return_list, item->data);
1515 PAPI int widget_provider_app_create_app(void)
1517 return WIDGET_ERROR_NONE;
1520 PAPI int widget_provider_app_terminate_app(widget_destroy_type_e reason, int destroy_instances)
1522 struct widget_provider_event_callback *table;
1528 DbgPrint("Reason: %d, %d\n", reason, destroy_instances);
1530 if (!destroy_instances) {
1531 DbgPrint("Do not destroy instances\n");
1532 return WIDGET_ERROR_NONE;
1535 table = widget_provider_callback_data();
1537 ErrPrint("Provider App is not initialized\n");
1538 return WIDGET_ERROR_FAULT;
1541 EINA_LIST_FOREACH_SAFE(s_info.inst_list, l, n, item) {
1542 invoke_pre_callback(WIDGET_PRE_DESTROY_CALLBACK, item->id);
1544 if (table->destroy) {
1545 (void)table->destroy(widget_util_uri_to_path(item->id), reason, table->data);
1548 instance_destroy(item);
1552 DbgPrint("%d instances are destroyed\n", ret);
1554 return ret ? WIDGET_ERROR_NONE : WIDGET_ERROR_NOT_EXIST;
1557 EAPI int widget_provider_app_add_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
1559 struct pre_callback_item *item;
1562 if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
1563 return WIDGET_ERROR_INVALID_PARAMETER;
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;
1572 item = malloc(sizeof(*item));
1574 ErrPrint("malloc: %s\n", strerror(errno));
1575 return WIDGET_ERROR_OUT_OF_MEMORY;
1581 s_info.widget_pre_callback_list[type] = eina_list_append(s_info.widget_pre_callback_list[type], item);
1585 EAPI int widget_provider_app_del_pre_callback(widget_pre_callback_e type, widget_pre_callback_t cb, void *data)
1589 struct pre_callback_item *item;
1591 if (!cb || type == WIDGET_PRE_CALLBACK_COUNT) {
1592 ErrPrint("Invalid parameter\n");
1593 return WIDGET_ERROR_INVALID_PARAMETER;
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);
1600 return WIDGET_ERROR_NONE;
1604 return WIDGET_ERROR_NOT_EXIST;