Add fallback for multilingual support
[platform/core/appfw/app-core.git] / src / base / appcore_base.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #define _GNU_SOURCE
19
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <malloc.h>
28 #include <locale.h>
29 #include <libintl.h>
30 #include <linux/limits.h>
31 #include <glib.h>
32 #include <gio/gio.h>
33 #include <sys/time.h>
34 #include <dlfcn.h>
35 #include <vconf.h>
36 #include <aul.h>
37 #include <bundle_internal.h>
38 #include "appcore_base.h"
39 #include "appcore_base_private.h"
40
41 #define PATH_LOCALE "locale"
42 #define RESOURCED_FREEZER_PATH "/Org/Tizen/Resourced/Freezer"
43 #define RESOURCED_FREEZER_INTERFACE "org.tizen.resourced.freezer"
44 #define RESOURCED_FREEZER_SIGNAL "FreezerState"
45
46 typedef struct _appcore_base_context {
47         appcore_base_ops ops;
48         void *data;
49         int argc;
50         char **argv;
51         unsigned int tid;
52         bool suspended_state;
53         bool allowed_bg;
54 } appcore_base_context;
55
56 typedef struct _appcore_base_event_node {
57         int type;
58         appcore_base_event_cb cb;
59         void *data;
60 } appcore_base_event_node;
61
62 static appcore_base_context __context;
63 static GList *__events;
64 static GDBusConnection *__bus;
65 static guint __suspend_dbus_handler_initialized;
66 static char *__locale_dir;
67
68 static void __invoke_callback(void *event, int type)
69 {
70         GList *iter = __events;
71
72         while (iter) {
73                 appcore_base_event_node *node = iter->data;
74
75                 if (node->type == type)
76                         node->cb(event, node->data);
77                 iter = g_list_next(iter);
78         }
79 }
80
81 static bool __exist_callback(int type)
82 {
83         GList *iter = __events;
84
85         while (iter) {
86                 appcore_base_event_node *node = iter->data;
87
88                 if (node->type == type)
89                         return true;
90
91                 iter = g_list_next(iter);
92         }
93
94         return false;
95 }
96
97 static void __on_low_memory(keynode_t *key, void *data)
98 {
99         int val;
100
101         val = vconf_keynode_get_int(key);
102
103         if (val >= VCONFKEY_SYSMAN_LOW_MEMORY_SOFT_WARNING) {
104                 __invoke_callback(key, APPCORE_BASE_EVENT_LOW_MEMORY);
105                 malloc_trim(0);
106         }
107 }
108
109 static void __on_low_battery(keynode_t *key, void *data)
110 {
111         int val;
112
113         val = vconf_keynode_get_int(key);
114
115         if (val <= VCONFKEY_SYSMAN_BAT_CRITICAL_LOW)
116                 __invoke_callback(key, APPCORE_BASE_EVENT_LOW_BATTERY);
117 }
118
119 static void __free_children_langs(gpointer data)
120 {
121         GList *list = (GList *)data;
122
123         if (list == NULL)
124                 return;
125
126         g_list_free_full(list, (GDestroyNotify)free);
127 }
128
129 static gint __compare_langs(gconstpointer a, gconstpointer b)
130 {
131         return strcmp(a, b);
132 }
133
134 static GHashTable *__get_lang_table(void)
135 {
136         GHashTable *table;
137         DIR *dp;
138         struct dirent *dentry;
139         char buf[PATH_MAX];
140         struct stat stat_buf;
141         int ret;
142         char *dup_lang;
143         char *token;
144         GList *list;
145
146         if (__locale_dir == NULL || __locale_dir[0] == '\0')
147                 return NULL;
148
149         table = g_hash_table_new_full(g_str_hash, g_str_equal,
150                         free, __free_children_langs);
151         if (table == NULL) {
152                 _ERR("Out of memory");
153                 return NULL;
154         }
155
156         dp = opendir(__locale_dir);
157         if (dp == NULL) {
158                 g_hash_table_destroy(table);
159                 return NULL;
160         }
161
162         while ((dentry = readdir(dp)) != NULL) {
163                 if (!strcmp(dentry->d_name, ".") ||
164                                 !strcmp(dentry->d_name, ".."))
165                         continue;
166
167                 snprintf(buf, sizeof(buf), "%s/%s",
168                                 __locale_dir, dentry->d_name);
169                 ret = stat(buf, &stat_buf);
170                 if (ret != 0 || !S_ISDIR(stat_buf.st_mode))
171                         continue;
172
173                 dup_lang = strdup(dentry->d_name);
174                 if (dup_lang == NULL) {
175                         _ERR("Out of memory");
176                         break;
177                 }
178
179                 token = strtok(dup_lang, "_");
180                 if (token == NULL) {
181                         free(dup_lang);
182                         continue;
183                 }
184
185                 list = (GList *)g_hash_table_lookup(table, token);
186                 if (list == NULL) {
187                         list = g_list_append(list, strdup(dentry->d_name));
188                         g_hash_table_insert(table, strdup(token), list);
189                 } else {
190                         list = g_list_append(list, strdup(dentry->d_name));
191                 }
192                 free(dup_lang);
193         }
194         closedir(dp);
195
196         return table;
197 }
198
199 static GList *__append_langs(const char *lang, GList *list, GHashTable *table)
200 {
201         GList *child_list;
202         GList *child_iter;
203         GList *found;
204         char *child_lang;
205         char *dup_lang;
206         char *token;
207
208         if (lang == NULL)
209                 return list;
210
211         found = g_list_find_custom(g_list_first(list), lang,
212                         __compare_langs);
213         if (found) {
214                 list = g_list_remove_link(list, found);
215                 free(found->data);
216                 g_list_free(found);
217                 list = g_list_append(list, strdup(lang));
218                 return list;
219         }
220
221         dup_lang = strdup(lang);
222         if (dup_lang == NULL)
223                 return list;
224
225         token = strtok(dup_lang, "_");
226         if (token == NULL) {
227                 free(dup_lang);
228                 return list;
229         }
230
231         child_list = g_hash_table_lookup(table, token);
232         if (child_list == NULL) {
233                 free(dup_lang);
234                 return list;
235         }
236
237         found = g_list_find_custom(g_list_first(child_list),
238                         lang, __compare_langs);
239         if (found) {
240                 list = g_list_append(list, strdup(lang));
241                 child_list = g_list_remove_link(child_list, found);
242                 free(found->data);
243                 g_list_free(found);
244                 free(dup_lang);
245                 return list;
246         }
247
248         found = g_list_find_custom(g_list_first(child_list),
249                         token, __compare_langs);
250         if (found) {
251                 list = g_list_append(list, strdup(token));
252                 child_list = g_list_remove_link(child_list, found);
253                 free(found->data);
254                 g_list_free(found);
255                 free(dup_lang);
256                 return list;
257         }
258         free(dup_lang);
259
260         child_iter = g_list_first(child_list);
261         while (child_iter) {
262                 child_lang = (char *)child_iter->data;
263                 child_iter = g_list_next(child_iter);
264                 if (child_lang) {
265                         list = g_list_append(list, strdup(child_lang));
266                         child_list = g_list_remove(child_list, child_lang);
267                         free(child_lang);
268                         break;
269                 }
270         }
271
272         return list;
273 }
274
275 static GList *__split_language(const char *lang)
276 {
277         GList *list = NULL;
278         char *dup_lang;
279         char *token;
280
281         dup_lang = strdup(lang);
282         if (dup_lang == NULL) {
283                 _ERR("Out of memory");
284                 return NULL;
285         }
286
287         token = strtok(dup_lang, ":");
288         while (token != NULL) {
289                 list = g_list_append(list, strdup(token));
290                 token = strtok(NULL, ":");
291         }
292         free(dup_lang);
293
294         return list;
295 }
296
297 static char *__get_language(const char *lang)
298 {
299         GHashTable *table;
300         GList *list;
301         GList *lang_list = NULL;
302         GList *iter;
303         char *language;
304         char buf[LINE_MAX] = {'\0'};
305         size_t n;
306
307         list = __split_language(lang);
308         if (list == NULL)
309                 return NULL;
310
311         table = __get_lang_table();
312         if (table == NULL) {
313                 g_list_free_full(list, free);
314                 return NULL;
315         }
316
317         iter = g_list_first(list);
318         while (iter) {
319                 language = (char *)iter->data;
320                 lang_list = __append_langs(language, lang_list, table);
321                 iter = g_list_next(iter);
322         }
323         g_list_free_full(list, free);
324         g_hash_table_destroy(table);
325
326         iter = g_list_first(lang_list);
327         while (iter) {
328                 language = (char *)iter->data;
329                 if (language) {
330                         if (buf[0] == '\0') {
331                                 snprintf(buf, sizeof(buf), "%s", language);
332                         } else {
333                                 n = sizeof(buf) - strlen(buf) - 1;
334                                 strncat(buf, ":", n);
335                                 n = sizeof(buf) - strlen(buf) - 1;
336                                 strncat(buf, language, n);
337                         }
338                 }
339                 iter = g_list_next(iter);
340         }
341         g_list_free_full(lang_list, free);
342
343         n = sizeof(buf) - strlen(buf) - 1;
344         strncat(buf, ":", n);
345         n = sizeof(buf) - strlen(buf) - 1;
346         strncat(buf, "en_US:en_GB:en", n);
347
348         return strdup(buf);
349 }
350
351 static void __update_lang(void)
352 {
353         char *language;
354         char *lang;
355         char *r;
356
357         lang = vconf_get_str(VCONFKEY_LANGSET);
358         if (lang) {
359                 /* TODO: Use VCONFKEY_SETAPPL_LANGUAGES key */
360                 language = __get_language(lang);
361                 if (language) {
362                         _DBG("*****language(%s)", language);
363                         setenv("LANGUAGE", language, 1);
364                         free(language);
365                 } else {
366                         setenv("LANGUAGE", language, 1);
367                 }
368                 setenv("LANG", lang, 1);
369                 setenv("LC_MESSAGES", lang, 1);
370                 r = setlocale(LC_ALL, "");
371                 if (r == NULL) {
372                         r = setlocale(LC_ALL, lang);
373                         if (r != NULL)
374                                 _DBG("*****appcore setlocale=%s\n", r);
375                 }
376                 free(lang);
377         }
378 }
379
380 static void __update_region(void)
381 {
382         char *region;
383         char *r;
384
385         region = vconf_get_str(VCONFKEY_REGIONFORMAT);
386         if (region) {
387                 setenv("LC_CTYPE", region, 1);
388                 setenv("LC_NUMERIC", region, 1);
389                 setenv("LC_TIME", region, 1);
390                 setenv("LC_COLLATE", region, 1);
391                 setenv("LC_MONETARY", region, 1);
392                 setenv("LC_PAPER", region, 1);
393                 setenv("LC_NAME", region, 1);
394                 setenv("LC_ADDRESS", region, 1);
395                 setenv("LC_TELEPHONE", region, 1);
396                 setenv("LC_MEASUREMENT", region, 1);
397                 setenv("LC_IDENTIFICATION", region, 1);
398                 r = setlocale(LC_ALL, "");
399                 if (r != NULL)
400                         _DBG("*****appcore setlocale=%s\n", r);
401
402                 free(region);
403         }
404 }
405
406 static void __on_language_change(keynode_t *key, void *data)
407 {
408         char *val;
409
410         val = vconf_keynode_get_str(key);
411
412         __update_lang();
413         __invoke_callback((void *)val, APPCORE_BASE_EVENT_LANG_CHANGE);
414 }
415
416 static void __on_region_change(keynode_t *key, void *data)
417 {
418         char *val = NULL;
419         const char *name;
420
421         name = vconf_keynode_get_name(key);
422         if (!strcmp(name, VCONFKEY_REGIONFORMAT))
423                 val = vconf_keynode_get_str(key);
424
425         __update_region();
426         __invoke_callback((void *)val, APPCORE_BASE_EVENT_REGION_CHANGE);
427 }
428
429 static gboolean __flush_memory(gpointer data)
430 {
431         int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
432
433         appcore_base_flush_memory();
434         __context.tid = 0;
435
436         if (!__context.allowed_bg && !__context.suspended_state) {
437                 _DBG("[__SUSPEND__] flush case");
438                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
439                 __context.suspended_state = true;
440         }
441
442         return FALSE;
443 }
444
445 static void __add_suspend_timer(void)
446 {
447         __context.tid = g_timeout_add_seconds(5, __flush_memory, NULL);
448 }
449
450 static void __remove_suspend_timer(void)
451 {
452         if (__context.tid > 0) {
453                 g_source_remove(__context.tid);
454                 __context.tid = 0;
455         }
456 }
457
458 static void __on_receive_suspend_signal(GDBusConnection *connection,
459                                         const gchar *sender_name,
460                                         const gchar *object_path,
461                                         const gchar *interface_name,
462                                         const gchar *signal_name,
463                                         GVariant *parameters,
464                                         gpointer user_data)
465 {
466         gint suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
467         gint pid;
468         gint status;
469
470         if (g_strcmp0(signal_name, RESOURCED_FREEZER_SIGNAL) == 0) {
471                 g_variant_get(parameters, "(ii)", &status, &pid);
472                 if (pid == getpid() && status == 0) {
473                         if (!__context.allowed_bg && __context.suspended_state) {
474                                 __remove_suspend_timer();
475                                 __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
476                                 __context.suspended_state = false;
477                                 __add_suspend_timer();
478                         }
479                 }
480         }
481 }
482
483 static int __init_suspend_dbus_handler(void)
484 {
485         GError *err = NULL;
486
487         if (__suspend_dbus_handler_initialized)
488                 return 0;
489
490         if (!__bus) {
491                 __bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
492                 if (!__bus) {
493                         _ERR("Failed to connect to the D-BUS daemon: %s",
494                                                 err->message);
495                         g_error_free(err);
496                         return -1;
497                 }
498         }
499
500         __suspend_dbus_handler_initialized = g_dbus_connection_signal_subscribe(
501                                                 __bus,
502                                                 NULL,
503                                                 RESOURCED_FREEZER_INTERFACE,
504                                                 RESOURCED_FREEZER_SIGNAL,
505                                                 RESOURCED_FREEZER_PATH,
506                                                 NULL,
507                                                 G_DBUS_SIGNAL_FLAGS_NONE,
508                                                 __on_receive_suspend_signal,
509                                                 NULL,
510                                                 NULL);
511         if (__suspend_dbus_handler_initialized == 0) {
512                 _ERR("g_dbus_connection_signal_subscribe() is failed.");
513                 return -1;
514         }
515
516         _DBG("[__SUSPEND__] suspend signal initialized");
517
518         return 0;
519 }
520
521 static void __fini_suspend_dbus_handler(void)
522 {
523         if (__bus == NULL)
524                 return;
525
526         if (__suspend_dbus_handler_initialized) {
527                 g_dbus_connection_signal_unsubscribe(__bus,
528                                 __suspend_dbus_handler_initialized);
529                 __suspend_dbus_handler_initialized = 0;
530         }
531
532         g_object_unref(__bus);
533         __bus = NULL;
534 }
535
536 static int __get_locale_resource_dir(char *locale_dir, int size)
537 {
538         const char *res_path;
539
540         res_path = aul_get_app_resource_path();
541         if (res_path == NULL) {
542                 _ERR("Failed to get resource path");
543                 return -1;
544         }
545
546         snprintf(locale_dir, size, "%s" PATH_LOCALE, res_path);
547         if (access(locale_dir, R_OK) != 0)
548                 return -1;
549
550         return 0;
551 }
552
553 static int __get_app_name(const char *appid, char **name)
554 {
555         char *name_token = NULL;
556
557         if (appid == NULL)
558                 return -1;
559
560         /* com.vendor.name -> name */
561         name_token = strrchr(appid, '.');
562         if (name_token == NULL)
563                 return -1;
564
565         name_token++;
566
567         *name = strdup(name_token);
568         if (*name == NULL)
569                 return -1;
570
571         return 0;
572 }
573
574 static int __set_i18n(const char *domain, const char *dir)
575 {
576         char *r;
577         char *lan;
578
579         if (domain == NULL) {
580                 errno = EINVAL;
581                 return -1;
582         }
583
584         __update_lang();
585         __update_region();
586
587         r = setlocale(LC_ALL, "");
588         /* if locale is not set properly, try again to set as language base */
589         if (r == NULL) {
590                 lan = vconf_get_str(VCONFKEY_LANGSET);
591                 if (lan != NULL) {
592                         r = setlocale(LC_ALL, lan);
593                         _DBG("*****appcore setlocale=%s\n", r);
594                         free(lan);
595                 }
596         }
597         if (r == NULL)
598                 _ERR("appcore: setlocale() error");
599
600         if (dir) {
601                 if (__locale_dir)
602                         free(__locale_dir);
603                 __locale_dir = strdup(dir);
604         }
605
606         r = bindtextdomain(domain, dir);
607         if (r == NULL)
608                 _ERR("appcore: bindtextdomain() error");
609
610         r = textdomain(domain);
611         if (r == NULL)
612                 _ERR("appcore: textdomain() error");
613
614         return 0;
615 }
616
617 EXPORT_API int appcore_base_on_set_i18n(void)
618 {
619         int r;
620         char locale_dir[PATH_MAX];
621         char appid[PATH_MAX];
622         char *name = NULL;
623
624         r = aul_app_get_appid_bypid(getpid(), appid, PATH_MAX);
625         if (r < 0)
626                 return -1;
627
628         r = __get_app_name(appid, &name);
629         if (r < 0)
630                 return -1;
631
632         r = __get_locale_resource_dir(locale_dir, sizeof(locale_dir));
633         if (r < 0) {
634                 free(name);
635                 return -1;
636         }
637
638         r = __set_i18n(name, locale_dir);
639         if (r < 0) {
640                 free(name);
641                 return -1;
642         }
643
644         free(name);
645
646         return 0;
647 }
648
649 EXPORT_API int appcore_base_init(appcore_base_ops ops, int argc, char **argv, void *data)
650 {
651         __context.ops = ops;
652         __context.argc = argc;
653         __context.argv = argv;
654         __context.data = data;
655         __context.tid = 0;
656         __context.suspended_state = false;
657         __context.allowed_bg = false;
658
659         if (__context.ops.set_i18n)
660                 __context.ops.set_i18n(__context.data);
661
662         __init_suspend_dbus_handler();
663
664         if (__context.ops.create && __context.ops.create(__context.data) < 0) {
665                 aul_status_update(STATUS_DYING);
666                 return 0;
667         }
668
669         if (__context.ops.run)
670                 __context.ops.run(__context.data);
671
672         return 0;
673 }
674
675 EXPORT_API void appcore_base_fini(void)
676 {
677         int i;
678
679         for (i = APPCORE_BASE_EVENT_START + 1; i < APPCORE_BASE_EVENT_MAX; i++) {
680                 if (__exist_callback(i)) {
681                         if (__context.ops.unset_event)
682                                 __context.ops.unset_event(i, __context.data);
683                 }
684         }
685
686         g_list_free_full(__events, free);
687         __events = NULL;
688         __fini_suspend_dbus_handler();
689
690         aul_status_update(STATUS_DYING);
691         if (__context.ops.terminate)
692                 __context.ops.terminate(__context.data);
693
694         if (__locale_dir) {
695                 free(__locale_dir);
696                 __locale_dir = NULL;
697         }
698 }
699
700 EXPORT_API int appcore_base_flush_memory(void)
701 {
702         malloc_trim(0);
703         return 0;
704 }
705
706 EXPORT_API int appcore_base_on_receive(aul_type type, bundle *b)
707 {
708         int ret;
709         const char **tep_path;
710         int len = 0;
711         int i;
712         const char *bg;
713         int dummy = 0;
714
715         switch (type) {
716         case AUL_START:
717                 _DBG("[APP %d]     AUL event: AUL_START", getpid());
718                 tep_path = bundle_get_str_array(b, AUL_TEP_PATH, &len);
719                 if (tep_path) {
720                         for (i = 0; i < len; i++) {
721                                 ret = aul_check_tep_mount(tep_path[i]);
722                                 if (ret == -1) {
723                                         _ERR("mount request not completed within 1 sec");
724                                         exit(-1);
725                                 }
726                         }
727                 }
728
729                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
730                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
731                         _DBG("[__SUSPEND__] allowed background");
732                         __context.allowed_bg = true;
733                         __remove_suspend_timer();
734                 }
735
736                 if (__context.ops.control)
737                        __context.ops.control(b, __context.data);
738                 break;
739         case AUL_RESUME:
740                 _DBG("[APP %d]     AUL event: AUL_RESUME", getpid());
741                 bg = bundle_get_val(b, AUL_K_ALLOWED_BG);
742                 if (bg && strncmp(bg, "ALLOWED_BG", strlen("ALLOWED_BG")) == 0) {
743                         _DBG("[__SUSPEND__] allowed background");
744                         __context.allowed_bg = true;
745                         __remove_suspend_timer();
746                 }
747                 break;
748         case AUL_TERMINATE:
749                 _DBG("[APP %d]     AUL event: AUL_TERMINATE", getpid());
750                 aul_status_update(STATUS_DYING);
751                 if (!__context.allowed_bg)
752                         __remove_suspend_timer();
753
754                 if (__context.ops.exit)
755                         __context.ops.exit(__context.data);
756                 break;
757         case AUL_TERMINATE_BGAPP:
758                 _DBG("[APP %d]     AUL event: AUL_TERMINATE_BGAPP", getpid());
759                 if (!__context.allowed_bg)
760                         __remove_suspend_timer();
761                 break;
762         case AUL_WAKE:
763                 _DBG("[APP %d]     AUL event: AUL_WAKE", getpid());
764                 if (!__context.allowed_bg && __context.suspended_state) {
765                         int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
766                         __remove_suspend_timer();
767                         __invoke_callback((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
768                         __context.suspended_state = false;
769                 }
770                 break;
771         case AUL_SUSPEND:
772                 _DBG("[APP %d]     AUL event: AUL_SUSPEND", getpid());
773                 if (!__context.allowed_bg && !__context.suspended_state) {
774                         __remove_suspend_timer();
775                         __flush_memory(NULL);
776                 }
777                 break;
778         case AUL_UPDATE_REQUESTED:
779                 _DBG("[APP %d]     AUL event: AUL_UPDATE_REQUESTED", getpid());
780                 __invoke_callback((void *)&dummy, APPCORE_BASE_EVENT_UPDATE_REQUESTED);
781                 break;
782         default:
783                 _DBG("[APP %d]     AUL event: %d", getpid(), type);
784                 /* do nothing */
785                 break;
786         }
787
788         return 0;
789 }
790
791 EXPORT_API int appcore_base_on_create(void)
792 {
793         int r;
794         r = aul_launch_init(__context.ops.receive, NULL);
795         if (r < 0) {
796                 _ERR("Aul init failed: %d", r);
797                 return -1;
798         }
799
800         r = aul_launch_argv_handler(__context.argc, __context.argv);
801         if (r < 0) {
802                 _ERR("Aul argv handler failed: %d", r);
803                 return -1;
804         }
805
806         return 0;
807 }
808
809 EXPORT_API int appcore_base_on_control(bundle *b)
810 {
811         return 0;
812 }
813
814 EXPORT_API int appcore_base_on_terminate()
815 {
816         aul_finalize();
817         if (__context.ops.exit)
818                 __context.ops.exit(__context.data);
819
820         return 0;
821 }
822
823 EXPORT_API void appcore_base_on_set_event(enum appcore_base_event event)
824 {
825         int r;
826
827         switch (event) {
828         case APPCORE_BASE_EVENT_LOW_MEMORY:
829                 vconf_notify_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory, NULL);
830                 break;
831         case APPCORE_BASE_EVENT_LOW_BATTERY:
832                 vconf_notify_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery, NULL);
833                 break;
834         case APPCORE_BASE_EVENT_LANG_CHANGE:
835                 vconf_notify_key_changed(VCONFKEY_LANGSET, __on_language_change, NULL);
836                 break;
837         case APPCORE_BASE_EVENT_REGION_CHANGE:
838                 r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change, NULL);
839                 if (r < 0)
840                         break;
841
842                 vconf_notify_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change, NULL);
843                 break;
844         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
845                 break;
846
847         default:
848                 break;
849         }
850
851 }
852
853 EXPORT_API void appcore_base_on_unset_event(enum appcore_base_event event)
854 {
855         int r;
856
857         switch (event) {
858         case APPCORE_BASE_EVENT_LOW_MEMORY:
859                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_LOW_MEMORY, __on_low_memory);
860                 break;
861         case APPCORE_BASE_EVENT_LOW_BATTERY:
862                 vconf_ignore_key_changed(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, __on_low_battery);
863                 break;
864         case APPCORE_BASE_EVENT_LANG_CHANGE:
865                 vconf_ignore_key_changed(VCONFKEY_LANGSET, __on_language_change);
866                 break;
867         case APPCORE_BASE_EVENT_REGION_CHANGE:
868                 r = vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT, __on_region_change);
869                 if (r < 0)
870                         break;
871                 vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT_TIME1224, __on_region_change);
872                 break;
873         case APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE:
874                 break;
875         default:
876                 break;
877         }
878 }
879
880 EXPORT_API appcore_base_event_h appcore_base_add_event(enum appcore_base_event event,
881                 appcore_base_event_cb cb, void *data)
882 {
883         appcore_base_event_node *node;
884
885         if (!__exist_callback(event)) {
886                 if (__context.ops.set_event)
887                         __context.ops.set_event(event, __context.data);
888         }
889
890         node = malloc(sizeof(appcore_base_event_node));
891
892         if (node == NULL)
893                 return NULL;
894
895         node->cb = cb;
896         node->type = event;
897         node->data = data;
898         __events = g_list_append(__events, node);
899
900         return node;
901 }
902
903 EXPORT_API int appcore_base_remove_event(appcore_base_event_h handle)
904 {
905         appcore_base_event_node *node = handle;
906         enum appcore_base_event event;
907
908         event = node->type;
909         __events = g_list_remove(__events, node);
910         free(node);
911         if (!__exist_callback(event)) {
912                 if (__context.ops.unset_event)
913                         __context.ops.unset_event(event, __context.data);
914         }
915
916         return 0;
917 }
918
919 EXPORT_API int appcore_base_raise_event(void *event, enum appcore_base_event type)
920 {
921         __invoke_callback(event, type);
922         return 0;
923 }
924
925 EXPORT_API int appcore_base_get_rotation_state(enum appcore_base_rm *curr)
926 {
927         return 0;
928 }
929
930 EXPORT_API bool appcore_base_is_bg_allowed(void)
931 {
932         return __context.allowed_bg;
933 }
934
935 EXPORT_API bool appcore_base_is_suspended(void)
936 {
937         return __context.suspended_state;
938 }
939
940 EXPORT_API void appcore_base_toggle_suspended_state(void)
941 {
942         __context.suspended_state ^= __context.suspended_state;
943 }
944
945 static int __on_receive(aul_type type, bundle *b, void *data)
946 {
947         return appcore_base_on_receive(type, b);
948 }
949
950 static int __on_create(void *data)
951 {
952         return appcore_base_on_create();
953 }
954
955 static int __on_control(bundle *b, void *data)
956 {
957         return appcore_base_on_control(b);
958 }
959
960 static int __on_terminate(void *data)
961 {
962         return appcore_base_on_terminate();
963 }
964
965 static int __on_set_i18n(void *data)
966 {
967         return appcore_base_on_set_i18n();
968 }
969
970 static void __on_set_event(enum appcore_base_event event, void *data)
971 {
972         return appcore_base_on_set_event(event);
973 }
974
975 static void __on_unset_event(enum appcore_base_event event, void *data)
976 {
977         return appcore_base_on_unset_event(event);
978 }
979
980 EXPORT_API appcore_base_ops appcore_base_get_default_ops(void)
981 {
982         appcore_base_ops ops;
983
984         ops.create = __on_create;
985         ops.control = __on_control;
986         ops.terminate = __on_terminate;
987         ops.receive = __on_receive;
988         ops.set_i18n = __on_set_i18n;
989         ops.run = NULL;
990         ops.exit = NULL;
991         ops.set_event = __on_set_event;
992         ops.unset_event = __on_unset_event;
993
994         return ops;
995 }
996
997