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