2 * Copyright 2018-2019 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.1 (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
8 * http://floralicense.org/license/
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.
18 #include <service_app.h>
19 #include <app_manager.h>
25 #include <package_manager.h>
26 #include <pkgmgr-info.h>
33 #include "multi_assistant_main.h"
34 #include "multi_assistant_service_client.h"
35 #include "multi_assistant_service_plugin.h"
36 #include "multi_assistant_dbus.h"
37 #include "multi_assistant_config.h"
39 static const char *g_current_lang = "en_US";
41 #define ENABLE_MULTI_ASSISTANT_BY_DEFAULT
43 #define MULTI_ASSISTANT_SETTINGS_ACTIVATED "db/multi-assistant/activated"
44 #define WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID "db/multi-assistant/preprocessing_assistant_appid"
45 #define WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE "db/multi-assistant/prelaunch_mode"
47 #define MAX_MACLIENT_INFO_NUM 16
48 #define MAX_WAKEUP_WORDS_NUM 255
49 #define MAX_WAKEUP_WORD_LEN 32
50 #define MAX_SUPPORTED_LANGUAGES_NUM 255
51 #define MAX_SUPPORTED_LANGUAGE_LEN 16
54 char appid[MAX_APPID_LEN];
55 char wakeup_word[MAX_WAKEUP_WORDS_NUM][MAX_WAKEUP_WORD_LEN];
56 char wakeup_language[MAX_WAKEUP_WORDS_NUM][MAX_SUPPORTED_LANGUAGE_LEN];
57 char wakeup_engine[MAX_APPID_LEN];
58 char supported_language[MAX_SUPPORTED_LANGUAGES_NUM][MAX_SUPPORTED_LANGUAGE_LEN];
59 bool custom_ui_option;
61 ma_preprocessing_allow_mode_e preprocessing_allow_mode;
62 char preprocessing_allow_appid[MAX_APPID_LEN];
65 static ma_client_info g_maclient_info[MAX_MACLIENT_INFO_NUM];
69 char appid[MAX_APPID_LEN];
72 static int g_current_maclient_info = 0;
73 static int g_current_preprocessing_maclient_info = -1;
74 static const char *g_wakeup_maclient_appid = NULL;
75 static package_manager_h g_pkgmgr = NULL;
77 static PREPROCESSING_STATE g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
80 static GSList* g_client_list = NULL;
82 int ma_client_create(ma_client_s *info)
85 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
89 ma_client_s* data = NULL;
91 data = (ma_client_s*)calloc(1, sizeof(ma_client_s));
93 MAS_LOGE("[ERROR] Fail to allocate memory"); //LCOV_EXCL_LINE
94 return -1;// MA_ERROR_OUT_OF_MEMORY;
99 g_client_list = g_slist_append(g_client_list, data);
104 int ma_client_destroy(ma_client_s *client)
106 if (NULL == client) {
107 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
108 return -1;// MA_ERROR_OPERATION_FAILED;
111 g_client_list = g_slist_remove(g_client_list, client);
119 ma_client_s* ma_client_find_by_appid(const char *appid)
122 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
126 ma_client_s *data = NULL;
128 int count = g_slist_length(g_client_list);
131 for (i = 0; i < count; i++) {
132 data = g_slist_nth_data(g_client_list, i);
135 if (0 == strncmp(data->appid, appid, MAX_APPID_LEN)) {
141 MAS_LOGE("[ERROR] client Not found");
146 ma_client_s* ma_client_find_by_pid(int pid)
148 ma_client_s *data = NULL;
150 int count = g_slist_length(g_client_list);
153 for (i = 0; i < count; i++) {
154 data = g_slist_nth_data(g_client_list, i);
157 if (data->pid == pid) {
163 MAS_LOGE("[ERROR] client Not found");
168 bool check_preprocessing_assistant_exists()
172 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
174 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
175 if (g_maclient_info[loop].used) {
176 if (strncmp(vconf_str, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
177 ma_client_s* client = ma_client_find_by_appid(vconf_str);
178 if (client && client->pid > 0) {
188 MAS_LOGD("result : %d", ret);
193 bool is_current_preprocessing_assistant(const char* appid)
195 if (NULL == appid) return false;
199 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
201 if (strncmp(vconf_str, appid, MAX_APPID_LEN) == 0) {
211 int mas_client_initialize(int pid)
213 MAS_LOGD("[Enter] pid(%d)", pid);
215 char appid[MAX_APPID_LEN] = {'\0',};
216 if (AUL_R_OK == aul_app_get_appid_bypid(pid, appid, sizeof(appid))) {
217 appid[MAX_APPID_LEN - 1] = '\0';
219 MAS_LOGD("appid for pid %d is : %s", pid, (appid ? appid : "Unknown"));
221 /* Remove existing client that has same appid, if there's any */
222 ma_client_s *old_client = NULL;
223 old_client = ma_client_find_by_appid(appid);
225 ma_client_destroy(old_client);
229 /* And remove a client that has same pid also */
230 old_client = ma_client_find_by_pid(pid);
232 ma_client_destroy(old_client);
236 ma_client_s new_client;
237 new_client.pid = pid;
238 strncpy(new_client.appid, appid, MAX_APPID_LEN);
239 new_client.appid[MAX_APPID_LEN - 1] = '\0';
240 ma_client_create(&new_client);
242 const char *current_maclient_appid = NULL;
243 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
244 current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
247 mas_client_send_preprocessing_information(pid);
248 if (current_maclient_appid && 0 == strncmp(current_maclient_appid, appid, MAX_APPID_LEN)) {
249 MAS_LOGD("MA client with current maclient appid connected!");
251 if (g_wakeup_maclient_appid && strncmp(g_wakeup_maclient_appid, appid, MAX_APPID_LEN) == 0) {
252 g_wakeup_maclient_appid = NULL;
253 mas_client_activate(pid);
254 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED);
256 MAS_LOGE("[ERROR] g_wakeup_maclient_appid and appid differ : %s %s",
257 (g_wakeup_maclient_appid ? g_wakeup_maclient_appid : "NULL"), appid);
260 MAS_LOGD("MA client connected, but its appid does not match with current maclient");
263 MAS_LOGE("[ERROR] Fail to retrieve appid");
269 int mas_client_deinitialize(int pid)
271 MAS_LOGD("[Enter] pid(%d)", pid);
272 ma_client_s *client = ma_client_find_by_pid(pid);
274 ma_client_destroy(client);
280 int mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type)
282 MAS_LOGD("[Enter] pid(%d)", pid);
284 int ret = multi_assistant_service_plugin_get_recording_audio_format(rate, channel, audio_type);
286 MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret);
292 int mas_client_get_audio_source_type(int pid, char** type)
294 MAS_LOGD("[Enter] pid(%d)", pid);
296 int ret = multi_assistant_service_plugin_get_recording_audio_source_type(type);
298 MAS_LOGE("[ERROR] Fail to get recording audio source type, ret(%d)", ret);
304 int mas_client_send_preprocessing_information(int pid)
307 MAS_LOGD("[Enter] pid(%d)", pid);
309 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
310 MAS_LOGD("preprocessing_assistant_appid : %s", vconf_str);
312 ret = masc_dbus_send_preprocessing_information(pid, vconf_str);
320 int mas_client_activate(int pid)
323 MAS_LOGD("[Enter] pid(%d)", pid);
325 ret = masc_dbus_active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
330 int mas_client_deactivate(int pid)
333 MAS_LOGD("[Enter] pid(%d)", pid);
335 ret = masc_dbus_active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
340 int mas_client_send_asr_result(int pid, int event, char* asr_result)
342 MAS_LOGD("[Enter] pid(%d), event(%d), asr_result(%s)", pid, event, asr_result);
343 int ret = masc_ui_dbus_send_asr_result(pid, event, asr_result);
345 MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret);
348 // if final event is , launch assistant app which is invoked with wakeup word.
353 int mas_client_send_result(int pid, char* display_text, char* utterance_text, char* result_json)
355 MAS_LOGD("[Enter] pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json);
356 int ret = masc_ui_dbus_send_result(pid, display_text, utterance_text, result_json);
358 MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret);
361 const char* pid_appid = NULL;
362 char buf[MAX_APPID_LEN] = {'\0',};
363 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
364 buf[MAX_APPID_LEN - 1] = '\0';
367 multi_assistant_service_plugin_update_recognition_result(pid_appid, MA_RECOGNITION_RESULT_EVENT_SUCCESS);
372 int mas_client_send_recognition_result(int pid, int result)
374 MAS_LOGD("[Enter] pid(%d), result(%d)", pid, result);
375 int ret = masc_ui_dbus_send_recognition_result(pid, result);
377 MAS_LOGE("[ERROR] Fail to send recognition result, ret(%d)", ret);
380 const char* pid_appid = NULL;
381 char buf[MAX_APPID_LEN] = {'\0',};
382 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
383 buf[MAX_APPID_LEN - 1] = '\0';
386 multi_assistant_service_plugin_update_recognition_result(pid_appid, result);
391 int mas_client_start_streaming_audio_data(int pid, int type)
395 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
396 ret = multi_assistant_service_plugin_start_streaming_utterance_data();
397 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED);
399 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
400 ret = multi_assistant_service_plugin_start_streaming_previous_utterance_data();
401 /* Preprocessing is not required for previous utterance streaming */
403 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
404 ret = multi_assistant_service_plugin_start_streaming_follow_up_data();
405 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED);
411 int mas_client_stop_streaming_audio_data(int pid, int type)
415 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
416 ret = multi_assistant_service_plugin_stop_streaming_utterance_data();
418 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
419 ret = multi_assistant_service_plugin_stop_streaming_previous_utterance_data();
421 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
422 ret = multi_assistant_service_plugin_stop_streaming_follow_up_data();
428 int mas_client_update_voice_feedback_state(int pid, int state)
430 const char* pid_appid = NULL;
431 char buf[MAX_APPID_LEN] = {'\0',};
432 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
433 buf[MAX_APPID_LEN - 1] = '\0';
436 multi_assistant_service_plugin_update_voice_feedback_state(pid_appid, state);
440 int mas_client_send_assistant_specific_command(int pid, const char *command)
442 const char* pid_appid = NULL;
443 char buf[MAX_APPID_LEN] = {'\0',};
444 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
445 buf[MAX_APPID_LEN - 1] = '\0';
448 multi_assistant_service_plugin_send_assistant_specific_command(pid_appid, command);
452 int mas_client_set_background_volume(int pid, double ratio)
454 const char* pid_appid = NULL;
455 char buf[MAX_APPID_LEN] = {'\0',};
456 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
457 buf[MAX_APPID_LEN - 1] = '\0';
460 multi_assistant_service_plugin_set_background_volume(pid_appid, ratio);
464 int mas_client_set_preprocessing_allow_mode(int pid, int mode, const char* appid)
466 const char* pid_appid = NULL;
467 char buf[MAX_APPID_LEN] = {'\0',};
468 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
469 buf[MAX_APPID_LEN - 1] = '\0';
473 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
474 if (g_maclient_info[loop].used) {
475 if (pid_appid && strncmp(pid_appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
476 g_maclient_info[loop].preprocessing_allow_mode = mode;
478 strncpy(g_maclient_info[loop].preprocessing_allow_appid, appid, MAX_APPID_LEN);
479 g_maclient_info[loop].preprocessing_allow_appid[MAX_APPID_LEN - 1] = '\0';
481 g_maclient_info[loop].preprocessing_allow_appid[0] = '\0';
487 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED);
492 int mas_client_send_preprocessing_result(int pid, bool result)
494 const char* pid_appid = NULL;
495 char buf[MAX_APPID_LEN] = {'\0',};
496 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
497 buf[MAX_APPID_LEN - 1] = '\0';
500 if (!is_current_preprocessing_assistant(pid_appid)) return -1;
502 const char *current_maclient_appid = NULL;
503 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
504 current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
508 MAS_LOGD("Preprocessing succeeded, bring (%s) to foreground", pid_appid);
509 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED);
511 MAS_LOGD("Preprocessing failed, bring (%s) to foreground", current_maclient_appid);
512 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED);
515 ma_client_s* client = ma_client_find_by_appid(current_maclient_appid);
517 masc_dbus_send_preprocessing_result(client->pid, result);
523 int mas_client_set_wake_word_audio_require_flag(int pid, bool require)
525 const char* pid_appid = NULL;
526 char buf[MAX_APPID_LEN] = {'\0',};
527 if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
528 buf[MAX_APPID_LEN - 1] = '\0';
532 multi_assistant_service_plugin_set_wake_word_audio_require_flag(pid_appid, require);
536 int mas_client_set_assistant_language(int pid, const char* language)
538 const char* pid_appid = NULL;
539 char buf[MAX_APPID_LEN] = {'\0',};
540 int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
541 if (AUL_R_OK == ret) {
542 buf[MAX_APPID_LEN - 1] = '\0';
546 multi_assistant_service_plugin_assistant_language(pid_appid, language);
550 int mas_ui_client_initialize(int pid)
552 MAS_LOGD("[Enter] pid(%d)", pid);
557 int mas_ui_client_deinitialize(int pid)
559 MAS_LOGD("[Enter] pid(%d)", pid);
564 int mas_ui_client_change_assistant(const char* appid)
569 MAS_LOGE("NULL parameter");
573 bool use_custom_ui = mas_get_client_custom_ui_option_by_appid(appid);
574 masc_ui_dbus_enable_common_ui(!use_custom_ui);
576 mas_set_current_client_by_appid(appid);
577 int pid = mas_get_client_pid_by_appid(appid);
579 mas_bring_client_to_foreground(appid);
580 mas_client_send_preprocessing_information(pid);
581 mas_client_activate(pid);
582 MAS_LOGD("MA Client with appid %s exists, requesting speech data", (appid ? appid : "NULL"));
584 int ret = multi_assistant_service_plugin_start_streaming_utterance_data();
586 MAS_LOGE("[ERROR] Fail to start streaming utterance data(%d)", ret);
590 // Appropriate MA Client not available, trying to launch new one
591 MAS_LOGD("MA Client with appid %s does not exist, launching client", (appid ? appid : "NULL"));
593 /* The appid parameter might not exist after this function call, so we use appid string in our g_maclient_info */
594 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
595 if (g_maclient_info[loop].used &&
596 0 < strlen(g_maclient_info[loop].appid) &&
597 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
598 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
599 mas_launch_client_by_appid(g_maclient_info[loop].appid, CLIENT_LAUNCH_MODE_ACTIVATION);
608 int __mas_assistant_info_cb(const char* appid, const char* name, const char* icon_path,
609 const char* wakeup_list[], const char* wakeup_language[], int cnt_wakeup,
610 const char* supported_lang[], int cnt_lang, const char* wakeup_engine,
611 bool custom_ui_option, void* user_data) {
612 MAS_LOGD("__mas_assistant_info_cb called");
615 MAS_LOGD("app_id NULL, returning");
621 while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) {
622 if (false == g_maclient_info[loop].used) {
628 g_maclient_info[index].used = true;
629 g_maclient_info[index].preprocessing_allow_mode = MA_PREPROCESSING_ALLOW_NONE;
630 g_maclient_info[index].preprocessing_allow_appid[0] = '\0';
631 MAS_LOGD("app_id(%s)", appid);
632 strncpy(g_maclient_info[index].appid, appid, MAX_APPID_LEN);
633 g_maclient_info[index].appid[MAX_APPID_LEN - 1] = '\0';
635 if (is_current_preprocessing_assistant(g_maclient_info[index].appid)) {
636 g_current_preprocessing_maclient_info = index;
639 for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
640 if (loop < cnt_wakeup && wakeup_list[loop]) {
641 MAS_LOGD("wakeup_list(%d)(%s)(%s)", loop, wakeup_list[loop], wakeup_language[loop]);
642 strncpy(g_maclient_info[index].wakeup_word[loop], wakeup_list[loop], MAX_WAKEUP_WORD_LEN);
643 g_maclient_info[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
644 if (wakeup_language[loop]) {
645 strncpy(g_maclient_info[index].wakeup_language[loop], wakeup_language[loop], MAX_SUPPORTED_LANGUAGE_LEN);
646 g_maclient_info[index].wakeup_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
648 strncpy(g_maclient_info[index].wakeup_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
651 strncpy(g_maclient_info[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN);
655 for (loop = 0;loop < MAX_SUPPORTED_LANGUAGES_NUM;loop++) {
656 if (loop < cnt_lang && supported_lang[loop]) {
657 MAS_LOGD("supported_lang(%d)(%s)", loop, supported_lang[loop]);
658 strncpy(g_maclient_info[index].supported_language[loop], supported_lang[loop], MAX_SUPPORTED_LANGUAGE_LEN);
659 g_maclient_info[index].supported_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
661 strncpy(g_maclient_info[index].supported_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
665 MAS_LOGD("wakeup_engine(%s)", wakeup_engine);
667 strncpy(g_maclient_info[index].wakeup_engine, wakeup_engine, MAX_APPID_LEN);
668 g_maclient_info[index].wakeup_engine[MAX_APPID_LEN - 1] = '\0';
670 g_maclient_info[index].wakeup_engine[0] = '\0';
671 MAS_LOGW("Wakeup engine information not provided for : %s", appid);
673 g_maclient_info[index].custom_ui_option = custom_ui_option;
675 MAS_LOGD("Couldn't find an empty slot for storing assistant info");
678 MAS_LOGD("__mas_assistant_info_cb end");
683 static void mas_active_state_changed_cb(keynode_t* key, void* data)
686 if (vconf_get_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED, &vconf_value) == 0) {
687 MAS_LOGD("multi-assistant active state : %d\n", vconf_value);
690 multi_assistant_service_plugin_activate();
692 multi_assistant_service_plugin_deactivate();
697 static int init_plugin(void)
699 if (0 != multi_assistant_service_plugin_initialize()) {
700 MAS_LOGE("Fail to ws intialize");
704 if (0 != multi_assistant_service_plugin_set_language(g_current_lang)) {
705 MAS_LOGE("Fail to ws set language");
709 if (0 == mas_config_get_assistant_info(__mas_assistant_info_cb, NULL)) {
710 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
712 if (g_maclient_info[loop].used &&
713 0 < strlen(g_maclient_info[loop].appid)) {
714 if (0 < strlen(g_maclient_info[loop].wakeup_engine)) {
715 multi_assistant_service_plugin_set_assistant_wakeup_engine(
716 g_maclient_info[loop].appid,
717 g_maclient_info[loop].wakeup_engine);
719 for (inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
720 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
721 MAS_LOGD("Registering wakeup word %s for app %s",
722 g_maclient_info[loop].wakeup_word[inner_loop], g_maclient_info[loop].appid);
723 if (0 != multi_assistant_service_plugin_add_assistant_wakeup_word(
724 g_maclient_info[loop].appid,
725 g_maclient_info[loop].wakeup_word[inner_loop],
726 g_maclient_info[loop].wakeup_language[inner_loop])) {
727 MAS_LOGE("Fail to add assistant's wakeup word");
731 for (inner_loop = 0; inner_loop < MAX_SUPPORTED_LANGUAGE_NUM; inner_loop++) {
732 if (0 < strlen(g_maclient_info[loop].supported_language[inner_loop])) {
733 MAS_LOGD("Adding language %s for app %s",
734 g_maclient_info[loop].supported_language[inner_loop], g_maclient_info[loop].appid);
735 if (0 != multi_assistant_service_plugin_add_assistant_language(
736 g_maclient_info[loop].appid,
737 g_maclient_info[loop].supported_language[inner_loop])) {
738 MAS_LOGE("Fail to add assistant's language");
745 MAS_LOGE("Fail to load assistant info");
748 if (0 != multi_assistant_service_plugin_set_callbacks()) {
749 MAS_LOGE("Fail to set callbacks");
756 static int deinit_plugin(void)
759 if (0 != multi_assistant_service_plugin_deactivate()) {
760 MAS_LOGE("Fail to deactivate");
762 if (0 != multi_assistant_service_plugin_deinitialize()) {
763 MAS_LOGE("Fail to deinitialize");
769 static int process_activated_setting()
771 if (0 == vconf_notify_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, mas_active_state_changed_cb, NULL)) {
772 /* Activate / deactivate according to the vconf key setting */
773 mas_active_state_changed_cb(NULL, NULL);
775 #ifdef ENABLE_MULTI_ASSISTANT_BY_DEFAULT
776 /* Multi-assistant needs to be enabled by default, unless disabled explicitly */
777 multi_assistant_service_plugin_activate();
778 const char *default_assistant = NULL;
779 if (0 == multi_assistant_service_plugin_get_default_assistant(&default_assistant)) {
780 if (NULL == default_assistant) {
781 if (g_maclient_info[0].used) {
782 default_assistant = g_maclient_info[0].appid;
783 MAS_LOGW("No default assistant, setting %s as default", default_assistant);
784 multi_assistant_service_plugin_set_default_assistant(default_assistant);
786 MAS_LOGE("No default assistant, and no assistant installed");
795 static int init_wakeup(void)
797 MAS_LOGD("[Enter] init_wakeup");
799 int ret = mas_dbus_open_connection();
801 MAS_LOGE("[ERROR] Fail to open connection");
806 process_activated_setting();
808 mas_prelaunch_default_assistant();
810 /* For the case of preprocessing assistant, it always have to be launched beforehand */
812 vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
814 MAS_LOGD("prelaunching preprocessing_assistant_appid : %s", vconf_str);
815 mas_launch_client_by_appid(vconf_str, CLIENT_LAUNCH_MODE_PRELAUNCH);
823 static void deinit_wakeup(void)
825 MAS_LOGI("[Enter] deinit_wakeup");
827 /* if (NULL != g_current_lang) {
828 free(g_current_lang);
829 g_current_lang = NULL;
834 vconf_ignore_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, mas_active_state_changed_cb);
836 int ret = mas_dbus_close_connection();
838 MAS_LOGE("[ERROR] Fail to close connection");
843 int mas_get_current_client_pid()
846 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
847 const char *appid = g_maclient_info[g_current_maclient_info].appid;
848 ma_client_s* client = ma_client_find_by_appid(appid);
856 int mas_get_current_preprocessing_client_pid()
859 if (g_current_preprocessing_maclient_info >= 0 && g_current_preprocessing_maclient_info < MAX_MACLIENT_INFO_NUM) {
860 const char *appid = g_maclient_info[g_current_preprocessing_maclient_info].appid;
861 ma_client_s* client = ma_client_find_by_appid(appid);
869 int mas_get_client_pid_by_appid(const char *appid)
874 ma_client_s *client = NULL;
875 client = ma_client_find_by_appid(appid);
881 int status = aul_app_get_status_bypid(ret);
882 if (-1 != ret && 0 > status) {
883 MAS_LOGE("The PID for %s was %d, but it seems to be terminated : %d",
884 (appid ? appid : "NULL"), ret, status);
885 mas_client_deinitialize(ret);
892 bool mas_get_client_custom_ui_option_by_appid(const char *appid)
895 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
896 if (g_maclient_info[loop].used &&
897 0 < strlen(g_maclient_info[loop].appid) &&
898 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
899 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
900 ret = g_maclient_info[loop].custom_ui_option;
907 int mas_get_client_pid_by_wakeup_word(const char *wakeup_word)
909 const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
910 return mas_get_client_pid_by_appid(appid);
913 const char* mas_get_client_appid_by_wakeup_word(const char *wakeup_word)
916 const char *appid = NULL;
918 if (NULL == wakeup_word) return NULL;
920 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
921 if (g_maclient_info[loop].used &&
922 0 < strlen(g_maclient_info[loop].appid)) {
923 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
924 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
925 if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
926 appid = g_maclient_info[loop].appid;
933 /* Perform extended search, by eliminating blank characters */
935 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
936 if (g_maclient_info[loop].used &&
937 0 < strlen(g_maclient_info[loop].appid)) {
938 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
939 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
940 char comparand[MAX_WAKEUP_WORD_LEN];
941 int comparand_index = 0;
942 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
943 if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) {
944 comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index];
947 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
948 appid = g_maclient_info[loop].appid;
959 int mas_set_current_client_by_wakeup_word(const char *wakeup_word)
963 int prev_selection = g_current_maclient_info;
965 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
966 if (g_maclient_info[loop].used &&
967 0 < strlen(g_maclient_info[loop].appid)) {
968 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
969 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
970 if (0 == strncmp(wakeup_word, g_maclient_info[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
971 g_current_maclient_info = loop;
978 /* Perform extended search, by eliminating blank characters */
980 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
981 if (g_maclient_info[loop].used &&
982 0 < strlen(g_maclient_info[loop].appid)) {
983 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
984 if (0 < strlen(g_maclient_info[loop].wakeup_word[inner_loop])) {
985 char comparand[MAX_WAKEUP_WORD_LEN];
986 int comparand_index = 0;
987 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
988 if (' ' != g_maclient_info[loop].wakeup_word[inner_loop][index]) {
989 comparand[comparand_index++] = g_maclient_info[loop].wakeup_word[inner_loop][index];
992 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
993 g_current_maclient_info = loop;
1002 if (g_current_maclient_info != prev_selection) {
1003 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
1004 mas_client_deactivate(mas_get_client_pid_by_appid(g_maclient_info[prev_selection].appid));
1011 int mas_set_current_client_by_appid(const char *appid)
1014 int prev_selection = g_current_maclient_info;
1016 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1017 if (g_maclient_info[loop].used &&
1018 0 < strlen(g_maclient_info[loop].appid) &&
1019 0 < strlen(g_maclient_info[loop].wakeup_word[0])) {
1020 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
1021 g_current_maclient_info = loop;
1027 if (g_current_maclient_info != prev_selection) {
1028 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
1029 mas_client_deactivate(mas_get_client_pid_by_appid(g_maclient_info[prev_selection].appid));
1036 int mas_launch_client_by_appid(const char *appid, CLIENT_LAUNCH_MODE launch_mode)
1038 if (NULL == appid || 0 == strlen(appid)) {
1039 MAS_LOGE("appid invalid, failed launching MA Client");
1044 b = bundle_create();
1046 MAS_LOGE("Failed creating bundle for aul operation");
1050 int result = aul_svc_set_background_launch(b, TRUE);
1051 if (result < AUL_R_OK) {
1052 MAS_LOGE("ERROR : aul_svc_set_background_launch failed. app_id [%s] bundle[%p] result[%d : %s]",
1053 appid, b, result, get_error_message(result));
1056 result = aul_launch_app(appid, b);
1057 if (result < AUL_R_OK) {
1058 MAS_LOGE("ERROR : aul_launch_app failed. app_id [%s] bundle[%p] result[%d : %s]",
1059 appid, b, result, get_error_message(result));
1062 if (CLIENT_LAUNCH_MODE_ACTIVATION == launch_mode) {
1064 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1065 if (g_maclient_info[loop].used &&
1066 0 < strlen(g_maclient_info[loop].appid)) {
1067 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
1068 g_wakeup_maclient_appid = g_maclient_info[loop].appid;
1073 MAS_LOGD("g_wakeup_maclient_appid : %s, %d", g_wakeup_maclient_appid, found);
1076 if (b) bundle_free(b);
1082 int mas_bring_client_to_foreground(const char* appid)
1084 /* Bring MA client to foreground - is there a better way other than launching? */
1085 if (NULL == appid || 0 == strlen(appid)) {
1086 MAS_LOGE("appid invalid, failed launching MA Client");
1091 b = bundle_create();
1093 MAS_LOGE("Failed creating bundle for aul operation");
1097 int result = aul_launch_app(appid, b);
1098 if (result < AUL_R_OK) {
1099 MAS_LOGE("ERROR : aul_launch_app failed. app_id [%s] bundle[%p] result[%d : %s]",
1100 appid, b, result, get_error_message(result));
1103 if (b) bundle_free(b);
1109 int mas_launch_client_by_wakeup_word(const char *wakeup_word)
1111 const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
1112 return mas_launch_client_by_appid(appid, CLIENT_LAUNCH_MODE_ACTIVATION);
1115 int mas_prelaunch_default_assistant()
1117 /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
1119 int res = vconf_get_bool(WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE, &prelaunch_mode);
1120 if (0 == res && 0 != prelaunch_mode) {
1121 const char *default_assistant = NULL;
1122 if (0 == multi_assistant_service_plugin_get_default_assistant(&default_assistant)) {
1123 if (0 == aul_app_is_running(default_assistant)) {
1124 MAS_LOGD("prelaunching default_assistant_appid : %s", default_assistant);
1125 mas_launch_client_by_appid(default_assistant, CLIENT_LAUNCH_MODE_PRELAUNCH);
1133 ma_preprocessing_allow_mode_e get_preprocessing_allow_mode(const char* appid)
1135 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1136 if (appid && g_maclient_info[loop].used) {
1137 if (strncmp(appid, g_maclient_info[loop].appid, MAX_APPID_LEN) == 0) {
1138 return g_maclient_info[loop].preprocessing_allow_mode;
1142 return MA_PREPROCESSING_ALLOW_NONE;
1145 /* This might need to be read from settings in the future, but using macro for now */
1146 //#define BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1148 int mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT event)
1150 const char* current_maclient_appid = NULL;
1151 const char* preprocessing_allow_appid = NULL;
1152 if (g_current_maclient_info >= 0 && g_current_maclient_info < MAX_MACLIENT_INFO_NUM) {
1153 current_maclient_appid = g_maclient_info[g_current_maclient_info].appid;
1154 preprocessing_allow_appid = g_maclient_info[g_current_maclient_info].preprocessing_allow_appid;
1156 ma_preprocessing_allow_mode_e mode = get_preprocessing_allow_mode(current_maclient_appid);
1159 case PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED:
1161 #ifndef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1162 /* If there is no need to bring preprocessing assistant to front,
1163 current_maclient should always be brought to front */
1164 mas_bring_client_to_foreground(current_maclient_appid);
1166 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1167 if (check_preprocessing_assistant_exists()) {
1168 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1169 MA_PREPROCESSING_ALLOW_ALL == mode) {
1170 if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1171 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1175 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1176 /* If preprocessing assistant does not exist, there is no way to enable
1177 preprocessing assistant, so bring current maclient to front right away */
1178 mas_bring_client_to_foreground(current_maclient_appid);
1183 case PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED:
1185 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1186 /* Enable preprocessing mode only if the preprocessing assistant exists */
1187 if (check_preprocessing_assistant_exists()) {
1188 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1189 MA_PREPROCESSING_ALLOW_ALL == mode) {
1190 if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1191 g_current_preprocessing_state = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1197 case PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED:
1199 if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED == g_current_preprocessing_state) {
1200 g_current_preprocessing_state = PREPROCESSING_STATE_PREPROCESSING_UTTERANCE;
1201 } else if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED == g_current_preprocessing_state) {
1202 /* If preprocessing assistant does not exist, the current_maclient
1203 would have been brought to front already on wakeup event */
1204 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1205 if (check_preprocessing_assistant_exists()) {
1206 mas_bring_client_to_foreground(current_maclient_appid);
1209 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1213 case PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED:
1215 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1216 if (check_preprocessing_assistant_exists()) {
1217 if (MA_PREPROCESSING_ALLOW_FOLLOW_UP == mode ||
1218 MA_PREPROCESSING_ALLOW_ALL == mode) {
1219 g_current_preprocessing_state = PREPROCESSING_STATE_PREPROCESSING_FOLLOW_UP;
1224 case PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED:
1226 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1227 if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == g_current_preprocessing_state ||
1228 PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == g_current_preprocessing_state) {
1229 char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
1230 MAS_LOGD("preprocessing_assistant_appid : %s", vconf_str);
1232 mas_bring_client_to_foreground(vconf_str);
1238 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1241 case PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED:
1243 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1244 if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == g_current_preprocessing_state ||
1245 PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == g_current_preprocessing_state) {
1246 mas_bring_client_to_foreground(current_maclient_appid);
1249 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1256 static int pkg_app_list_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
1260 int ret = pkgmgrinfo_appinfo_get_appid (handle, &appid);
1261 if (PMINFO_R_OK == ret && NULL != appid) {
1262 int *result = (int*)user_data;
1264 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM;loop++) {
1265 if (g_maclient_info[loop].used) {
1266 LOGD("comparing appid : %s %s", g_maclient_info[loop].wakeup_engine, appid);
1267 if (0 == strncmp(g_maclient_info[loop].wakeup_engine, appid, MAX_APPID_LEN)) {
1274 LOGE("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret);
1282 INFO: Package install/update/uninstall scenario
1283 Install and Uninstall are obviously simple.
1284 Install: just INSTALL
1285 Uninstall: just UNINSTALL
1286 Update package (change the source codes and Run As again), there are four scenarios:
1289 2. UNINSTALL -> INSTALL
1290 This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Check "Enable Project specific settings"
1291 and change Application ID in tizen-manifest.xml file and Run As.
1292 3. UPDATE -> INSTALL
1293 This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Uncheck "Enable Project specific settings"
1294 and change Application ID in tizen-manifest.xml file and Run As.
1295 At UPDATE event, pkgid (package parameter) is invalid...
1297 Exceptionally, only UPDATE can be called when Application ID in tizen-manifest.xml file is changed.
1298 At UPDATE event, pkgid (package parameter) is valid, and only appid is changed; the previous appid is invalid.
1300 static void _package_manager_event_cb(const char *type, const char *package, package_manager_event_type_e event_type, package_manager_event_state_e event_state, int progress, package_manager_error_e error, void *user_data)
1303 uid_t uid = getuid ();
1304 pkgmgrinfo_pkginfo_h handle = NULL;
1305 static bool in_progress = false;
1307 if (!package || !type)
1310 if (PACKAGE_MANAGER_EVENT_TYPE_UPDATE != event_type &&
1311 PACKAGE_MANAGER_EVENT_TYPE_INSTALL != event_type &&
1312 PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL != event_type)
1315 if (PACKAGE_MANAGER_EVENT_STATE_STARTED != event_state &&
1316 PACKAGE_MANAGER_EVENT_STATE_COMPLETED != event_state)
1320 LOGD("type=%s package=%s event_type=%d event_state=%d progress=%d error=%d",
1321 type, package, event_type, event_state, progress, error);
1322 ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
1323 if (ret != PMINFO_R_OK || NULL == handle) {
1324 LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid ());
1325 /* Try to get in user packages */
1327 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo (package, uid, &handle);
1328 if (ret != PMINFO_R_OK || NULL == handle) {
1329 LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid ());
1335 /* Try to get in user packages */
1336 pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret, uid);
1338 /* Try to get in global packages */
1339 pkgmgrinfo_appinfo_get_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret);
1342 if (PACKAGE_MANAGER_EVENT_STATE_STARTED == event_state) {
1343 LOGD("processing PACKAGE_MANAGER_EVENT_STATE_STARTED event");
1344 if (false == in_progress) {
1348 } else if (PACKAGE_MANAGER_EVENT_STATE_COMPLETED == event_state) {
1349 LOGD("processing PACKAGE_MANAGER_EVENT_STATE_COMPLETED event");
1350 if (true == in_progress) {
1352 process_activated_setting();
1353 in_progress = false;
1358 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1363 bool service_app_create(void *data)
1365 // Todo: add your code here.
1367 MAS_LOGD("[Enter] Service app create");
1369 if (0 != init_wakeup()) {
1370 MAS_LOGE("Fail to init wakeup service");
1375 int ret = package_manager_create(&g_pkgmgr);
1376 if (ret == PACKAGE_MANAGER_ERROR_NONE) {
1377 ret = package_manager_set_event_cb(g_pkgmgr, _package_manager_event_cb, NULL);
1378 if (ret == PACKAGE_MANAGER_ERROR_NONE) {
1379 LOGD("package_manager_set_event_cb succeeded.");
1382 LOGE("package_manager_set_event_cb failed(%d)", ret);
1386 LOGE("package_manager_create failed(%d)", ret);
1393 void service_app_terminate(void *data)
1395 MAS_LOGI("[ENTER]");
1397 package_manager_unset_event_cb(g_pkgmgr);
1398 package_manager_destroy(g_pkgmgr);
1402 // Todo: add your code here.
1408 void service_app_control(app_control_h app_control, void *data)
1410 // Todo: add your code here.
1415 service_app_lang_changed(app_event_info_h event_info, void *user_data)
1417 /*APP_EVENT_LANGUAGE_CHANGED*/
1422 service_app_region_changed(app_event_info_h event_info, void *user_data)
1424 /*APP_EVENT_REGION_FORMAT_CHANGED*/
1428 service_app_low_battery(app_event_info_h event_info, void *user_data)
1430 /*APP_EVENT_LOW_BATTERY*/
1434 service_app_low_memory(app_event_info_h event_info, void *user_data)
1436 /*APP_EVENT_LOW_MEMORY*/
1439 int main(int argc, char* argv[])
1442 service_app_lifecycle_callback_s event_callback;
1443 app_event_handler_h handlers[5] = {NULL, };
1445 event_callback.create = service_app_create;
1446 event_callback.terminate = service_app_terminate;
1447 event_callback.app_control = service_app_control;
1449 service_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, service_app_low_battery, &ad);
1450 service_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, service_app_low_memory, &ad);
1451 service_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, service_app_lang_changed, &ad);
1452 service_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, service_app_region_changed, &ad);
1454 int ret = service_app_main(argc, argv, &event_callback, ad);
1455 LOGI("Main function exits with : %d", ret);