Update year information of license boilerplate
[platform/core/uifw/multi-assistant-service.git] / src / multi_assistant_service.c
1 /*
2  * Copyright 2018-2019 Samsung Electronics Co., Ltd
3  *
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
7  *
8  * http://floralicense.org/license/
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 #include <tizen.h>
18 #include <service_app.h>
19 #include <app_manager.h>
20 #include <app.h>
21 #include <aul.h>
22 #include <malloc.h>
23 #include <Ecore.h>
24 #include <vconf.h>
25 #include <package_manager.h>
26 #include <pkgmgr-info.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <glib.h>
32
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"
38
39 static const char *g_current_lang = "en_US";
40
41 #define ENABLE_MULTI_ASSISTANT_BY_DEFAULT
42
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"
46
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
52 typedef struct {
53         bool used;
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;
60
61         ma_preprocessing_allow_mode_e preprocessing_allow_mode;
62         char preprocessing_allow_appid[MAX_APPID_LEN];
63 } ma_client_info;
64
65 static ma_client_info g_maclient_info[MAX_MACLIENT_INFO_NUM];
66
67 typedef struct {
68         int pid;
69         char appid[MAX_APPID_LEN];
70 } ma_client_s;
71
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;
76
77 static PREPROCESSING_STATE g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
78
79 /* client list */
80 static GSList* g_client_list = NULL;
81
82 int ma_client_create(ma_client_s *info)
83 {
84         if (NULL == info) {
85                 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
86                 return -1;
87         }
88
89         ma_client_s* data = NULL;
90
91         data = (ma_client_s*)calloc(1, sizeof(ma_client_s));
92         if (NULL == data) {
93                 MAS_LOGE("[ERROR] Fail to allocate memory"); //LCOV_EXCL_LINE
94                 return -1;// MA_ERROR_OUT_OF_MEMORY;
95         }
96
97         *data = *info;
98
99         g_client_list = g_slist_append(g_client_list, data);
100
101         return 0;
102 }
103
104 int ma_client_destroy(ma_client_s *client)
105 {
106         if (NULL == client) {
107                 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
108                 return -1;// MA_ERROR_OPERATION_FAILED;
109         }
110
111         g_client_list =  g_slist_remove(g_client_list, client);
112
113         free(client);
114         client = NULL;
115
116         return 0;
117 }
118
119 ma_client_s* ma_client_find_by_appid(const char *appid)
120 {
121         if (NULL == appid) {
122                 MAS_LOGE("Input parameter is NULL"); //LCOV_EXCL_LINE
123                 return NULL;
124         }
125
126         ma_client_s *data = NULL;
127
128         int count = g_slist_length(g_client_list);
129         int i;
130
131         for (i = 0; i < count; i++) {
132                 data = g_slist_nth_data(g_client_list, i);
133
134                 if (NULL != data) {
135                         if (0 == strncmp(data->appid, appid, MAX_APPID_LEN)) {
136                                 return data;
137                         }
138                 }
139         }
140
141         MAS_LOGE("[ERROR] client Not found");
142
143         return NULL;
144 }
145
146 ma_client_s* ma_client_find_by_pid(int pid)
147 {
148         ma_client_s *data = NULL;
149
150         int count = g_slist_length(g_client_list);
151         int i;
152
153         for (i = 0; i < count; i++) {
154                 data = g_slist_nth_data(g_client_list, i);
155
156                 if (NULL != data) {
157                         if (data->pid == pid) {
158                                 return data;
159                         }
160                 }
161         }
162
163         MAS_LOGE("[ERROR] client Not found");
164
165         return NULL;
166 }
167
168 bool check_preprocessing_assistant_exists()
169 {
170         bool ret = false;
171
172         char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
173         if (vconf_str) {
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) {
179                                                 ret = true;
180                                         }
181                                 }
182                         }
183                 }
184                 free(vconf_str);
185                 vconf_str = NULL;
186         }
187
188         MAS_LOGD("result : %d", ret);
189
190         return ret;
191 }
192
193 bool is_current_preprocessing_assistant(const char* appid)
194 {
195         if (NULL == appid) return false;
196
197         bool ret = false;
198
199         char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
200         if (vconf_str) {
201                 if (strncmp(vconf_str, appid, MAX_APPID_LEN) == 0) {
202                         ret = true;
203                 }
204                 free(vconf_str);
205                 vconf_str = NULL;
206         }
207
208         return ret;
209 }
210
211 int mas_client_initialize(int pid)
212 {
213         MAS_LOGD("[Enter] pid(%d)", pid);
214
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';
218
219                 MAS_LOGD("appid for pid %d is : %s", pid, (appid ? appid : "Unknown"));
220
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);
224                 if (old_client) {
225                         ma_client_destroy(old_client);
226                         old_client = NULL;
227                 }
228
229                 /* And remove a client that has same pid also */
230                 old_client = ma_client_find_by_pid(pid);
231                 if (old_client) {
232                         ma_client_destroy(old_client);
233                         old_client = NULL;
234                 }
235
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);
241
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;
245                 }
246
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!");
250
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);
255                         } else {
256                                 MAS_LOGE("[ERROR] g_wakeup_maclient_appid and appid differ : %s %s",
257                                         (g_wakeup_maclient_appid ? g_wakeup_maclient_appid : "NULL"), appid);
258                         }
259                 } else {
260                         MAS_LOGD("MA client connected, but its appid does not match with current maclient");
261                 }
262         } else {
263                 MAS_LOGE("[ERROR] Fail to retrieve appid");
264         }
265
266         return 0;
267 }
268
269 int mas_client_deinitialize(int pid)
270 {
271         MAS_LOGD("[Enter] pid(%d)", pid);
272         ma_client_s *client = ma_client_find_by_pid(pid);
273         if (client) {
274                 ma_client_destroy(client);
275                 client = NULL;
276         }
277         return 0;
278 }
279
280 int mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type)
281 {
282         MAS_LOGD("[Enter] pid(%d)", pid);
283
284         int ret = multi_assistant_service_plugin_get_recording_audio_format(rate, channel, audio_type);
285         if (0 != ret){
286                 MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret);
287         }
288
289         return ret;
290 }
291
292 int mas_client_get_audio_source_type(int pid, char** type)
293 {
294         MAS_LOGD("[Enter] pid(%d)", pid);
295
296         int ret = multi_assistant_service_plugin_get_recording_audio_source_type(type);
297         if (0 != ret){
298                 MAS_LOGE("[ERROR] Fail to get recording audio source type, ret(%d)", ret);
299         }
300
301         return ret;
302 }
303
304 int mas_client_send_preprocessing_information(int pid)
305 {
306         int ret = -1;
307         MAS_LOGD("[Enter] pid(%d)", pid);
308
309         char* vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
310         MAS_LOGD("preprocessing_assistant_appid : %s", vconf_str);
311         if (vconf_str) {
312                 ret = masc_dbus_send_preprocessing_information(pid, vconf_str);
313                 free(vconf_str);
314                 vconf_str = NULL;
315         }
316
317         return ret;
318 }
319
320 int mas_client_activate(int pid)
321 {
322         int ret = -1;
323         MAS_LOGD("[Enter] pid(%d)", pid);
324
325         ret = masc_dbus_active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
326
327         return ret;
328 }
329
330 int mas_client_deactivate(int pid)
331 {
332         int ret = -1;
333         MAS_LOGD("[Enter] pid(%d)", pid);
334
335         ret = masc_dbus_active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
336
337         return ret;
338 }
339
340 int mas_client_send_asr_result(int pid, int event, char* asr_result)
341 {
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);
344         if (0 != ret){
345                 MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret);
346         }
347
348         // if final event is , launch assistant app which is invoked with wakeup word.
349         /* TO_DO */
350         return ret;
351 }
352
353 int mas_client_send_result(int pid, char* display_text, char* utterance_text, char* result_json)
354 {
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);
357         if (0 != ret){
358                 MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret);
359         }
360
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';
365                 pid_appid = buf;
366         }
367         multi_assistant_service_plugin_update_recognition_result(pid_appid, MA_RECOGNITION_RESULT_EVENT_SUCCESS);
368
369         return ret;
370 }
371
372 int mas_client_send_recognition_result(int pid, int result)
373 {
374         MAS_LOGD("[Enter] pid(%d), result(%d)", pid, result);
375         int ret = masc_ui_dbus_send_recognition_result(pid, result);
376         if (0 != ret){
377                 MAS_LOGE("[ERROR] Fail to send recognition result, ret(%d)", ret);
378         }
379
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';
384                 pid_appid = buf;
385         }
386         multi_assistant_service_plugin_update_recognition_result(pid_appid, result);
387
388         return ret;
389 }
390
391 int mas_client_start_streaming_audio_data(int pid, int type)
392 {
393         int ret = -1;
394         switch(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);
398                         break;
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 */
402                         break;
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);
406                         break;
407         }
408         return ret;
409 }
410
411 int mas_client_stop_streaming_audio_data(int pid, int type)
412 {
413         int ret = -1;
414         switch(type) {
415                 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
416                         ret = multi_assistant_service_plugin_stop_streaming_utterance_data();
417                         break;
418                 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
419                         ret = multi_assistant_service_plugin_stop_streaming_previous_utterance_data();
420                         break;
421                 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
422                         ret = multi_assistant_service_plugin_stop_streaming_follow_up_data();
423                         break;
424         }
425         return ret;
426 }
427
428 int mas_client_update_voice_feedback_state(int pid, int state)
429 {
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';
434                 pid_appid = buf;
435         }
436         multi_assistant_service_plugin_update_voice_feedback_state(pid_appid, state);
437         return 0;
438 }
439
440 int mas_client_send_assistant_specific_command(int pid, const char *command)
441 {
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';
446                 pid_appid = buf;
447         }
448         multi_assistant_service_plugin_send_assistant_specific_command(pid_appid, command);
449         return 0;
450 }
451
452 int mas_client_set_background_volume(int pid, double ratio)
453 {
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';
458                 pid_appid = buf;
459         }
460         multi_assistant_service_plugin_set_background_volume(pid_appid, ratio);
461         return 0;
462 }
463
464 int mas_client_set_preprocessing_allow_mode(int pid, int mode, const char* appid)
465 {
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';
470                 pid_appid = buf;
471         }
472
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;
477                                 if (appid) {
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';
480                                 } else {
481                                         g_maclient_info[loop].preprocessing_allow_appid[0] = '\0';
482                                 }
483                         }
484                 }
485         }
486
487         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED);
488
489         return 0;
490 }
491
492 int mas_client_send_preprocessing_result(int pid, bool result)
493 {
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';
498                 pid_appid = buf;
499         }
500         if (!is_current_preprocessing_assistant(pid_appid)) return -1;
501
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;
505         }
506
507         if (result) {
508                 MAS_LOGD("Preprocessing succeeded, bring (%s) to foreground", pid_appid);
509                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED);
510         } else {
511                 MAS_LOGD("Preprocessing failed, bring (%s) to foreground", current_maclient_appid);
512                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED);
513         }
514
515         ma_client_s* client = ma_client_find_by_appid(current_maclient_appid);
516         if (client) {
517                 masc_dbus_send_preprocessing_result(client->pid, result);
518         }
519
520         return 0;
521 }
522
523 int mas_client_set_wake_word_audio_require_flag(int pid, bool require)
524 {
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';
529                 pid_appid = buf;
530         }
531
532         multi_assistant_service_plugin_set_wake_word_audio_require_flag(pid_appid, require);
533         return 0;
534 }
535
536 int mas_client_set_assistant_language(int pid, const char* language)
537 {
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';
543                 pid_appid = buf;
544         }
545
546         multi_assistant_service_plugin_assistant_language(pid_appid, language);
547         return 0;
548 }
549
550 int mas_ui_client_initialize(int pid)
551 {
552         MAS_LOGD("[Enter] pid(%d)", pid);
553
554         return 0;
555 }
556
557 int mas_ui_client_deinitialize(int pid)
558 {
559         MAS_LOGD("[Enter] pid(%d)", pid);
560
561         return 0;
562 }
563
564 int mas_ui_client_change_assistant(const char* appid)
565 {
566         MAS_LOGD("[Enter]");
567
568         if (NULL == appid) {
569                 MAS_LOGE("NULL parameter");
570                 return -1;
571         }
572
573         bool use_custom_ui = mas_get_client_custom_ui_option_by_appid(appid);
574         masc_ui_dbus_enable_common_ui(!use_custom_ui);
575
576         mas_set_current_client_by_appid(appid);
577         int pid = mas_get_client_pid_by_appid(appid);
578         if (pid != -1) {
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"));
583                 /*
584                 int ret = multi_assistant_service_plugin_start_streaming_utterance_data();
585                 if (0 != ret) {
586                         MAS_LOGE("[ERROR] Fail to start streaming utterance data(%d)", ret);
587                 }
588                 */
589         } else {
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"));
592
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);
600                                 }
601                         }
602                 }
603         }
604
605         return 0;
606 }
607
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");
613
614         if (NULL == appid) {
615                 MAS_LOGD("app_id NULL, returning");
616                 return -1;
617         }
618
619         int index = -1;
620         int loop = 0;
621         while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) {
622                 if (false == g_maclient_info[loop].used) {
623                         index = loop;
624                 }
625                 loop++;
626         }
627         if (-1 != index) {
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';
634
635                 if (is_current_preprocessing_assistant(g_maclient_info[index].appid)) {
636                         g_current_preprocessing_maclient_info = index;
637                 }
638
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';
647                                 } else {
648                                         strncpy(g_maclient_info[index].wakeup_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
649                                 }
650                         } else {
651                                 strncpy(g_maclient_info[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN);
652                         }
653                 }
654
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';
660                         } else {
661                                 strncpy(g_maclient_info[index].supported_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
662                         }
663                 }
664
665                 MAS_LOGD("wakeup_engine(%s)", wakeup_engine);
666                 if (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';
669                 } else {
670                         g_maclient_info[index].wakeup_engine[0] = '\0';
671                         MAS_LOGW("Wakeup engine information not provided for : %s", appid);
672                 }
673                 g_maclient_info[index].custom_ui_option = custom_ui_option;
674         } else {
675                 MAS_LOGD("Couldn't find an empty slot for storing assistant info");
676         }
677
678         MAS_LOGD("__mas_assistant_info_cb end");
679
680         return 0;
681 }
682
683 static void mas_active_state_changed_cb(keynode_t* key, void* data)
684 {
685         int vconf_value = 0;
686         if (vconf_get_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED, &vconf_value) == 0) {
687                 MAS_LOGD("multi-assistant active state : %d\n", vconf_value);
688
689                 if (vconf_value) {
690                         multi_assistant_service_plugin_activate();
691                 } else {
692                         multi_assistant_service_plugin_deactivate();
693                 }
694         }
695 }
696
697 static int init_plugin(void)
698 {
699         if (0 != multi_assistant_service_plugin_initialize()) {
700                 MAS_LOGE("Fail to ws intialize");
701                 return -1;
702         }
703
704         if (0 != multi_assistant_service_plugin_set_language(g_current_lang)) {
705                 MAS_LOGE("Fail to ws set language");
706                 return -1;
707         }
708
709         if (0 == mas_config_get_assistant_info(__mas_assistant_info_cb, NULL)) {
710                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
711                         int inner_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);
718                                 }
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");
728                                                 }
729                                         }
730                                 }
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");
739                                                 }
740                                         }
741                                 }
742                         }
743                 }
744         } else {
745                 MAS_LOGE("Fail to load assistant info");
746         }
747
748         if (0 != multi_assistant_service_plugin_set_callbacks()) {
749                 MAS_LOGE("Fail to set callbacks");
750                 return -1;
751         }
752
753         return 0;
754 }
755
756 static int deinit_plugin(void)
757 {
758         MAS_LOGI("[ENTER]");
759         if (0 != multi_assistant_service_plugin_deactivate()) {
760                 MAS_LOGE("Fail to deactivate");
761         }
762         if (0 != multi_assistant_service_plugin_deinitialize()) {
763                 MAS_LOGE("Fail to deinitialize");
764         }
765         MAS_LOGI("[END]");
766         return 0;
767 }
768
769 static int process_activated_setting()
770 {
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);
774         } else {
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);
785                                 } else {
786                                         MAS_LOGE("No default assistant, and no assistant installed");
787                                 }
788                         }
789                 }
790 #endif
791         }
792         return 0;
793 }
794
795 static int init_wakeup(void)
796 {
797         MAS_LOGD("[Enter] init_wakeup");
798
799         int ret = mas_dbus_open_connection();
800         if (0 != ret) {
801                 MAS_LOGE("[ERROR] Fail to open connection");
802         }
803
804         init_plugin();
805
806         process_activated_setting();
807
808         mas_prelaunch_default_assistant();
809
810         /* For the case of preprocessing assistant, it always have to be launched beforehand */
811         char *vconf_str;
812         vconf_str = vconf_get_str(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
813         if (vconf_str) {
814                 MAS_LOGD("prelaunching preprocessing_assistant_appid : %s", vconf_str);
815                 mas_launch_client_by_appid(vconf_str, CLIENT_LAUNCH_MODE_PRELAUNCH);
816                 free(vconf_str);
817                 vconf_str = NULL;
818         }
819
820         return 0;
821 }
822
823 static void deinit_wakeup(void)
824 {
825         MAS_LOGI("[Enter] deinit_wakeup");
826
827 /*      if (NULL != g_current_lang) {
828                 free(g_current_lang);
829                 g_current_lang = NULL;
830         }
831 */
832         deinit_plugin();
833
834         vconf_ignore_key_changed(MULTI_ASSISTANT_SETTINGS_ACTIVATED, mas_active_state_changed_cb);
835
836         int ret = mas_dbus_close_connection();
837         if (0 != ret) {
838                 MAS_LOGE("[ERROR] Fail to close connection");
839         }
840         MAS_LOGI("[END]");
841 }
842
843 int mas_get_current_client_pid()
844 {
845         int ret = -1;
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);
849                 if (client) {
850                         ret = client->pid;
851                 }
852         }
853         return ret;
854 }
855
856 int mas_get_current_preprocessing_client_pid()
857 {
858         int ret = -1;
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);
862                 if (client) {
863                         ret = client->pid;
864                 }
865         }
866         return ret;
867 }
868
869 int mas_get_client_pid_by_appid(const char *appid)
870 {
871         int ret = -1;
872
873         if (appid) {
874                 ma_client_s *client = NULL;
875                 client = ma_client_find_by_appid(appid);
876                 if (client) {
877                         ret = client->pid;
878                 }
879         }
880
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);
886                 ret = -1;
887         }
888
889         return ret;
890 }
891
892 bool mas_get_client_custom_ui_option_by_appid(const char *appid)
893 {
894         bool ret = false;
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;
901                         }
902                 }
903         }
904         return ret;
905 }
906
907 int mas_get_client_pid_by_wakeup_word(const char *wakeup_word)
908 {
909         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
910         return mas_get_client_pid_by_appid(appid);
911 }
912
913 const char* mas_get_client_appid_by_wakeup_word(const char *wakeup_word)
914 {
915         int loop;
916         const char *appid = NULL;
917
918         if (NULL == wakeup_word) return NULL;
919
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;
927                                         }
928                                 }
929                         }
930                 }
931         }
932
933         /* Perform extended search, by eliminating blank characters */
934         if (NULL == appid) {
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];
945                                                         }
946                                                 }
947                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
948                                                         appid = g_maclient_info[loop].appid;
949                                                 }
950                                         }
951                                 }
952                         }
953                 }
954         }
955
956         return appid;
957 }
958
959 int mas_set_current_client_by_wakeup_word(const char *wakeup_word)
960 {
961         int loop;
962         int ret = -1;
963         int prev_selection = g_current_maclient_info;
964
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;
972                                                 ret = 0;
973                                         }
974                                 }
975                         }
976                 }
977         }
978         /* Perform extended search, by eliminating blank characters */
979         if (ret == -1) {
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];
990                                                         }
991                                                 }
992                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
993                                                         g_current_maclient_info = loop;
994                                                         ret = 0;
995                                                 }
996                                         }
997                                 }
998                         }
999                 }
1000         }
1001
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));
1005                 }
1006         }
1007
1008         return ret;
1009 }
1010
1011 int mas_set_current_client_by_appid(const char *appid)
1012 {
1013         int ret = -1;
1014         int prev_selection = g_current_maclient_info;
1015
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;
1022                                 ret = 0;
1023                         }
1024                 }
1025         }
1026
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));
1030                 }
1031         }
1032
1033         return ret;
1034 }
1035
1036 int mas_launch_client_by_appid(const char *appid, CLIENT_LAUNCH_MODE launch_mode)
1037 {
1038         if (NULL == appid || 0 == strlen(appid)) {
1039                 MAS_LOGE("appid invalid, failed launching MA Client");
1040                 return -1;
1041         }
1042
1043         bundle *b = NULL;
1044         b = bundle_create();
1045         if (NULL == b) {
1046                 MAS_LOGE("Failed creating bundle for aul operation");
1047                 return -1;
1048         }
1049
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));
1054         }
1055
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));
1060         }
1061
1062         if (CLIENT_LAUNCH_MODE_ACTIVATION == launch_mode) {
1063                 bool found = false;
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;
1069                                         found = true;
1070                                 }
1071                         }
1072                 }
1073                 MAS_LOGD("g_wakeup_maclient_appid : %s, %d", g_wakeup_maclient_appid, found);
1074         }
1075
1076         if (b) bundle_free(b);
1077         b = NULL;
1078
1079         return result;
1080 }
1081
1082 int mas_bring_client_to_foreground(const char* appid)
1083 {
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");
1087                 return -1;
1088         }
1089
1090         bundle *b = NULL;
1091         b = bundle_create();
1092         if (NULL == b) {
1093                 MAS_LOGE("Failed creating bundle for aul operation");
1094                 return -1;
1095         }
1096
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));
1101         }
1102
1103         if (b) bundle_free(b);
1104         b = NULL;
1105
1106         return result;
1107 }
1108
1109 int mas_launch_client_by_wakeup_word(const char *wakeup_word)
1110 {
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);
1113 }
1114
1115 int mas_prelaunch_default_assistant()
1116 {
1117         /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
1118         int prelaunch_mode;
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);
1126                         }
1127                 }
1128         }
1129         return 0;
1130 }
1131
1132
1133 ma_preprocessing_allow_mode_e get_preprocessing_allow_mode(const char* appid)
1134 {
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;
1139                         }
1140                 }
1141         }
1142         return MA_PREPROCESSING_ALLOW_NONE;
1143 }
1144
1145 /* This might need to be read from settings in the future, but using macro for now */
1146 //#define BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1147
1148 int mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT event)
1149 {
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;
1155         }
1156         ma_preprocessing_allow_mode_e mode = get_preprocessing_allow_mode(current_maclient_appid);
1157
1158         switch (event) {
1159                 case PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED:
1160                 {
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);
1165 #endif
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;
1172                                         }
1173                                 }
1174                         } else {
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);
1179 #endif
1180                         }
1181                 }
1182                 break;
1183                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED:
1184                 {
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;
1192                                         }
1193                                 }
1194                         }
1195                 }
1196                 break;
1197                 case PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED:
1198                 {
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);
1207                                 }
1208 #endif
1209                                 g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1210                         }
1211                 }
1212                 break;
1213                 case PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED:
1214                 {
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;
1220                                 }
1221                         }
1222                 }
1223                 break;
1224                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED:
1225                 {
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);
1231                                 if (vconf_str) {
1232                                         mas_bring_client_to_foreground(vconf_str);
1233                                         free(vconf_str);
1234                                         vconf_str = NULL;
1235                                 }
1236                         }
1237 #endif
1238                         g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1239                 }
1240                 break;
1241                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED:
1242                 {
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);
1247                         }
1248 #endif
1249                         g_current_preprocessing_state = PREPROCESSING_STATE_NONE;
1250                 }
1251                 break;
1252         }
1253         return 0;
1254 }
1255
1256 static int pkg_app_list_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
1257 {
1258         char *appid = NULL;
1259
1260         int ret = pkgmgrinfo_appinfo_get_appid (handle, &appid);
1261         if (PMINFO_R_OK == ret && NULL != appid) {
1262                 int *result = (int*)user_data;
1263                 if (result) {
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)) {
1268                                                 *result = 1;
1269                                         }
1270                                 }
1271                         }
1272                 }
1273         } else {
1274                 LOGE("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret);
1275                 return 0;
1276         }
1277
1278         return 0;
1279 }
1280
1281 /*
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:
1287 1. UPDATE
1288    Source code change
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...
1296 4. UPDATE
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.
1299 */
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)
1301 {
1302         int ret = 0;
1303         uid_t uid = getuid ();
1304         pkgmgrinfo_pkginfo_h handle = NULL;
1305         static bool in_progress = false;
1306
1307         if (!package || !type)
1308                 return;
1309
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)
1313                 return;
1314
1315         if (PACKAGE_MANAGER_EVENT_STATE_STARTED != event_state &&
1316                 PACKAGE_MANAGER_EVENT_STATE_COMPLETED != event_state)
1317                 return;
1318
1319         bool user = false;
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 */
1326                 user = true;
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 ());
1330                         return;
1331                 }
1332         }
1333
1334         if (user) {
1335                 /* Try to get in user packages */
1336                 pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret, uid);
1337         }  else {
1338                 /* Try to get in global packages */
1339                 pkgmgrinfo_appinfo_get_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret);
1340         }
1341         if (1 == ret) {
1342                 if (PACKAGE_MANAGER_EVENT_STATE_STARTED == event_state) {
1343                         LOGD("processing PACKAGE_MANAGER_EVENT_STATE_STARTED event");
1344                         if (false == in_progress) {
1345                                 in_progress = true;
1346                                 deinit_plugin();
1347                         }
1348                 } else if (PACKAGE_MANAGER_EVENT_STATE_COMPLETED == event_state) {
1349                         LOGD("processing PACKAGE_MANAGER_EVENT_STATE_COMPLETED event");
1350                         if (true == in_progress) {
1351                                 init_plugin();
1352                                 process_activated_setting();
1353                                 in_progress = false;
1354                         }
1355                 }
1356         }
1357
1358         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1359
1360         return;
1361 }
1362
1363 bool service_app_create(void *data)
1364 {
1365         // Todo: add your code here.
1366
1367         MAS_LOGD("[Enter] Service app create");
1368
1369         if (0 != init_wakeup()) {
1370                 MAS_LOGE("Fail to init wakeup service");
1371                 return false;
1372         }
1373
1374         if (!g_pkgmgr) {
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.");
1380                         }
1381                         else {
1382                                 LOGE("package_manager_set_event_cb failed(%d)", ret);
1383                         }
1384                 }
1385                 else {
1386                         LOGE("package_manager_create failed(%d)", ret);
1387                 }
1388         }
1389
1390         return true;
1391 }
1392
1393 void service_app_terminate(void *data)
1394 {
1395         MAS_LOGI("[ENTER]");
1396         if (g_pkgmgr) {
1397                 package_manager_unset_event_cb(g_pkgmgr);
1398                 package_manager_destroy(g_pkgmgr);
1399                 g_pkgmgr = NULL;
1400         }
1401
1402         // Todo: add your code here.
1403         deinit_wakeup();
1404         MAS_LOGI("[END]");
1405         return;
1406 }
1407
1408 void service_app_control(app_control_h app_control, void *data)
1409 {
1410         // Todo: add your code here.
1411         return;
1412 }
1413
1414 static void
1415 service_app_lang_changed(app_event_info_h event_info, void *user_data)
1416 {
1417         /*APP_EVENT_LANGUAGE_CHANGED*/
1418         return;
1419 }
1420
1421 static void
1422 service_app_region_changed(app_event_info_h event_info, void *user_data)
1423 {
1424         /*APP_EVENT_REGION_FORMAT_CHANGED*/
1425 }
1426
1427 static void
1428 service_app_low_battery(app_event_info_h event_info, void *user_data)
1429 {
1430         /*APP_EVENT_LOW_BATTERY*/
1431 }
1432
1433 static void
1434 service_app_low_memory(app_event_info_h event_info, void *user_data)
1435 {
1436         /*APP_EVENT_LOW_MEMORY*/
1437 }
1438
1439 int main(int argc, char* argv[])
1440 {
1441         char ad[50] = {0,};
1442         service_app_lifecycle_callback_s event_callback;
1443         app_event_handler_h handlers[5] = {NULL, };
1444
1445         event_callback.create = service_app_create;
1446         event_callback.terminate = service_app_terminate;
1447         event_callback.app_control = service_app_control;
1448
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);
1453
1454         int ret = service_app_main(argc, argv, &event_callback, ad);
1455         LOGI("Main function exits with : %d", ret);
1456         return ret;
1457 }