Fix bug about the update requested event
[platform/core/api/application.git] / src / app_main.c
index 81f4f5e..fc57921 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2011 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * Licensed under the Apache License, Version 2.0 (the License);
  * you may not use this file except in compliance with the License.
  * distributed under the License is distributed on an AS IS BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License. 
+ * limitations under the License.
  */
 
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include <Elementary.h>
 
-#include <app_private.h>
-#include <app_service_private.h>
+#include <app_internal.h>
+#include <app_control_internal.h>
+#include <tizen_error.h>
+
+#include "app_extension.h"
 
 #ifdef LOG_TAG
 #undef LOG_TAG
 
 #define LOG_TAG "CAPI_APPFW_APPLICATION"
 
+#define UI_APP_EVENT_MAX 7
+
 typedef enum {
-       APP_STATE_NOT_RUNNING, // The application has been launched or was running but was terminated
-       APP_STATE_CREATING, // The application is initializing the resources on app_create_cb callback
-       APP_STATE_RUNNING, // The application is running in the foreground and background
+       APP_STATE_NOT_RUNNING, /* The application has been launched or was running but was terminated */
+       APP_STATE_CREATING, /* The application is initializing the resources on app_create_cb callback */
+       APP_STATE_RUNNING, /* The application is running in the foreground and background */
 } app_state_e;
 
 typedef struct {
        char *package;
        char *app_name;
-       app_state_e state;
        app_event_callback_s *callback;
        void *data;
 } app_context_s;
 
 typedef app_context_s *app_context_h;
 
+struct ui_app_context {
+       char *package;
+       char *app_name;
+       ui_app_lifecycle_callback_s *callback;
+       void *data;
+};
+
+static Eina_List *handler_list[UI_APP_EVENT_MAX] = {NULL, };
+static int handler_initialized;
+static int appcore_initialized;
+static app_state_e app_state = APP_STATE_NOT_RUNNING;
+
 static int app_appcore_create(void *data);
 static int app_appcore_pause(void *data);
 static int app_appcore_resume(void *data);
 static int app_appcore_terminate(void *data);
 static int app_appcore_reset(bundle *appcore_bundle, void *data);
 
-static int app_appcore_low_memory(void *data);
-static int app_appcore_low_battery(void *data);
-static int app_appcore_rotation_event(enum appcore_rm rm, void *data);
-static int app_appcore_lang_changed(void *data);
-static int app_appcore_region_changed(void *data);
+static int app_appcore_low_memory(void *event, void *data);
+static int app_appcore_low_battery(void *event, void *data);
+static int app_appcore_rotation_event(void *event, enum appcore_rm rm, void *data);
+static int app_appcore_lang_changed(void *event, void *data);
+static int app_appcore_region_changed(void *event, void *data);
 
 static void app_set_appcore_event_cb(app_context_h app_context);
 static void app_unset_appcore_event_cb(void);
 
+int app_main(int argc, char **argv, app_event_callback_s *callback, void *user_data)
+{
+       return app_efl_main(&argc, &argv, callback, user_data);
+}
 
 int app_efl_main(int *argc, char ***argv, app_event_callback_s *callback, void *user_data)
 {
        app_context_s app_context = {
                .package = NULL,
                .app_name = NULL,
-               .state = APP_STATE_NOT_RUNNING,
                .callback = callback,
                .data = user_data
        };
@@ -92,47 +110,43 @@ int app_efl_main(int *argc, char ***argv, app_event_callback_s *callback, void *
        };
 
        if (argc == NULL || argv == NULL || callback == NULL)
-       {
                return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
-       }
 
        if (callback->create == NULL)
-       {
                return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "app_create_cb() callback must be registered");
-       }
 
-       if (app_context.state != APP_STATE_NOT_RUNNING)
-       {
+       if (app_state != APP_STATE_NOT_RUNNING)
                return app_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, NULL);
-       }
 
        if (app_get_id(&(app_context.package)) != APP_ERROR_NONE)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "failed to get the package");
-       }
-       
-       if (app_get_package_app_name(app_context.package, &(app_context.app_name)) != APP_ERROR_NONE)
-       {
+
+       if (app_get_package_app_name(app_context.package, &(app_context.app_name)) != APP_ERROR_NONE) {
+               free(app_context.package);
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "failed to get the package's app name");
        }
 
-       app_context.state = APP_STATE_CREATING;
+       app_state = APP_STATE_CREATING;
 
        appcore_efl_main(app_context.app_name, argc, argv, &appcore_context);
 
+       app_state = APP_STATE_NOT_RUNNING;
        free(app_context.package);
        free(app_context.app_name);
 
        return APP_ERROR_NONE;
 }
 
+void app_exit(void)
+{
+       app_efl_exit();
+}
 
 void app_efl_exit(void)
 {
        elm_exit();
 }
 
-
 int app_appcore_create(void *data)
 {
        app_context_h app_context = data;
@@ -140,26 +154,23 @@ int app_appcore_create(void *data)
        char locale_dir[TIZEN_PATH_MAX] = {0, };
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        app_set_appcore_event_cb(app_context);
 
-       snprintf(locale_dir, TIZEN_PATH_MAX, PATH_FMT_LOCALE_DIR, app_context->package);
+       snprintf(locale_dir, TIZEN_PATH_MAX, "%s/%s" PATH_FMT_RES_DIR
+                       PATH_FMT_LOCALE_DIR, PATH_FMT_APP_ROOT, app_context->package);
        if (access(locale_dir, R_OK) != 0) {
-               snprintf(locale_dir, TIZEN_PATH_MAX, PATH_FMT_RO_LOCALE_DIR, app_context->package);
+               snprintf(locale_dir, TIZEN_PATH_MAX, "%s/%s" PATH_FMT_RO_RES_DIR
+                               PATH_FMT_RO_LOCALE_DIR, PATH_FMT_RO_APP_ROOT, app_context->package);
        }
        appcore_set_i18n(app_context->app_name, locale_dir);
 
        create_cb = app_context->callback->create;
-
        if (create_cb == NULL || create_cb(app_context->data) == false)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "app_create_cb() returns false");
-       }
 
-       app_context->state = APP_STATE_RUNNING;
+       app_state = APP_STATE_RUNNING;
 
        return APP_ERROR_NONE;
 }
@@ -170,148 +181,116 @@ int app_appcore_terminate(void *data)
        app_terminate_cb terminate_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        terminate_cb = app_context->callback->terminate;
 
        if (terminate_cb != NULL)
-       {
                terminate_cb(app_context->data);
-       }
 
-       app_unset_appcore_event_cb();   
+       app_unset_appcore_event_cb();
 
        app_finalizer_execute();
 
        return APP_ERROR_NONE;
 }
 
+/* LCOV_EXCL_START */
 int app_appcore_pause(void *data)
 {
        app_context_h app_context = data;
        app_pause_cb pause_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        pause_cb = app_context->callback->pause;
-
        if (pause_cb != NULL)
-       {
                pause_cb(app_context->data);
-       }
 
        return APP_ERROR_NONE;
 }
+/* LCOV_EXCL_STOP */
 
+/* LCOV_EXCL_START */
 int app_appcore_resume(void *data)
 {
        app_context_h app_context = data;
        app_resume_cb resume_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        resume_cb = app_context->callback->resume;
-
        if (resume_cb != NULL)
-       {
                resume_cb(app_context->data);
-       }
 
        return APP_ERROR_NONE;
 }
-
+/* LCOV_EXCL_STOP */
 
 int app_appcore_reset(bundle *appcore_bundle, void *data)
 {
        app_context_h app_context = data;
-       app_service_cb service_cb;
-       service_h service;
+       app_control_cb callback;
+       app_control_h app_control;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
-       if (service_create_event(appcore_bundle, &service) != APP_ERROR_NONE)
-       {
+       if (app_control_create_event(appcore_bundle, &app_control) != APP_ERROR_NONE)
                return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "failed to create a service handle from the bundle");
-       }
-
-       service_cb = app_context->callback->service;
 
-       if (service_cb != NULL)
-       {
-               service_cb(service, app_context->data);
-       }
+       callback = app_context->callback->app_control;
+       if (callback != NULL)
+               callback(app_control, app_context->data);
 
-       service_destroy(service);
+       app_control_destroy(app_control);
 
        return APP_ERROR_NONE;
 }
 
-
-int app_appcore_low_memory(void *data)
+int app_appcore_low_memory(void *event_info, void *data)
 {
        app_context_h app_context = data;
        app_low_memory_cb low_memory_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        low_memory_cb = app_context->callback->low_memory;
-
        if (low_memory_cb != NULL)
-       {
                low_memory_cb(app_context->data);
-       }
 
        return APP_ERROR_NONE;
 }
 
-int app_appcore_low_battery(void *data)
+int app_appcore_low_battery(void *event_info, void *data)
 {
        app_context_h app_context = data;
        app_low_battery_cb low_battery_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        low_battery_cb = app_context->callback->low_battery;
-
        if (low_battery_cb != NULL)
-       {
                low_battery_cb(app_context->data);
-       }
 
        return APP_ERROR_NONE;
 }
 
-int app_appcore_rotation_event(enum appcore_rm rm, void *data)
+/* LCOV_EXCL_START */
+int app_appcore_rotation_event(void *event_info, enum appcore_rm rm, void *data)
 {
        app_context_h app_context = data;
        app_device_orientation_cb device_orientation_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        device_orientation_cb = app_context->callback->device_orientation;
-
-       if (device_orientation_cb != NULL)
-       {
+       if (device_orientation_cb != NULL) {
                app_device_orientation_e dev_orientation;
 
                dev_orientation = app_convert_appcore_rm(rm);
@@ -321,74 +300,54 @@ int app_appcore_rotation_event(enum appcore_rm rm, void *data)
 
        return APP_ERROR_NONE;
 }
+/* LCOV_EXCL_STOP */
 
-int app_appcore_lang_changed(void *data)
+int app_appcore_lang_changed(void *event_info, void *data)
 {
        app_context_h app_context = data;
        app_language_changed_cb lang_changed_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        lang_changed_cb = app_context->callback->language_changed;
-
        if (lang_changed_cb != NULL)
-       {
                lang_changed_cb(app_context->data);
-       }
 
        return APP_ERROR_NONE;
 }
 
-int app_appcore_region_changed(void *data)
+int app_appcore_region_changed(void *event_info, void *data)
 {
        app_context_h app_context = data;
        app_region_format_changed_cb region_changed_cb;
 
        if (app_context == NULL)
-       {
                return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
-       }
 
        region_changed_cb = app_context->callback->region_format_changed;
-
        if (region_changed_cb != NULL)
-       {
                region_changed_cb(app_context->data);
-       }
 
        return APP_ERROR_NONE;
 }
 
-
 void app_set_appcore_event_cb(app_context_h app_context)
 {
        if (app_context->callback->low_memory != NULL)
-       {
                appcore_set_event_callback(APPCORE_EVENT_LOW_MEMORY, app_appcore_low_memory, app_context);
-       }
 
        if (app_context->callback->low_battery != NULL)
-       {
                appcore_set_event_callback(APPCORE_EVENT_LOW_BATTERY, app_appcore_low_battery, app_context);
-       }
 
        if (app_context->callback->device_orientation != NULL)
-       {
                appcore_set_rotation_cb(app_appcore_rotation_event, app_context);
-       }
 
        if (app_context->callback->language_changed != NULL)
-       {
                appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, app_appcore_lang_changed, app_context);
-       }
 
        if (app_context->callback->region_format_changed != NULL)
-       {
                appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, app_appcore_region_changed, app_context);
-       }
 }
 
 void app_unset_appcore_event_cb(void)
@@ -399,3 +358,596 @@ void app_unset_appcore_event_cb(void)
        appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, NULL, NULL);
        appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, NULL, NULL);
 }
+
+static void _free_handler_list(void)
+{
+       int i;
+       app_event_handler_h handler;
+
+       for (i = 0; i < UI_APP_EVENT_MAX; i++) {
+               EINA_LIST_FREE(handler_list[i], handler)
+                       if (handler)
+                               free(handler);
+       }
+
+       eina_shutdown();
+}
+
+static int _ui_app_appcore_low_memory(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_app_appcore_low_memory");
+
+       event.type = APP_EVENT_LOW_MEMORY;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_LOW_MEMORY], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+
+static int _ui_app_appcore_low_battery(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_ui_app_appcore_low_battery");
+
+       event.type = APP_EVENT_LOW_BATTERY;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_LOW_BATTERY], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+
+/* LCOV_EXCL_START */
+static int _ui_app_appcore_rotation_event(void *event_info, enum appcore_rm rm, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_ui_app_appcore_rotation_event");
+
+       event.type = APP_EVENT_DEVICE_ORIENTATION_CHANGED;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_DEVICE_ORIENTATION_CHANGED], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+/* LCOV_EXCL_STOP */
+
+static int _ui_app_appcore_lang_changed(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_ui_app_appcore_lang_changed");
+
+       event.type = APP_EVENT_LANGUAGE_CHANGED;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_LANGUAGE_CHANGED], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+
+static int _ui_app_appcore_region_changed(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       if (event_info == NULL) {
+               LOGI("receive empty event, ignore it");
+               return APP_ERROR_NONE;
+       }
+
+       LOGI("_ui_app_appcore_region_changed");
+
+       event.type = APP_EVENT_REGION_FORMAT_CHANGED;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_REGION_FORMAT_CHANGED], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+
+/* LCOV_EXCL_START */
+static int _ui_app_appcore_suspended_state_changed(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_ui_app_appcore_suspended_state_changed");
+       LOGI("[__SUSPEND__] suspended state: %d (0: suspend, 1: wake)", *(int *)event_info);
+
+       event.type = APP_EVENT_SUSPENDED_STATE_CHANGED;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_SUSPENDED_STATE_CHANGED], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+/* LCOV_EXCL_STOP */
+
+static int _ui_app_appcore_update_requested(void *event_info, void *data)
+{
+       Eina_List *l;
+       app_event_handler_h handler;
+       struct app_event_info event;
+
+       LOGI("_ui_app_appcore_update_requested");
+
+       event.type = APP_EVENT_UPDATE_REQUESTED;
+       event.value = event_info;
+
+       EINA_LIST_FOREACH(handler_list[APP_EVENT_UPDATE_REQUESTED], l, handler) {
+               handler->cb(&event, handler->data);
+       }
+
+       return APP_ERROR_NONE;
+}
+
+static void _ui_app_appcore_set_event_cb(app_event_type_e event_type)
+{
+       switch (event_type) {
+       case APP_EVENT_LOW_MEMORY:
+               appcore_set_event_callback(APPCORE_EVENT_LOW_MEMORY, _ui_app_appcore_low_memory, NULL);
+               break;
+       case APP_EVENT_LOW_BATTERY:
+               appcore_set_event_callback(APPCORE_EVENT_LOW_BATTERY, _ui_app_appcore_low_battery, NULL);
+               break;
+       case APP_EVENT_LANGUAGE_CHANGED:
+               appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, _ui_app_appcore_lang_changed, NULL);
+               break;
+       case APP_EVENT_DEVICE_ORIENTATION_CHANGED:
+               appcore_set_rotation_cb(_ui_app_appcore_rotation_event, NULL);
+               break;
+       case APP_EVENT_REGION_FORMAT_CHANGED:
+               appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, _ui_app_appcore_region_changed, NULL);
+               break;
+       case APP_EVENT_SUSPENDED_STATE_CHANGED:
+               LOGI("[__SUSPEND__]");
+               appcore_set_event_callback(APPCORE_EVENT_SUSPENDED_STATE_CHANGE, _ui_app_appcore_suspended_state_changed, NULL);
+               break;
+       case APP_EVENT_UPDATE_REQUESTED:
+               appcore_set_event_callback(APPCORE_EVENT_UPDATE_REQUESTED, _ui_app_appcore_update_requested, NULL);
+               break;
+       default:
+               break;
+       }
+}
+
+static void _ui_app_appcore_unset_event_cb(app_event_type_e event_type)
+{
+       switch (event_type) {
+       case APP_EVENT_LOW_MEMORY:
+               appcore_set_event_callback(APPCORE_EVENT_LOW_MEMORY, NULL, NULL);
+               break;
+       case APP_EVENT_LOW_BATTERY:
+               appcore_set_event_callback(APPCORE_EVENT_LOW_BATTERY, NULL, NULL);
+               break;
+       case APP_EVENT_LANGUAGE_CHANGED:
+               appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, NULL, NULL);
+               break;
+       case APP_EVENT_DEVICE_ORIENTATION_CHANGED:
+               appcore_unset_rotation_cb();
+               break;
+       case APP_EVENT_REGION_FORMAT_CHANGED:
+               appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, NULL, NULL);
+               break;
+       case APP_EVENT_SUSPENDED_STATE_CHANGED:
+               LOGI("[__SUSPEND__]");
+               appcore_set_event_callback(APPCORE_EVENT_SUSPENDED_STATE_CHANGE, NULL, NULL);
+               break;
+       case APP_EVENT_UPDATE_REQUESTED:
+               appcore_set_event_callback(APPCORE_EVENT_UPDATE_REQUESTED, NULL, NULL);
+               break;
+       default:
+               break;
+       }
+}
+
+static void _ui_app_set_appcore_event_cb(void)
+{
+       _ui_app_appcore_set_event_cb(APP_EVENT_LOW_MEMORY);
+       _ui_app_appcore_set_event_cb(APP_EVENT_LANGUAGE_CHANGED);
+       _ui_app_appcore_set_event_cb(APP_EVENT_REGION_FORMAT_CHANGED);
+
+       if (eina_list_count(handler_list[APP_EVENT_LOW_BATTERY]) > 0)
+               _ui_app_appcore_set_event_cb(APP_EVENT_LOW_BATTERY);
+       if (eina_list_count(handler_list[APP_EVENT_DEVICE_ORIENTATION_CHANGED]) > 0)
+               _ui_app_appcore_set_event_cb(APP_EVENT_DEVICE_ORIENTATION_CHANGED);
+       if (eina_list_count(handler_list[APP_EVENT_SUSPENDED_STATE_CHANGED]) > 0)
+               _ui_app_appcore_set_event_cb(APP_EVENT_SUSPENDED_STATE_CHANGED);
+       if (eina_list_count(handler_list[APP_EVENT_UPDATE_REQUESTED]) > 0)
+               _ui_app_appcore_set_event_cb(APP_EVENT_UPDATE_REQUESTED);
+}
+
+static void _ui_app_unset_appcore_event_cb(void)
+{
+       _ui_app_appcore_unset_event_cb(APP_EVENT_LOW_MEMORY);
+       _ui_app_appcore_unset_event_cb(APP_EVENT_LANGUAGE_CHANGED);
+       _ui_app_appcore_unset_event_cb(APP_EVENT_REGION_FORMAT_CHANGED);
+
+       if (eina_list_count(handler_list[APP_EVENT_LOW_BATTERY]) > 0)
+               _ui_app_appcore_unset_event_cb(APP_EVENT_LOW_BATTERY);
+       if (eina_list_count(handler_list[APP_EVENT_DEVICE_ORIENTATION_CHANGED]) > 0)
+               _ui_app_appcore_unset_event_cb(APP_EVENT_DEVICE_ORIENTATION_CHANGED);
+       if (eina_list_count(handler_list[APP_EVENT_SUSPENDED_STATE_CHANGED]) > 0)
+               _ui_app_appcore_unset_event_cb(APP_EVENT_SUSPENDED_STATE_CHANGED);
+       if (eina_list_count(handler_list[APP_EVENT_UPDATE_REQUESTED]) > 0)
+               _ui_app_appcore_unset_event_cb(APP_EVENT_UPDATE_REQUESTED);
+}
+
+static int _ui_app_appcore_create(void *data)
+{
+       LOGI("app_appcore_create");
+       struct ui_app_context *app_context = data;
+       app_create_cb create_cb;
+
+       if (app_context == NULL)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+
+       appcore_initialized = 1;
+       _ui_app_set_appcore_event_cb();
+
+       create_cb = app_context->callback->create;
+
+       if (create_cb == NULL || create_cb(app_context->data) == false)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "app_create_cb() returns false");
+
+       app_state = APP_STATE_RUNNING;
+
+       return APP_ERROR_NONE;
+}
+
+static int _ui_app_appcore_terminate(void *data)
+{
+       LOGI("app_appcore_terminate");
+       struct ui_app_context *app_context = data;
+       app_terminate_cb terminate_cb;
+
+       if (app_context == NULL)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+
+       terminate_cb = app_context->callback->terminate;
+
+       if (terminate_cb != NULL)
+               terminate_cb(app_context->data);
+
+       _ui_app_unset_appcore_event_cb();
+
+       app_finalizer_execute();
+
+       if (handler_initialized) {
+               _free_handler_list();
+               handler_initialized = 0;
+       }
+
+       return APP_ERROR_NONE;
+}
+
+/* LCOV_EXCL_START */
+static int _ui_app_appcore_pause(void *data)
+{
+       LOGI("app_appcore_pause");
+       struct ui_app_context *app_context = data;
+       app_pause_cb pause_cb;
+
+       if (app_context == NULL)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+
+       pause_cb = app_context->callback->pause;
+
+       if (pause_cb != NULL)
+               pause_cb(app_context->data);
+
+       return APP_ERROR_NONE;
+}
+/* LCOV_EXCL_STOP */
+
+/* LCOV_EXCL_START */
+static int _ui_app_appcore_resume(void *data)
+{
+       LOGI("app_appcore_resume");
+       struct ui_app_context *app_context = data;
+       app_resume_cb resume_cb;
+
+       if (app_context == NULL)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+
+       resume_cb = app_context->callback->resume;
+
+       if (resume_cb != NULL)
+               resume_cb(app_context->data);
+
+       return APP_ERROR_NONE;
+}
+/* LCOV_EXCL_STOP */
+
+static int _ui_app_appcore_reset(bundle *appcore_bundle, void *data)
+{
+       LOGI("app_appcore_reset");
+       struct ui_app_context *app_context = data;
+       app_control_cb callback;
+       app_control_h app_control;
+       int ret;
+
+       if (app_context == NULL)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+
+       if (appcore_bundle) {
+               if (app_control_create_event(appcore_bundle, &app_control) != APP_ERROR_NONE)
+                       return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "failed to create an app_control handle from the bundle");
+       } else {
+               ret = app_control_create(&app_control);
+               if (ret != APP_ERROR_NONE)
+                       return app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "failed to create an app_control");
+       }
+
+       callback = app_context->callback->app_control;
+
+       if (callback != NULL)
+               callback(app_control, app_context->data);
+
+       app_control_destroy(app_control);
+
+       return APP_ERROR_NONE;
+}
+
+static int __create_ui_app_context(ui_app_lifecycle_callback_s *callback, void *user_data, struct ui_app_context **handle)
+{
+       struct ui_app_context *app_context;
+       int ret;
+
+       app_context = (struct ui_app_context *)calloc(1, sizeof(struct ui_app_context));
+       if (app_context == NULL)
+               return app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+
+       ret = app_get_id(&app_context->package);
+       if (ret != APP_ERROR_NONE) {
+               free(app_context);
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "failed to get the package");
+       }
+
+       ret = app_get_package_app_name(app_context->package, &app_context->app_name);
+       if (ret != APP_ERROR_NONE) {
+               free(app_context->package);
+               free(app_context);
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "failed to get the package's app name");
+       }
+
+       app_context->callback = (ui_app_lifecycle_callback_s *)malloc(sizeof(ui_app_lifecycle_callback_s));
+       if (app_context->callback == NULL) {
+               free(app_context->app_name);
+               free(app_context->package);
+               free(app_context);
+               return app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+       }
+       memcpy(app_context->callback, callback, sizeof(ui_app_lifecycle_callback_s));
+
+       app_context->data = user_data;
+
+       *handle = app_context;
+
+       return APP_ERROR_NONE;
+}
+
+static void __destroy_ui_app_context(struct ui_app_context *handle)
+{
+       if (handle == NULL)
+               return;
+
+       if (handle->callback) {
+               free(handle->callback);
+               handle->callback = NULL;
+       }
+
+       if (handle->app_name) {
+               free(handle->app_name);
+               handle->app_name = NULL;
+       }
+
+       if (handle->package) {
+               free(handle->package);
+               handle->package = NULL;
+       }
+
+       free(handle);
+}
+
+static int __create_appcore_context(struct ui_app_context *app_context, struct appcore_ops **handle)
+{
+       struct appcore_ops *appcore_context;
+
+       appcore_context = (struct appcore_ops *)malloc(sizeof(struct appcore_ops));
+       if (appcore_context == NULL)
+               return app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, NULL);
+
+       appcore_context->data = app_context;
+       appcore_context->create = _ui_app_appcore_create;
+       appcore_context->terminate = _ui_app_appcore_terminate;
+       appcore_context->pause = _ui_app_appcore_pause;
+       appcore_context->resume = _ui_app_appcore_resume;
+       appcore_context->reset = _ui_app_appcore_reset;
+
+       *handle = appcore_context;
+
+       return APP_ERROR_NONE;
+}
+
+static void __destroy_appcore_context(struct appcore_ops *handle)
+{
+       if (handle == NULL)
+               return;
+
+       __destroy_ui_app_context((struct ui_app_context *)handle->data);
+       free(handle);
+}
+
+int ui_app_init(int argc, char **argv, ui_app_lifecycle_callback_s *callback, void *user_data, appcore_context_h *handle)
+{
+       struct ui_app_context *app_context = NULL;
+       struct appcore_ops *appcore_context = NULL;
+       int ret;
+
+       if (argc < 1 || argv == NULL || callback == NULL || handle == NULL)
+               return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, NULL);
+
+       if (callback->create == NULL)
+               return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "app_create_cb() callback must be registered");
+
+       if (app_state != APP_STATE_NOT_RUNNING)
+               return app_error(APP_ERROR_ALREADY_RUNNING, __FUNCTION__, NULL);
+
+       ret = __create_ui_app_context(callback, user_data, &app_context);
+       if (ret != APP_ERROR_NONE)
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+
+       ret = __create_appcore_context(app_context, &appcore_context);
+       if (ret != APP_ERROR_NONE) {
+               __destroy_ui_app_context(app_context);
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+       }
+
+       app_state = APP_STATE_CREATING;
+
+       LOGI("app_efl_init");
+       ret = appcore_efl_init(app_context->app_name, &argc, &argv, appcore_context);
+       if (ret != APP_ERROR_NONE) {
+               app_state = APP_STATE_NOT_RUNNING;
+               __destroy_appcore_context(appcore_context);
+               return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL);
+       }
+
+       *handle = appcore_context;
+
+       return APP_ERROR_NONE;
+}
+
+void ui_app_fini(appcore_context_h handle)
+{
+       appcore_efl_fini();
+
+       app_state = APP_STATE_NOT_RUNNING;
+
+       __destroy_appcore_context(handle);
+}
+
+int ui_app_main(int argc, char **argv, ui_app_lifecycle_callback_s *callback, void *user_data)
+{
+       appcore_context_h handle = NULL;
+       int ret;
+
+       ret = ui_app_init(argc, argv, callback, user_data, &handle);
+       if (ret != APP_ERROR_NONE)
+               return app_error(ret, __FUNCTION__, NULL);
+
+       LOGI("run ui_app_main");
+       elm_run();
+
+       ui_app_fini(handle);
+
+       return APP_ERROR_NONE;
+}
+
+void ui_app_exit(void)
+{
+       app_efl_exit();
+}
+
+int ui_app_add_event_handler(app_event_handler_h *event_handler, app_event_type_e event_type, app_event_cb callback, void *user_data)
+{
+       app_event_handler_h handler;
+       Eina_List *l_itr;
+
+       if (!handler_initialized) {
+               eina_init();
+               handler_initialized = 1;
+       }
+
+       if (event_handler == NULL || callback == NULL)
+               return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter");
+
+       if (event_type < APP_EVENT_LOW_MEMORY || event_type > APP_EVENT_UPDATE_REQUESTED)
+               return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid event type");
+
+       EINA_LIST_FOREACH(handler_list[event_type], l_itr, handler) {
+               if (handler->cb == callback)
+                       return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "already registered");
+       }
+
+       handler = calloc(1, sizeof(struct app_event_handler));
+       if (!handler)
+               return app_error(APP_ERROR_OUT_OF_MEMORY, __FUNCTION__, "failed to create handler");
+
+       handler->type = event_type;
+       handler->cb = callback;
+       handler->data = user_data;
+
+       if (appcore_initialized && eina_list_count(handler_list[event_type]) == 0)
+               _ui_app_appcore_set_event_cb(event_type);
+
+       handler_list[event_type] = eina_list_append(handler_list[event_type], handler);
+
+       *event_handler = handler;
+
+       return APP_ERROR_NONE;
+}
+
+int ui_app_remove_event_handler(app_event_handler_h event_handler)
+{
+       app_event_handler_h handler;
+       app_event_type_e type;
+       Eina_List *l_itr;
+       Eina_List *l_next;
+
+       if (event_handler == NULL)
+               return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "handler is null");
+
+       if (!handler_initialized) {
+               LOGI("handler list is not initialized");
+               return APP_ERROR_NONE;
+       }
+
+       type = event_handler->type;
+       if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_UPDATE_REQUESTED)
+               return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "invalid handler");
+
+       EINA_LIST_FOREACH_SAFE(handler_list[type], l_itr, l_next, handler) {
+               if (handler == event_handler) {
+                       free(handler);
+                       handler_list[type] = eina_list_remove_list(handler_list[type], l_itr);
+
+                       if (appcore_initialized && eina_list_count(handler_list[type]) == 0)
+                               _ui_app_appcore_unset_event_cb(type);
+
+                       return APP_ERROR_NONE;
+               }
+       }
+
+       return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "cannot find such handler");
+}
+