From: Jiwoong Im Date: Tue, 30 Dec 2014 11:30:59 +0000 (+0900) Subject: Add new api for system event handling from tizen_2.3 X-Git-Tag: accepted/tizen/4.0/unified/20170816.011601~6^2~133^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=001fb68b65c4f1c6b93569723c558f687a18f68b;p=platform%2Fcore%2Fapi%2Fapp-control.git Add new api for system event handling from tizen_2.3 Remove system event callbacks except related application lifecycle. The system event callbacks can be registered using ui_app_add_event_handler(). Multiple system event callbacks can be registered. The application main loop api is renamed to ui_app_main. app_event_get_xxx provides apis for getting system event information. Change-Id: Ib24f8bb46038fc6a4b50c2516e846cfc27e7acfd Signed-off-by: Jiwoong Im --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ce05ad..df7f5df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) SET(requires "dlog bundle appcore-common appcore-efl aul ail appsvc notification elementary capi-base-common alarm-service sqlite3 libtzplatform-config") -SET(pc_requires "capi-base-common") +SET(pc_requires "capi-base-common vconf-internal-keys") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${requires}) diff --git a/include/app.h b/include/app.h index 362178b..ca71b6f 100755 --- a/include/app.h +++ b/include/app.h @@ -224,6 +224,26 @@ typedef struct app_region_format_changed_cb region_format_changed; /**< The registered callback function is called when region format setting is changes. */ } app_event_callback_s; +/** + * @brief The structure type containing the set of callback functions for handling application lifecycle events. + * @details It is one of the input parameters of the ui_app_main() function. + * + * @see ui_app_main() + * @see app_create_cb() + * @see app_pause_cb() + * @see app_resume_cb() + * @see app_terminate_cb() + * @see service_cb() + */ +typedef struct +{ + app_create_cb create; /**< This callback function is called at the start of the application. */ + app_terminate_cb terminate; /**< This callback function is called once after the main loop of the application exits. */ + app_pause_cb pause; /**< This callback function is called each time the application is completely obscured by another application and becomes invisible to the user. */ + app_resume_cb resume; /**< This callback function is called each time the application becomes visible to the user. */ + app_service_cb service; /**< This callback function is called when another application sends the launch request to the application. */ +} ui_app_lifecycle_callback_s; + /** * @brief Runs the main loop of application until app_efl_exit() is called @@ -271,6 +291,160 @@ void app_efl_exit(void); /** + * @brief Enumeration for system events + */ +typedef enum +{ + APP_EVENT_LOW_MEMORY, /**< The low memory event */ + APP_EVENT_LOW_BATTERY, /**< The low battery event */ + APP_EVENT_LANGUAGE_CHANGED, /**< The system language changed event */ + APP_EVENT_DEVICE_ORIENTATION_CHANGED, /**< The device orientation changed event */ + APP_EVENT_REGION_FORMAT_CHANGED, /**< The region format changed event */ +} app_event_type_e; + + +/** + * @brief Enumeration for low memory status. + */ +typedef enum +{ + APP_EVENT_LOW_MEMORY_NORMAL = 0x01, /**< Normal status */ + APP_EVENT_LOW_MEMORY_SOFT_WARNING = 0x02, /**< Soft warning status */ + APP_EVENT_LOW_MEMORY_HARD_WARNING = 0x04, /**< Hard warning status */ +} app_event_low_memory_status_e; + + +/** + * @brief Enumeration for battery status. + */ +typedef enum +{ + APP_EVENT_LOW_BATTERY_POWER_OFF = 1, /**< The battery status is under 1% */ + APP_EVENT_LOW_BATTERY_CRITICAL_LOW, /**< The battery status is under 5% */ +} app_event_low_battery_status_e; + + +/** + * @brief The event handler that returned from add event handler function + * + * @see app_event_type_e + * @see app_add_event_handler + * @see app_remove_event_handler + * @see app_event_info_h + */ +typedef struct app_event_handler* app_event_handler_h; + + +/** + * @brief The system event information + * + * @see app_event_get_low_memory_status + * @see app_event_get_low_battery_status + * @see app_event_get_language + * @see app_event_get_region_format + * @see app_event_get_device_orientation + */ +typedef struct app_event_info* app_event_info_h; + + +/** + * @brief The system event callback function + * + * @param[in] event_info The system event information + * @param[in] user_data The user data passed from the add event handler function + * + * @see app_add_event_handler + * @see app_event_info_h + */ +typedef void (*app_event_cb)(app_event_info_h event_info, void *user_data); + + +/** + * @brief Gets the low memory status from given event info + * + * @param[in] event_info The system event info + * @param[out] status The low memory status + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_INVALID_CONTEXT Invalid event context + * + * @see app_event_info_h + * @see app_event_low_memory_status_e + */ +int app_event_get_low_memory_status(app_event_info_h event_info, app_event_low_memory_status_e *status); + + +/** + * @brief Gets the low battery status from given event info + * + * @param[in] event_info The system event info + * @param[out] status The low battery status + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_INVALID_CONTEXT Invalid event context + * + * @see app_event_info_h + * @see app_event_low_battery_status_e + */ +int app_event_get_low_battery_status(app_event_info_h event_info, app_event_low_battery_status_e *status); + + +/** + * @brief Gets the language from given event info + * + * @remarks @a lang must be released using free() + * @param[in] event_info The system event info + * @param[out] lang The language changed + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_INVALID_CONTEXT Invalid event context + * + * @see app_event_info_h + */ +int app_event_get_language(app_event_info_h event_info, char **lang); + + +/** + * @brief Gets the region format from given event info + * + * @remarks @a region must be released using free() + * @param[in] event_info The system event info + * @param[out] region The region format changed + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_INVALID_CONTEXT Invalid event context + * + * @see app_event_info_h + */ +int app_event_get_region_format(app_event_info_h event_info, char **region); + + +/** + * @brief Gets the device orientation from given event info + * + * @param[in] event_info The system event info + * @param[out] orientation The device orientation changed + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_INVALID_CONTEXT Invalid event context + * + * @see app_event_info_h + * @see app_device_orientation_e + */ +int app_event_get_device_orientation(app_event_info_h event_info, app_device_orientation_e *orientation); + + +/** * @brief Gets the name of the application package. * * @remarks @a package must be released with free() by you. @@ -388,6 +562,81 @@ app_device_orientation_e app_get_device_orientation(void); */ void app_set_reclaiming_system_cache_on_pause(bool enable); +/** + * @brief Runs the application's main loop until ui_app_exit() is called. + * + * @details This function is the main entry point of the Tizen application. + * The app_create_cb() callback function is called to initialize the application before the main loop of application starts up. + * After the app_create_cb() callback function returns true, the main loop starts up and the service_cb() callback function is subsequently called. + * If the app_create_cb() callback function returns false, the main loop doesn't start up and app_terminate_cb() callback function is called. + * This main loop supports event handling for the Ecore Main Loop. + * + * @param[in] argc The argument count + * @param[in] argv The argument vector + * @param[in] callback The set of callback functions to handle application lifecycle events + * @param[in] user_data The user data to be passed to the callback functions + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_INVALID_CONTEXT The application is illegally launched, not launched by the launch system + * @retval #APP_ERROR_ALREADY_RUNNING The main loop already starts + * + * @see app_create_cb() + * @see app_terminate_cb() + * @see app_pause_cb() + * @see app_resume_cb() + * @see app_service_cb() + * @see ui_app_exit() + * @see #ui_app_lifecycle_callback_s + */ +int ui_app_main(int argc, char **argv, ui_app_lifecycle_callback_s *callback, void *user_data); + + +/** + * @brief Exits the main loop of application. + * + * @details The main loop of application stops and app_terminate_cb() is invoked. + * + * @see ui_app_main() + * @see app_terminate_cb() + */ +void ui_app_exit(void); + + +/** + * @brief Adds the system event handler + * + * @param[out] event_handler The event handler + * @param[in] event_type The system event type + * @param[in] callback The callback function + * @param[in] user_data The user data to be passed to the callback functions + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #APP_ERROR_OUT_OF_MEMORY Out of memory + * + * @see app_event_type_e + * @see app_event_cb + * @see ui_app_remove_event_handler + */ +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); + + +/** + * @brief Removes registered event handler + * + * @param[in] event_handler The event handler + * + * @return 0 on success, otherwise a negative error value + * @retval #APP_ERROR_NONE Successful + * @retval #APP_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see ui_app_add_event_handler + */ +int ui_app_remove_event_handler(app_event_handler_h event_handler); + /** * @} @@ -396,5 +645,4 @@ void app_set_reclaiming_system_cache_on_pause(bool enable); #ifdef __cplusplus } #endif - #endif /* __TIZEN_APPFW_APP_H__ */ diff --git a/include/app_private.h b/include/app_private.h index c3a6a15..52db85c 100755 --- a/include/app_private.h +++ b/include/app_private.h @@ -43,6 +43,19 @@ extern "C" { #define PATH_FMT_RO_RES_DIR "/res" #define PATH_FMT_RO_LOCALE_DIR "/local" +struct app_event_handler { + app_event_type_e type; + app_event_cb cb; + void *data; +}; + +struct app_event_info { + app_event_type_e type; + void *value; +}; + +app_device_orientation_e app_convert_appcore_rm(enum appcore_rm rm); + typedef void (*app_finalizer_cb) (void *data); int app_error(app_error_e error, const char* function, const char *description); diff --git a/packaging/capi-appfw-application.spec b/packaging/capi-appfw-application.spec index 8968348..59444c9 100755 --- a/packaging/capi-appfw-application.spec +++ b/packaging/capi-appfw-application.spec @@ -20,6 +20,7 @@ BuildRequires: pkgconfig(alarm-service) BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(libtzplatform-config) +BuildRequires: pkgconfig(vconf-internal-keys) %description An Application library in SLP C API package. diff --git a/src/app_device.c b/src/app_device.c index 8b6215d..a28c3f9 100755 --- a/src/app_device.c +++ b/src/app_device.c @@ -38,36 +38,6 @@ #define LOG_TAG "CAPI_APPFW_APPLICATION" -app_device_orientation_e app_convert_appcore_rm(enum appcore_rm rm) -{ - app_device_orientation_e dev_orientation; - - switch (rm) - { - case APPCORE_RM_PORTRAIT_NORMAL: - dev_orientation = APP_DEVICE_ORIENTATION_0; - break; - - case APPCORE_RM_PORTRAIT_REVERSE: - dev_orientation = APP_DEVICE_ORIENTATION_180; - break; - - case APPCORE_RM_LANDSCAPE_NORMAL: - dev_orientation = APP_DEVICE_ORIENTATION_270; - break; - - case APPCORE_RM_LANDSCAPE_REVERSE: - dev_orientation = APP_DEVICE_ORIENTATION_90; - break; - - default: - dev_orientation = APP_DEVICE_ORIENTATION_0; - break; - } - - return dev_orientation; -} - app_device_orientation_e app_get_device_orientation(void) { enum appcore_rm rm; diff --git a/src/app_event.c b/src/app_event.c new file mode 100755 index 0000000..b07645f --- /dev/null +++ b/src/app_event.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2011 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * 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. + */ + +#include + +#include +#include +#include + +app_device_orientation_e app_convert_appcore_rm(enum appcore_rm rm) +{ + app_device_orientation_e dev_orientation; + + switch (rm) + { + case APPCORE_RM_PORTRAIT_NORMAL: + dev_orientation = APP_DEVICE_ORIENTATION_0; + break; + + case APPCORE_RM_PORTRAIT_REVERSE: + dev_orientation = APP_DEVICE_ORIENTATION_180; + break; + + case APPCORE_RM_LANDSCAPE_NORMAL: + dev_orientation = APP_DEVICE_ORIENTATION_270; + break; + + case APPCORE_RM_LANDSCAPE_REVERSE: + dev_orientation = APP_DEVICE_ORIENTATION_90; + break; + + default: + dev_orientation = APP_DEVICE_ORIENTATION_0; + break; + } + + return dev_orientation; +} + +static int _app_convert_low_memory(void *val) +{ + switch (*(int *)val) { + case VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL: + return APP_EVENT_LOW_MEMORY_NORMAL; + case VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING: + return APP_EVENT_LOW_MEMORY_SOFT_WARNING; + case VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING: + return APP_EVENT_LOW_MEMORY_HARD_WARNING; + default: + return -1; + } +} + +static int _app_convert_low_battery(void *val) +{ + switch (*(int *)val) { + case VCONFKEY_SYSMAN_BAT_POWER_OFF: + return APP_EVENT_LOW_BATTERY_POWER_OFF; + case VCONFKEY_SYSMAN_BAT_CRITICAL_LOW: + return APP_EVENT_LOW_BATTERY_CRITICAL_LOW; + default: + return -1; + } +} + +int app_event_get_low_memory_status(app_event_info_h event_info, app_event_low_memory_status_e *status) +{ + int ret; + + if (event_info == NULL || status == NULL) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter"); + + if (event_info->type != APP_EVENT_LOW_MEMORY) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "event type mismatching"); + + ret = _app_convert_low_memory(event_info->value); + if (ret < 0) + return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "invalid event info"); + + *status = ret; + + return APP_ERROR_NONE; +} + +int app_event_get_low_battery_status(app_event_info_h event_info, app_event_low_battery_status_e *status) +{ + int ret; + + if (event_info == NULL || status == NULL) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter"); + + if (event_info->type != APP_EVENT_LOW_BATTERY) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "event type mismatching"); + + ret = _app_convert_low_battery(event_info->value); + if (ret < 0) + return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "invalid event info"); + + *status = ret; + + return APP_ERROR_NONE; +} + +int app_event_get_language(app_event_info_h event_info, char **lang) +{ + if (event_info == NULL || lang == NULL) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter"); + + if (event_info->type != APP_EVENT_LANGUAGE_CHANGED) + return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "event type mismatching"); + + *lang = strdup(event_info->value); + + return APP_ERROR_NONE; +} + +int app_event_get_region_format(app_event_info_h event_info, char **region) +{ + if (event_info == NULL || region == NULL) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter"); + + if (event_info->type != APP_EVENT_REGION_FORMAT_CHANGED) + return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "event type mismatching"); + + *region = strdup(event_info->value); + + return APP_ERROR_NONE; +} + +int app_event_get_device_orientation(app_event_info_h event_info, app_device_orientation_e *orientation) +{ + if (event_info == NULL || orientation == NULL) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "null parameter"); + + if (event_info->type != APP_EVENT_DEVICE_ORIENTATION_CHANGED) + return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, "event type mismatching"); + + *orientation = app_convert_appcore_rm(*(enum appcore_rm *)(event_info->value)); + + return APP_ERROR_NONE; +} + diff --git a/src/app_main.c b/src/app_main.c index 1b58f72..24079a2 100755 --- a/src/app_main.c +++ b/src/app_main.c @@ -62,11 +62,11 @@ 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 *evnet, void *data); +static int app_appcore_rotation_event(void *event, enum appcore_rm rm, void *data); +static int app_appcore_lang_changed(void *evnet, 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); @@ -260,7 +260,7 @@ int app_appcore_reset(bundle *appcore_bundle, void *data) } -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; @@ -280,7 +280,7 @@ int app_appcore_low_memory(void *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; @@ -300,7 +300,7 @@ int app_appcore_low_battery(void *data) return APP_ERROR_NONE; } -int app_appcore_rotation_event(enum appcore_rm rm, void *data) +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; @@ -324,7 +324,7 @@ int app_appcore_rotation_event(enum appcore_rm rm, void *data) return APP_ERROR_NONE; } -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; @@ -344,7 +344,7 @@ int app_appcore_lang_changed(void *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; @@ -401,3 +401,364 @@ 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); } + +#define UI_APP_EVENT_MAX 5 +static Eina_List *handler_list[UI_APP_EVENT_MAX] = {NULL, }; +static int _initialized = 0; + +struct ui_app_context { + char *package; + char *app_name; + app_state_e state; + ui_app_lifecycle_callback_s *callback; + void *data; +}; + +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) + 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; +} + +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; +} + +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; +} + + +static void _ui_app_set_appcore_event_cb(void) +{ + appcore_set_event_callback(APPCORE_EVENT_LOW_MEMORY, _ui_app_appcore_low_memory, NULL); + appcore_set_event_callback(APPCORE_EVENT_LOW_BATTERY, _ui_app_appcore_low_battery, NULL); + appcore_set_rotation_cb(_ui_app_appcore_rotation_event, NULL); + appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, _ui_app_appcore_lang_changed, NULL); + appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, _ui_app_appcore_region_changed, NULL); +} + +static void _ui_app_unset_appcore_event_cb(void) +{ + appcore_set_event_callback(APPCORE_EVENT_LOW_MEMORY, NULL, NULL); + appcore_set_event_callback(APPCORE_EVENT_LOW_BATTERY, NULL, NULL); + appcore_unset_rotation_cb(); + appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, NULL, NULL); + appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, NULL, NULL); +} + +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); + + _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_context->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 (_initialized) { + _free_handler_list(); + _initialized = 0; + } + + return APP_ERROR_NONE; +} + +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; +} + +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; +} + + +static int _ui_app_appcore_reset(bundle *appcore_bundle, void *data) +{ + LOGI("app_appcore_reset"); + struct ui_app_context *app_context = data; + app_service_cb callback; + service_h service; + + if (app_context == NULL) + return app_error(APP_ERROR_INVALID_CONTEXT, __FUNCTION__, NULL); + + if (service_create_event(appcore_bundle, &service) != APP_ERROR_NONE) + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "failed to create a service handle from the bundle"); + + callback = app_context->callback->service; + + if (callback != NULL) + callback(service, app_context->data); + + service_destroy(service); + + return APP_ERROR_NONE; +} + +int ui_app_main(int argc, char **argv, ui_app_lifecycle_callback_s *callback, void *user_data) +{ + struct ui_app_context app_context = { + .package = NULL, + .app_name = NULL, + .state = APP_STATE_NOT_RUNNING, + .callback = callback, + .data = user_data + }; + + struct appcore_ops appcore_context = { + .data = &app_context, + .create = _ui_app_appcore_create, + .terminate = _ui_app_appcore_terminate, + .pause = _ui_app_appcore_pause, + .resume = _ui_app_appcore_resume, + .reset = _ui_app_appcore_reset, + }; + + if (argc < 1 || 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) + 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) { + 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; + + LOGI("app_efl_main"); + appcore_efl_main(app_context.app_name, &argc, &argv, &appcore_context); + + free(app_context.package); + free(app_context.app_name); + + 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 (!_initialized) { + eina_init(); + _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_REGION_FORMAT_CHANGED) + 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; + 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 (!_initialized) { + LOGI("handler list is not initialized"); + return APP_ERROR_NONE; + } + + type = event_handler->type; + if (type < APP_EVENT_LOW_MEMORY || type > APP_EVENT_REGION_FORMAT_CHANGED) + 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); + return APP_ERROR_NONE; + } + } + + return app_error(APP_ERROR_INVALID_PARAMETER, __FUNCTION__, "cannot find such handler"); +}