#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#include <malloc.h>
#include <locale.h>
#include <vconf.h>
#include <aul.h>
#include <bundle_internal.h>
+#include <sensor_internal.h>
+#include <ttrace.h>
#include "appcore_base.h"
#include "appcore_base_private.h"
unsigned int tid;
bool suspended_state;
bool allowed_bg;
+ bool dirty;
} appcore_base_context;
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)
{
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;
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);
}
}
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, "");
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();
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;
}
return -1;
}
+ if (dir) {
+ if (__locale_dir)
+ free(__locale_dir);
+ __locale_dir = strdup(dir);
+ }
+
__update_lang();
__update_region();
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;
__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 0;
+ }
}
if (__context.ops.run)
{
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)
__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)
__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());
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)
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)
{
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);
}
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);
}
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;
}
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;