X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fbase%2Fappcore_base.c;h=c9a17cc69ebffdc30e16d2e82265f95c93eb4f45;hb=0fcfe3095409c931075c57faa7bd48809ab70b6f;hp=7c1b82662be66615bc373beb2fde03c0dd54db8b;hpb=ae38eaa6be67da01a9b56924324adfbb1a58e8b8;p=platform%2Fcore%2Fappfw%2Fapp-core.git diff --git a/src/base/appcore_base.c b/src/base/appcore_base.c index 7c1b826..c9a17cc 100644 --- a/src/base/appcore_base.c +++ b/src/base/appcore_base.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,8 @@ #include #include #include +#include +#include #include "appcore_base.h" #include "appcore_base_private.h" @@ -50,6 +53,7 @@ typedef struct _appcore_base_context { unsigned int tid; bool suspended_state; bool allowed_bg; + bool dirty; } appcore_base_context; typedef struct _appcore_base_event_node { @@ -58,10 +62,24 @@ typedef struct _appcore_base_event_node { void *data; } appcore_base_event_node; +typedef struct _appcore_base_rotation { + int conn; + int lock; + int ref; + enum appcore_base_rm rm; +} appcore_base_rotation; + +struct lang_info_s { + char *parent; + GList *list; +}; + static appcore_base_context __context; static GList *__events; static GDBusConnection *__bus; static guint __suspend_dbus_handler_initialized; +static char *__locale_dir; +static appcore_base_rotation __rotation; static void __invoke_callback(void *event, int type) { @@ -92,6 +110,156 @@ static bool __exist_callback(int type) return false; } +static enum appcore_base_rm __get_rm(sensor_data_t data) +{ + int event; + enum appcore_base_rm rm; + + if (data.value_count <= 0) { + _ERR("Failed to get sensor data"); + return APPCORE_BASE_RM_UNKNOWN; + } + + event = data.values[0]; + switch (event) { + case AUTO_ROTATION_DEGREE_0: + rm = APPCORE_BASE_RM_PORTRAIT_NORMAL; + break; + case AUTO_ROTATION_DEGREE_90: + rm = APPCORE_BASE_RM_LANDSCAPE_NORMAL; + break; + case AUTO_ROTATION_DEGREE_180: + rm = APPCORE_BASE_RM_PORTRAIT_REVERSE; + break; + case AUTO_ROTATION_DEGREE_270: + rm = APPCORE_BASE_RM_LANDSCAPE_REVERSE; + break; + default: + rm = APPCORE_BASE_RM_UNKNOWN; + break; + } + + return rm; +} + +static void __lock_cb(keynode_t *node, void *user_data) +{ + bool r; + sensor_data_t data; + enum appcore_base_rm rm; + + __rotation.lock = !vconf_keynode_get_bool(node); + if (__rotation.lock) { + _DBG("Rotation locked"); + rm = APPCORE_BASE_RM_PORTRAIT_NORMAL; + } else { + _DBG("Rotation unlocked"); + r = sensord_get_data(__rotation.conn, AUTO_ROTATION_SENSOR, &data); + if (!r) { + _ERR("Failed to get sensor data"); + return; + } + + rm = __get_rm(data); + if (rm == APPCORE_BASE_RM_UNKNOWN) { + _ERR("Unknown mode"); + return; + } + } + + if (__rotation.rm == rm) + return; + + _DBG("Rotation: %d -> %d", __rotation.rm, rm); + __rotation.rm = rm; + __invoke_callback((void *)&__rotation.rm, APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED); +} + +static void __auto_rotation_changed_cb(sensor_t sensor, unsigned int event_type, + sensor_data_t *data, void *user_data) +{ + enum appcore_base_rm rm; + + if (data == NULL) + return; + + if (__rotation.lock) + return; + + if (event_type != AUTO_ROTATION_CHANGE_STATE_EVENT) + return; + + rm = __get_rm(*data); + if (rm == APPCORE_BASE_RM_UNKNOWN) { + _ERR("Unknown mode"); + return; + } + + _DBG("Rotation: %d -> %d", __rotation.rm, rm); + __rotation.rm = rm; + __invoke_callback((void *)&__rotation.rm, APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED); +} + +static void __unregister_rotation_changed_event(void) +{ + if (!__rotation.ref) + return; + + __rotation.ref--; + if (__rotation.ref > 1) + return; + + vconf_ignore_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb); + sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT); + sensord_stop(__rotation.conn); + sensord_disconnect(__rotation.conn); + + __rotation.lock = 0; + __rotation.ref = 0; +} + +static void __register_rotation_changed_event(void) +{ + sensor_t sensor; + int lock; + bool r; + + if (__rotation.ref) { + __rotation.ref++; + return; + } + + sensor = sensord_get_sensor(AUTO_ROTATION_SENSOR); + __rotation.conn = sensord_connect(sensor); + if (__rotation.conn < 0) { + _ERR("Failed to connect sensord"); + return; + } + + r = sensord_register_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT, + SENSOR_INTERVAL_NORMAL, 0, __auto_rotation_changed_cb, NULL); + if (!r) { + _ERR("Failed to register auto rotation change event"); + sensord_disconnect(__rotation.conn); + return; + } + + r = sensord_start(__rotation.conn, 0); + if (!r) { + _ERR("Failed to start sensord"); + sensord_unregister_event(__rotation.conn, AUTO_ROTATION_CHANGE_STATE_EVENT); + sensord_disconnect(__rotation.conn); + return; + } + + lock = 0; + vconf_get_bool(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, &lock); + vconf_notify_key_changed(VCONFKEY_SETAPPL_AUTO_ROTATE_SCREEN_BOOL, __lock_cb, NULL); + + __rotation.lock = !lock; + __rotation.ref++; +} + static void __on_low_memory(keynode_t *key, void *data) { int val; @@ -99,7 +267,7 @@ static void __on_low_memory(keynode_t *key, void *data) val = vconf_keynode_get_int(key); if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) { - __invoke_callback(key, APPCORE_BASE_EVENT_LOW_MEMORY); + __invoke_callback(&val, APPCORE_BASE_EVENT_LOW_MEMORY); malloc_trim(0); } } @@ -111,19 +279,296 @@ static void __on_low_battery(keynode_t *key, void *data) val = vconf_keynode_get_int(key); if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW) - __invoke_callback(key, APPCORE_BASE_EVENT_LOW_BATTERY); + __invoke_callback(&val, APPCORE_BASE_EVENT_LOW_BATTERY); +} + +static void __destroy_lang_info(gpointer data) +{ + struct lang_info_s *info = (struct lang_info_s *)data; + + if (info == NULL) + return; + + if (info->list) + g_list_free_full(info->list, free); + if (info->parent) + free(info->parent); + free(info); +} + +static struct lang_info_s *__create_lang_info(const char *lang) +{ + struct lang_info_s *info; + + info = calloc(1, sizeof(struct lang_info_s)); + if (info == NULL) { + _ERR("Out of memory"); + return NULL; + } + + info->parent = strdup(lang); + if (info->parent == NULL) { + _ERR("Out of memory"); + free(info); + return NULL; + } + + return info; +} + +static gint __compare_langs(gconstpointer a, gconstpointer b) +{ + if (!a || !b) + return -1; + + return strcmp(a, b); +} + +static char *__get_string_before(const char *str, const char *delim) +{ + char *new_str; + char *dup_str; + char *token; + + dup_str = strdup(str); + if (dup_str == NULL) + return NULL; + + token = strtok(dup_str, delim); + if (token == NULL) { + free(dup_str); + return NULL; + } + + new_str = strdup(token); + free(dup_str); + + return new_str; +} + +static GHashTable *__get_lang_table(void) +{ + GHashTable *table; + DIR *dp; + struct dirent *dentry; + char buf[PATH_MAX]; + struct stat stat_buf; + int ret; + char *parent_lang; + struct lang_info_s *info; + + if (__locale_dir == NULL || __locale_dir[0] == '\0') + return NULL; + + table = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, __destroy_lang_info); + if (table == NULL) { + _ERR("Out of memory"); + return NULL; + } + + dp = opendir(__locale_dir); + if (dp == NULL) { + g_hash_table_destroy(table); + return NULL; + } + + while ((dentry = readdir(dp)) != NULL) { + if (!strcmp(dentry->d_name, ".") || + !strcmp(dentry->d_name, "..")) + continue; + + snprintf(buf, sizeof(buf), "%s/%s", + __locale_dir, dentry->d_name); + ret = stat(buf, &stat_buf); + if (ret != 0 || !S_ISDIR(stat_buf.st_mode)) + continue; + + parent_lang = __get_string_before(dentry->d_name, "_"); + if (parent_lang == NULL) { + _ERR("Out of memory"); + break; + } + + info = g_hash_table_lookup(table, parent_lang); + if (info == NULL) { + info = __create_lang_info(parent_lang); + if (info == NULL) { + free(parent_lang); + break; + } + g_hash_table_insert(table, info->parent, info); + } + info->list = g_list_append(info->list, strdup(dentry->d_name)); + free(parent_lang); + } + closedir(dp); + + return table; +} + +static GList *__append_langs(const char *lang, GList *list, GHashTable *table) +{ + struct lang_info_s *info; + GList *found; + char *parent_lang = NULL; + char *extract_lang; + + if (lang == NULL) + return list; + + extract_lang = __get_string_before(lang, "."); + if (extract_lang == NULL) + return list; + + found = g_list_find_custom(list, extract_lang, __compare_langs); + if (found) { + list = g_list_remove_link(list, found); + list = g_list_concat(list, found); + goto end; + } + + parent_lang = __get_string_before(extract_lang, "_"); + if (parent_lang == NULL) + goto end; + + info = g_hash_table_lookup(table, parent_lang); + if (info == NULL) + goto end; + + found = g_list_find_custom(info->list, extract_lang, __compare_langs); + if (found) { + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + goto end; + } + + found = g_list_find_custom(info->list, parent_lang, __compare_langs); + if (found) { + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + goto end; + } + + found = g_list_first(info->list); + if (found) { + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + } + +end: + if (extract_lang) + free(extract_lang); + if (parent_lang) + free(parent_lang); + + return list; +} + +static GList *__split_language(const char *lang) +{ + GList *list = NULL; + char *dup_lang; + char *token; + + dup_lang = strdup(lang); + if (dup_lang == NULL) { + _ERR("Out of memory"); + return NULL; + } + + token = strtok(dup_lang, ":"); + while (token != NULL) { + list = g_list_append(list, strdup(token)); + token = strtok(NULL, ":"); + } + free(dup_lang); + + return list; +} + +static GList *__append_default_langs(GList *list) +{ + const char *langs[] = {"en_US", "en_GB", "en"}; + unsigned int i; + GList *found; + + for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) { + found = g_list_find_custom(list, langs[i], __compare_langs); + if (found == NULL) + list = g_list_append(list, strdup(langs[i])); + } + + return list; +} + +static char *__get_language(const char *lang) +{ + GHashTable *table; + GList *list; + GList *lang_list = NULL; + GList *iter; + char *language; + char buf[LINE_MAX] = {'\0'}; + size_t n; + + list = __split_language(lang); + if (list == NULL) + return NULL; + + table = __get_lang_table(); + if (table == NULL) { + g_list_free_full(list, free); + return NULL; + } + + iter = g_list_first(list); + while (iter) { + language = (char *)iter->data; + lang_list = __append_langs(language, lang_list, table); + iter = g_list_next(iter); + } + g_list_free_full(list, free); + g_hash_table_destroy(table); + + lang_list = __append_default_langs(lang_list); + iter = g_list_first(lang_list); + while (iter) { + language = (char *)iter->data; + if (language) { + if (buf[0] == '\0') { + snprintf(buf, sizeof(buf), "%s", language); + } else { + n = sizeof(buf) - strlen(buf) - 1; + strncat(buf, ":", n); + n = sizeof(buf) - strlen(buf) - 1; + strncat(buf, language, n); + } + } + iter = g_list_next(iter); + } + g_list_free_full(lang_list, free); + + return strdup(buf); } static void __update_lang(void) { - char language[32]; + char *language; char *lang; char *r; lang = vconf_get_str(VCONFKEY_LANGSET); if (lang) { - snprintf(language, sizeof(language), "%s:en_US:en_GB:en", lang); - setenv("LANGUAGE", language, 1); + /* TODO: Use VCONFKEY_SETAPPL_LANGUAGES key */ + language = __get_language(lang); + if (language) { + _DBG("*****language(%s)", language); + setenv("LANGUAGE", language, 1); + free(language); + } else { + setenv("LANGUAGE", lang, 1); + } setenv("LANG", lang, 1); setenv("LC_MESSAGES", lang, 1); r = setlocale(LC_ALL, ""); @@ -178,7 +623,7 @@ static void __on_region_change(keynode_t *key, void *data) const char *name; name = vconf_keynode_get_name(key); - if (!strcmp(name, VCONFKEY_REGIONFORMAT)) + if (name && !strcmp(name, VCONFKEY_REGIONFORMAT)) val = vconf_keynode_get_str(key); __update_region(); @@ -304,7 +749,7 @@ static int __get_locale_resource_dir(char *locale_dir, int size) snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path); if (access(locale_dir, R_OK) != 0) - return -1; + _DBG("%s does not exist", locale_dir); return 0; } @@ -340,6 +785,12 @@ static int __set_i18n(const char *domain, const char *dir) return -1; } + if (dir) { + if (__locale_dir) + free(__locale_dir); + __locale_dir = strdup(dir); + } + __update_lang(); __update_region(); @@ -399,8 +850,16 @@ EXPORT_API int appcore_base_on_set_i18n(void) return 0; } +EXPORT_API int appcore_base_set_i18n(const char *domain_name, const char *dir_name) +{ + return __set_i18n(domain_name, dir_name); +} + EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void *data) { + int i; + int r; + __context.ops = ops; __context.argc = argc; __context.argv = argv; @@ -409,14 +868,33 @@ EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, vo __context.suspended_state = false; __context.allowed_bg = false; + if (__context.ops.init) + __context.ops.init(argc, argv, data); + if (__context.ops.set_i18n) __context.ops.set_i18n(__context.data); __init_suspend_dbus_handler(); - if (__context.ops.create && __context.ops.create(__context.data) < 0) { - aul_status_update(STATUS_DYING); - return 0; + if (!__context.dirty) { + __context.dirty = true; + + for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) { + if (__exist_callback(i)) { + if (__context.ops.set_event) + __context.ops.set_event(i, __context.data); + } + } + } + + if (__context.ops.create) { + traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE"); + r = __context.ops.create(__context.data); + traceEnd(TTRACE_TAG_APPLICATION_MANAGER); + if (r < 0) { + aul_status_update(STATUS_DYING); + return r; + } } if (__context.ops.run) @@ -429,6 +907,13 @@ EXPORT_API void appcore_base_fini(void) { int i; + aul_status_update(STATUS_DYING); + if (__context.ops.terminate) { + traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE"); + __context.ops.terminate(__context.data); + traceEnd(TTRACE_TAG_APPLICATION_MANAGER); + } + for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) { if (__exist_callback(i)) { if (__context.ops.unset_event) @@ -440,10 +925,15 @@ EXPORT_API void appcore_base_fini(void) __events = NULL; __fini_suspend_dbus_handler(); - aul_status_update(STATUS_DYING); - if (__context.ops.terminate) - __context.ops.terminate(__context.data); + if (__locale_dir) { + free(__locale_dir); + __locale_dir = NULL; + } + + __context.dirty = false; + if (__context.ops.finish) + __context.ops.finish(); } EXPORT_API int appcore_base_flush_memory(void) @@ -482,8 +972,11 @@ EXPORT_API int appcore_base_on_receive(aul_type type, bundle *b) __remove_suspend_timer(); } - if (__context.ops.control) - __context.ops.control(b, __context.data); + if (__context.ops.control) { + traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESET"); + __context.ops.control(b, __context.data); + traceEnd(TTRACE_TAG_APPLICATION_MANAGER); + } break; case AUL_RESUME: _DBG("[APP %d] AUL event: AUL_RESUME", getpid()); @@ -583,6 +1076,9 @@ EXPORT_API void appcore_base_on_set_event(enum appcore_base_event event) case APPCORE_BASE_EVENT_LANG_CHANGE: vconf_notify_key_changed(VCONFKEY_LANGSET, __on_language_change, NULL); break; + case APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED: + __register_rotation_changed_event(); + break; case APPCORE_BASE_EVENT_REGION_CHANGE: r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change, NULL); if (r < 0) @@ -613,6 +1109,9 @@ EXPORT_API void appcore_base_on_unset_event(enum appcore_base_event event) case APPCORE_BASE_EVENT_LANG_CHANGE: vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_language_change); break; + case APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED: + __unregister_rotation_changed_event(); + break; case APPCORE_BASE_EVENT_REGION_CHANGE: r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change); if (r < 0) @@ -631,7 +1130,7 @@ EXPORT_API appcore_base_event_h appcore_base_add_event(enum appcore_base_event e { appcore_base_event_node *node; - if (!__exist_callback(event)) { + if (__context.dirty && !__exist_callback(event)) { if (__context.ops.set_event) __context.ops.set_event(event, __context.data); } @@ -654,10 +1153,13 @@ EXPORT_API int appcore_base_remove_event(appcore_base_event_h handle) appcore_base_event_node *node = handle; enum appcore_base_event event; + if (!node || !g_list_find(__events, node)) + return -1; + event = node->type; __events = g_list_remove(__events, node); free(node); - if (!__exist_callback(event)) { + if (__context.dirty && !__exist_callback(event)) { if (__context.ops.unset_event) __context.ops.unset_event(event, __context.data); } @@ -673,6 +1175,13 @@ EXPORT_API int appcore_base_raise_event(void *event, enum appcore_base_event typ EXPORT_API int appcore_base_get_rotation_state(enum appcore_base_rm *curr) { + if (curr == NULL) + return -1; + + if (!__rotation.ref) + return -1; + + *curr = __rotation.rm; return 0; } @@ -735,6 +1244,8 @@ EXPORT_API appcore_base_ops appcore_base_get_default_ops(void) ops.terminate = __on_terminate; ops.receive = __on_receive; ops.set_i18n = __on_set_i18n; + ops.init = NULL; + ops.finish = NULL; ops.run = NULL; ops.exit = NULL; ops.set_event = __on_set_event;