Use aul key for end point data
[platform/core/appfw/appcore-widget.git] / src / base / widget_base.c
index 9df3504..efa1394 100644 (file)
@@ -20,6 +20,7 @@
 #include <bundle.h>
 #include <bundle_internal.h>
 #include <aul.h>
+#include <aul_widget.h>
 #include <dlog.h>
 #include <glib.h>
 #include <glib-object.h>
@@ -28,7 +29,7 @@
 #include <widget_errno.h>
 #include <widget_instance.h>
 #include <aul_app_com.h>
-#include <Ecore_Wayland.h>
+#include <Ecore_Wl2.h>
 #include <system_info.h>
 #include <vconf.h>
 #include <vconf-internal-keys.h>
@@ -84,8 +85,13 @@ typedef struct _widget_base_context {
 
 typedef struct _widget_base_instance_data {
        bundle *args;
+       char *id;
        char *content;
        void *tag;
+       double period;
+       guint periodic_timer;
+       bool pending_update;
+       char *pending_content;
        void *user_data;
 } widget_base_instance_data;
 
@@ -94,6 +100,39 @@ static char *__appid;
 static char *__package_id;
 static bool __fg_signal;
 static char *__viewer_endpoint;
+static bool __is_permanent;
+static void __call_update_cb(const char *class_id, const char *id, int force,
+               const char *content_raw);
+
+static gboolean __timeout_cb(gpointer user_data)
+{
+       widget_base_instance_data *data =
+                       (widget_base_instance_data *)user_data;
+       appcore_multiwindow_base_instance_h cxt;
+       const char *class_id;
+
+       cxt = appcore_multiwindow_base_instance_find(data->id);
+
+       if (!cxt) {
+               LOGE("Can't find the instance");
+               return G_SOURCE_REMOVE;
+       }
+
+       if (appcore_multiwindow_base_instance_is_resumed(cxt)) {
+               LOGD("Periodic update!");
+               class_id = appcore_multiwindow_base_instance_get_class_id(cxt);
+               __call_update_cb(class_id, data->id, 0, NULL);
+       } else {
+               data->pending_update = true;
+               if (data->periodic_timer) {
+                       LOGD("Remove timer!");
+                       g_source_remove(data->periodic_timer);
+                       data->periodic_timer = 0;
+               }
+       }
+
+       return G_SOURCE_CONTINUE;
+}
 
 static bool __is_widget_feature_enabled(void)
 {
@@ -150,7 +189,9 @@ static void __instance_drop(appcore_multiwindow_base_instance_h instance_h)
 
        data = appcore_multiwindow_base_instance_get_extra(instance_h);
        appcore_multiwindow_base_instance_drop(instance_h);
+       free(data->pending_content);
        free(data->content);
+       free(data->id);
        free(data);
        __check_empty_instance();
 }
@@ -162,16 +203,20 @@ static gint __comp_class(gconstpointer a, gconstpointer b)
        return strcmp(cls->id, b);
 }
 
-static widget_base_class __get_class(const char *class_id)
+static widget_base_class *__get_class(const char *class_id)
 {
        widget_base_class *cls;
        GList *class_node;
 
        class_node = g_list_find_custom(__context.classes, class_id,
                        __comp_class);
+       if (class_node == NULL) {
+               LOGE("empty classes");
+               return NULL;
+       }
        cls = (widget_base_class *)class_node->data;
 
-       return *cls;
+       return cls;
 }
 
 static int __send_lifecycle_event(const char *class_id, const char *instance_id,
@@ -201,12 +246,13 @@ static int __send_lifecycle_event(const char *class_id, const char *instance_id,
 }
 
 static int __send_update_status(const char *class_id, const char *instance_id,
-       int status, bundle *extra)
+       int status, int err, bundle *extra)
 {
        bundle *b;
        int lifecycle = -1;
        bundle_raw *raw = NULL;
        int len;
+       char err_str[256];
 
        b = bundle_create();
        if (!b) {
@@ -214,6 +260,11 @@ static int __send_update_status(const char *class_id, const char *instance_id,
                return -1; /* LCOV_EXCL_LINE */
        }
 
+       if (err < 0) {
+               snprintf(err_str, sizeof(err_str), "%d", err);
+               bundle_add_str(b, AUL_K_WIDGET_ERROR_CODE, err_str);
+       }
+
        bundle_add_str(b, AUL_K_WIDGET_ID, class_id);
        bundle_add_str(b, AUL_K_WIDGET_INSTANCE_ID, instance_id);
        bundle_add_byte(b, AUL_K_WIDGET_STATUS, &status, sizeof(int));
@@ -257,6 +308,11 @@ static void __control_create(const char *class_id, const char *id, bundle *b)
        widget_base_instance_data *data;
        char *content = NULL;
 
+       if (appcore_multiwindow_base_instance_find(id)) {
+               LOGE("Already exist id (%s)", id);
+               return;
+       }
+
        data = (widget_base_instance_data *)
                        calloc(1, sizeof(widget_base_instance_data));
        if (!data) {
@@ -264,6 +320,7 @@ static void __control_create(const char *class_id, const char *id, bundle *b)
                return;
        }
 
+       data->id = strdup(id);
        data->args = b;
 
        /* call stub create */
@@ -313,7 +370,7 @@ static void __control_resize(const char *class_id, const char *id, bundle *b)
        int w = 0;
        int h = 0;
        void *class_data;
-       widget_base_class cls;
+       widget_base_class *cls;
        const appcore_multiwindow_base_class *raw_cls;
 
        instance_h = appcore_multiwindow_base_instance_find(id);
@@ -327,6 +384,10 @@ static void __control_resize(const char *class_id, const char *id, bundle *b)
                return;
 
        cls = __get_class(class_id);
+       if (cls == NULL) {
+               LOGE("class not found: %s", class_id);
+               return;
+       }
        class_data = raw_cls->data;
        bundle_get_str(b, WIDGET_K_WIDTH, &w_str);
        bundle_get_str(b, WIDGET_K_HEIGHT, &h_str);
@@ -337,28 +398,26 @@ static void __control_resize(const char *class_id, const char *id, bundle *b)
        if (h_str)
                h = (int)g_ascii_strtoll(h_str, &remain, 10);
 
-       if (cls.ops.resize)
-               cls.ops.resize(instance_h, w, h, class_data);
+       if (cls->ops.resize)
+               cls->ops.resize(instance_h, w, h, class_data);
 
        LOGD("%s is resized to %dx%d", id, w, h);
        __send_update_status(class_id, id,
-               WIDGET_INSTANCE_EVENT_SIZE_CHANGED, NULL);
+               WIDGET_INSTANCE_EVENT_SIZE_CHANGED, 0, NULL);
 }
 
-static void __update_cb(const char *class_id, const char *id,
-               appcore_multiwindow_base_instance_h instance_h, void *data)
+static void __call_update_cb(const char *class_id, const char *id, int force,
+               const char *content_raw)
 {
        void *class_data;
+       widget_base_class *cls;
        const appcore_multiwindow_base_class *raw_cls;
+       appcore_multiwindow_base_instance_h instance_h;
        bundle *content = NULL;
-       char *content_raw = NULL;
-       char *force_str = NULL;
-       int force;
-       bundle *b = data;
-       widget_base_class cls;
 
-       if (!b) {
-               LOGE("bundle is NULL");
+       instance_h = appcore_multiwindow_base_instance_find(id);
+       if (!instance_h) {
+               LOGE("context not found: %s", id);
                return;
        }
 
@@ -370,44 +429,89 @@ static void __update_cb(const char *class_id, const char *id,
 
        class_data = raw_cls->data;
        cls = __get_class(class_id);
+       if (cls == NULL) {
+               LOGE("class not found: %s", class_id);
+               return;
+       }
 
-       if (!cls.ops.update) {
+       if (!cls->ops.update) {
                LOGE("update callback is NULL");
                return;
        }
 
-       bundle_get_str(b, WIDGET_K_FORCE, &force_str);
-
-       if (force_str && strcmp(force_str, "true") == 0)
-               force = 1;
-       else
-               force = 0;
-
-       bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content_raw);
-
        if (content_raw) {
                content = bundle_decode((const bundle_raw *)content_raw,
                                strlen(content_raw));
        }
 
-       if (cls.ops.update)
-               cls.ops.update(instance_h, content, force, class_data);
+       if (cls->ops.update)
+               cls->ops.update(instance_h, content, force, class_data);
 
        __send_update_status(class_id, id,
-               WIDGET_INSTANCE_EVENT_UPDATE, NULL);
+               WIDGET_INSTANCE_EVENT_UPDATE, 0, NULL);
        LOGD("updated:%s", id);
 
        if (content)
                bundle_free(content);
 }
 
+static void __update_pending_content(
+               appcore_multiwindow_base_instance_h instance_h,
+               const char *content_raw)
+{
+       widget_base_instance_data *data;
+
+       data = (widget_base_instance_data *)
+                       appcore_multiwindow_base_instance_get_extra(instance_h);
+
+       if (data->pending_content) {
+               free(data->pending_content);
+               data->pending_content = NULL;
+       }
+
+       if (content_raw) {
+               data->pending_content = strdup(content_raw);
+               if (data->pending_content == NULL)
+                       LOGW("Out of memory");
+       }
+
+       data->pending_update = true;
+}
+
+static void __update_process(const char *class_id, const char *id,
+               appcore_multiwindow_base_instance_h instance_h, void *data)
+{
+       char *content_raw = NULL;
+       char *force_str = NULL;
+       int force;
+       bundle *b = data;
+
+       if (!b) {
+               LOGE("bundle is NULL");
+               return;
+       }
+
+       bundle_get_str(b, WIDGET_K_FORCE, &force_str);
+
+       if (force_str && strcmp(force_str, "true") == 0)
+               force = 1;
+       else
+               force = 0;
+
+       bundle_get_str(b, WIDGET_K_CONTENT_INFO, &content_raw);
+       if (!appcore_multiwindow_base_instance_is_resumed(instance_h) && !force)
+               __update_pending_content(instance_h, content_raw);
+       else
+               __call_update_cb(class_id, id, force, content_raw);
+}
+
 static void __control_update(const char *class_id, const char *id, bundle *b)
 {
        appcore_multiwindow_base_instance_h instance_h;
 
        if (!id) {
                appcore_multiwindow_base_instance_foreach(class_id,
-                               __update_cb, b);
+                               __update_process, b);
                return;
        }
 
@@ -417,7 +521,7 @@ static void __control_update(const char *class_id, const char *id, bundle *b)
                return;
        }
 
-       __update_cb(class_id, id, instance_h, b);
+       __update_process(class_id, id, instance_h, b);
 }
 
 static void __control_destroy(const char *class_id, const char *id, bundle *b)
@@ -438,11 +542,55 @@ static void __control_destroy(const char *class_id, const char *id, bundle *b)
 
        /* call stub terminate */
        appcore_multiwindow_base_instance_exit(instance_h);
+       free(data->pending_content);
        free(data->content);
+       free(data->id);
        free(data);
        __check_empty_instance();
 }
 
+static void __control_change_period(const char *class_id, const char *id,
+               bundle *b)
+{
+       appcore_multiwindow_base_instance_h instance_h;
+       widget_base_instance_data *data;
+       double *period = NULL;
+       size_t size;
+       int ret;
+
+       instance_h = appcore_multiwindow_base_instance_find(id);
+       if (!instance_h) {
+               LOGE("context not found: %s", id);
+               return;
+       }
+
+       data = (widget_base_instance_data *)
+                       appcore_multiwindow_base_instance_get_extra(instance_h);
+
+       if (!data) {
+               LOGE("could not find instance data: %s", id);
+               return;
+       }
+
+       if (data->periodic_timer) {
+               LOGD("Remove timer!");
+               g_source_remove(data->periodic_timer);
+               data->periodic_timer = 0;
+       }
+
+       ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period, &size);
+       if (ret == BUNDLE_ERROR_NONE)
+               data->period = *period;
+
+       if (data->period > 0) {
+               LOGD("Restart timer!");
+               data->periodic_timer = g_timeout_add_seconds(data->period,
+                               __timeout_cb, data);
+       }
+
+       return;
+}
+
 static int __multiwindow_create(void *data)
 {
        char pkgid[256] = {0, };
@@ -534,6 +682,8 @@ static int __multiwindow_control(bundle *b, void *data)
                __control_pause(class_id, id, b);
        else if (strcmp(operation, "terminate") == 0)
                __control_destroy(class_id, id, b);
+       else if (strcmp(operation, "period") == 0)
+               __control_change_period(class_id, id, b);
 
        return 0;
 }
@@ -629,10 +779,22 @@ static void __multiwindow_exit(void *data)
                __context.ops.exit(data);
 }
 
+static void __multiwindow_trim_memory(void *data)
+{
+       if (__context.ops.trim_memory)
+               __context.ops.trim_memory(data);
+}
+
 EXPORT_API int widget_base_exit(void)
 {
+       int ret;
+
        appcore_multiwindow_base_exit();
-       aul_widget_notify_exit();
+       if (appcore_multiwindow_base_instance_get_cnt() == 0 && __is_permanent) {
+               ret = aul_notify_exit();
+               aul_widget_write_log(LOG_TAG, "[%s:%d] permanent exit : %d",
+                       __FUNCTION__, __LINE__, ret);
+       }
 
        return 0;
 }
@@ -831,7 +993,7 @@ EXPORT_API int widget_base_context_set_content_info(
                return WIDGET_BASE_ERROR_FAULT;
 
        ret = __send_update_status(class_id, id,
-                       WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, content_info);
+                       WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0, content_info);
 
        if (data->content)
                free(data->content);
@@ -996,6 +1158,7 @@ EXPORT_API int widget_base_init(widget_base_ops ops, int argc, char **argv,
        raw_ops.base.finish = __multiwindow_finish;
        raw_ops.base.run = __multiwindow_run;
        raw_ops.base.exit = __multiwindow_exit;
+       raw_ops.base.trim_memory = __multiwindow_trim_memory;
 
        if (!__is_widget_feature_enabled()) {
                LOGE("not supported"); /* LCOV_EXCL_LINE */
@@ -1004,7 +1167,7 @@ EXPORT_API int widget_base_init(widget_base_ops ops, int argc, char **argv,
 
        kb = bundle_import_from_argv(argc, argv);
        if (kb) {
-               bundle_get_str(kb, WIDGET_K_ENDPOINT, &viewer_endpoint);
+               bundle_get_str(kb, AUL_K_WIDGET_VIEWER, &viewer_endpoint);
                if (viewer_endpoint) {
                        LOGD("viewer endpoint :%s", viewer_endpoint);
                        __viewer_endpoint = strdup(viewer_endpoint);
@@ -1054,6 +1217,11 @@ static void __on_exit(void *data)
        widget_base_on_exit();
 }
 
+static void __on_trim_memory(void *data)
+{
+       widget_base_on_trim_memory();
+}
+
 EXPORT_API int widget_base_on_create(void)
 {
        appcore_multiwindow_base_on_create();
@@ -1085,6 +1253,13 @@ EXPORT_API void widget_base_on_exit(void)
 {
 }
 
+EXPORT_API int widget_base_on_trim_memory(void)
+{
+       appcore_multiwindow_base_on_trim_memory();
+
+       return 0;
+}
+
 EXPORT_API widget_base_ops widget_base_get_default_ops(void)
 {
        widget_base_ops ops;
@@ -1096,6 +1271,7 @@ EXPORT_API widget_base_ops widget_base_get_default_ops(void)
        ops.finish = __on_finish;
        ops.run = __on_run;
        ops.exit = __on_exit;
+       ops.trim_memory = __on_trim_memory;
 
        return ops;
 }
@@ -1117,11 +1293,11 @@ EXPORT_API void widget_base_fini(void)
 
 EXPORT_API int widget_base_context_window_bind(
                widget_base_instance_h instance_h, const char *id,
-               Ecore_Wl_Window *wl_win)
+               Ecore_Wl2_Window *wl_win)
 {
        struct wl_surface *surface;
 
-       surface = ecore_wl_window_surface_get(wl_win);
+       surface = ecore_wl2_window_surface_get(wl_win);
        if (surface == NULL) {
                LOGE("failed to get surface"); /* LCOV_EXCL_LINE */
                return WIDGET_BASE_ERROR_FAULT; /* LCOV_EXCL_LINE */
@@ -1186,7 +1362,9 @@ static void __multiwindow_instance_create(
        int w = 0;
        int h = 0;
        int ret = -1;
-       widget_base_class cls;
+       widget_base_class *cls;
+       double *period = NULL;
+       size_t size;
 
        appcore_multiwindow_base_class_on_create(instance_h);
        instance_data = appcore_multiwindow_base_instance_get_extra(instance_h);
@@ -1198,6 +1376,11 @@ static void __multiwindow_instance_create(
                class_id = __appid;
 
        cls = __get_class(class_id);
+       if (cls == NULL) {
+               LOGE("class not found: %s", class_id);
+               return;
+       }
+
        bundle_get_str(b, AUL_K_WIDGET_INSTANCE_ID, &id);
        bundle_get_str(b, WIDGET_K_OPERATION, &operation);
 
@@ -1220,20 +1403,34 @@ static void __multiwindow_instance_create(
                content_info = bundle_decode((const bundle_raw *)content,
                                strlen(content));
 
-       if (cls.ops.create)
-               ret = cls.ops.create(instance_h, content_info, w, h, class_data);
+       if (cls->ops.create)
+               ret = cls->ops.create(instance_h, content_info, w, h, class_data);
 
        if (ret < 0) {
                LOGW("Create callback returns error(%d)", ret);
                ret = __send_update_status(class_id, id,
-                               WIDGET_INSTANCE_EVENT_CREATE_ABORTED, NULL);
+                               WIDGET_INSTANCE_EVENT_CREATE_ABORTED, ret, NULL);
+               if (ret < 0)
+                       LOGE("Fail to send abort status (%d) ", ret);
                __instance_drop(instance_h);
        } else {
                LOGD("%s is created", id);
                ret = __send_update_status(class_id, id,
-                       WIDGET_INSTANCE_EVENT_CREATE, NULL);
+                       WIDGET_INSTANCE_EVENT_CREATE, 0, NULL);
+               if (ret < 0)
+                       LOGE("Fail to send create status (%d) ", ret);
 
                aul_widget_instance_add(class_id, id);
+
+               ret = bundle_get_byte(b, WIDGET_K_PERIOD, (void **)&period,
+                               &size);
+               if (ret == BUNDLE_ERROR_NONE && *period > 0) {
+                       LOGI("set periodic update timer (%lf)", *period);
+                       instance_data->period = *period;
+                       instance_data->periodic_timer = g_timeout_add_seconds(
+                                       instance_data->period,
+                                       __timeout_cb, instance_data);
+               }
        }
 
        if (content_info)
@@ -1246,27 +1443,43 @@ static void __multiwindow_instance_resume(
 {
        const char *id;
        const char *class_id;
-       widget_base_class cls;
+       widget_base_class *cls;
+       widget_base_instance_data *data;
 
        appcore_multiwindow_base_class_on_resume(instance_h);
        id = appcore_multiwindow_base_instance_get_id(instance_h);
        class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
        cls = __get_class(class_id);
+       if (cls == NULL) {
+               LOGE("class not found: %s", class_id);
+               return;
+       }
+
+       data = (widget_base_instance_data *)
+                       appcore_multiwindow_base_instance_get_extra(instance_h);
+
+       if (data->pending_update) {
+               LOGD("pending update!");
+               data->pending_update = false;
+               __call_update_cb(class_id, data->id, 0, data->pending_content);
+               if (data->period > 0) {
+                       LOGD("Restart timer!");
+                       data->periodic_timer = g_timeout_add_seconds(
+                                       data->period,
+                                       __timeout_cb, data);
+               }
+       }
 
-       if (cls.ops.resume)
-               cls.ops.resume(instance_h, class_data);
+       if (cls->ops.resume)
+               cls->ops.resume(instance_h, class_data);
 
        LOGD("%s is resumed", id);
        __send_update_status(class_id, id,
-               WIDGET_INSTANCE_EVENT_RESUME, NULL);
+               WIDGET_INSTANCE_EVENT_RESUME, 0, NULL);
 
        if (!__fg_signal) {
                LOGD("Send fg signal to resourceD");
-               aul_send_app_status_change_signal(getpid(),
-                               __appid,
-                               __package_id,
-                               STATUS_FOREGROUND,
-                               APP_TYPE_WIDGET);
+               aul_widget_instance_change_status(class_id, STATUS_FOREGROUND);
                __fg_signal = true;
        }
 }
@@ -1277,27 +1490,27 @@ static void __multiwindow_instance_pause(
 {
        const char *id;
        const char *class_id;
-       widget_base_class cls;
+       widget_base_class *cls;
 
        appcore_multiwindow_base_class_on_pause(instance_h);
        id = appcore_multiwindow_base_instance_get_id(instance_h);
        class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
        cls = __get_class(class_id);
+       if (cls == NULL) {
+               LOGE("class not found: %s", class_id);
+               return;
+       }
 
-       if (cls.ops.pause)
-               cls.ops.pause(instance_h, class_data);
+       if (cls->ops.pause)
+               cls->ops.pause(instance_h, class_data);
 
        LOGD("%s is paused", id);
        __send_update_status(class_id, id,
-               WIDGET_INSTANCE_EVENT_PAUSE, NULL);
+               WIDGET_INSTANCE_EVENT_PAUSE, 0, NULL);
 
        if (__fg_signal) {
                LOGD("Send bg signal to resourceD");
-               aul_send_app_status_change_signal(getpid(),
-                               __appid,
-                               __package_id,
-                               STATUS_BACKGROUND,
-                               APP_TYPE_WIDGET);
+               aul_widget_instance_change_status(class_id, STATUS_BACKGROUND);
                __fg_signal = false;
        }
 }
@@ -1314,7 +1527,7 @@ static void __multiwindow_instance_terminate(
        int event = WIDGET_INSTANCE_EVENT_TERMINATE;
        const char *id;
        const char *class_id;
-       widget_base_class cls;
+       widget_base_class *cls;
 
        id = appcore_multiwindow_base_instance_get_id(instance_h);
        class_id = appcore_multiwindow_base_instance_get_class_id(instance_h);
@@ -1322,6 +1535,10 @@ static void __multiwindow_instance_terminate(
                        (appcore_multiwindow_base_instance_h)instance_h);
        b = data->args;
        cls = __get_class(class_id);
+       if (cls == NULL) {
+               LOGE("class not found: %s", class_id);
+               return;
+       }
 
        if (b) {
                bundle_get_str(b, WIDGET_K_OPERATION, &operation);
@@ -1335,23 +1552,28 @@ static void __multiwindow_instance_terminate(
        else
                content_info = bundle_create();
 
-       if (cls.ops.destroy)
-               cls.ops.destroy(instance_h, reason, content_info, class_data);
+       if (cls->ops.destroy)
+               cls->ops.destroy(instance_h, reason, content_info, class_data);
 
-       LOGD("%s is destroyed %d", id, reason);
+       LOGW("%s is destroyed %d", id, reason);
        if (reason == WIDGET_BASE_DESTROY_TYPE_PERMANENT) {
+               __is_permanent = true;
                event = WIDGET_INSTANCE_EVENT_DESTROY;
                aul_widget_instance_del(class_id, id);
        } else {
+               __is_permanent = false;
                __send_update_status(class_id, id,
-                               WIDGET_INSTANCE_EVENT_EXTRA_UPDATED,
+                               WIDGET_INSTANCE_EVENT_EXTRA_UPDATED, 0,
                                content_info);
        }
 
        if (content_info)
                bundle_free(content_info);
 
-       __send_update_status(class_id, id, event, NULL);
+       if (data->periodic_timer)
+               g_source_remove(data->periodic_timer);
+
+       __send_update_status(class_id, id, event, 0, NULL);
        appcore_multiwindow_base_class_on_terminate(instance_h);
 }
 
@@ -1407,6 +1629,7 @@ EXPORT_API widget_base_class widget_base_class_get_default(void)
        cls.ops.destroy = __class_on_destroy;
        cls.ops.pause = __class_on_pause;
        cls.ops.resume = __class_on_resume;
+       cls.id = NULL;
 
        return cls;
 }