+
+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");
+}
+