Extract vconf dependency from service_main.cpp
[platform/core/uifw/multi-assistant-service.git] / src / service_main.cpp
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 <aul_svc.h>
23 #include <malloc.h>
24 #include <Ecore.h>
25 #include <vconf.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 "service_common.h"
34 #include "service_main.h"
35 #include "service_plugin.h"
36 #include "service_ipc_dbus.h"
37 #include "service_config.h"
38
39 static CServiceMain* g_service_main = nullptr;
40
41 bool CServiceMain::check_preprocessing_assistant_exists()
42 {
43         bool ret = false;
44
45         boost::optional<std::string> preprocessing_appid =
46                 mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
47         if (preprocessing_appid) {
48                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
49                         if (mClientInfo[loop].used &&
50                                 strncmp((*preprocessing_appid).c_str(), mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
51                                 if (mClientManager.check_client_validity_by_appid(*preprocessing_appid)) {
52                                         ret = true;
53                                 }
54                         }
55                 }
56         }
57
58         MAS_LOGD("result : %d", ret);
59
60         return ret;
61 }
62
63 bool CServiceMain::is_current_preprocessing_assistant(const char* appid)
64 {
65         if (NULL == appid) return false;
66
67         bool ret = false;
68
69         boost::optional<std::string> preprocessing_appid =
70                 mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
71         if (preprocessing_appid) {
72                 if (strncmp((*preprocessing_appid).c_str(), appid, MAX_APPID_LEN) == 0) {
73                         ret = true;
74                 }
75         }
76
77         return ret;
78 }
79
80 int CServiceMain::mas_client_get_audio_format(int pid, int* rate, int* channel, int* audio_type)
81 {
82         MAS_LOGD("[Enter] pid(%d)", pid);
83
84         int ret = mServicePlugin.get_recording_audio_format(rate, channel, audio_type);
85         if (0 != ret){
86                 MAS_LOGE("[ERROR] Fail to get recording audio format, ret(%d)", ret);
87         }
88
89         return ret;
90 }
91
92 #define MAX_LOCAL_VARIABLE_STRING_LEN 256
93 int CServiceMain::mas_client_get_audio_source_type(int pid, char** type)
94 {
95         MAS_LOGD("[Enter] pid(%d)", pid);
96
97         if (NULL == type) return -1;
98
99         static char cached[MAX_LOCAL_VARIABLE_STRING_LEN] = {'\0'};
100         int ret = mServicePlugin.get_recording_audio_source_type(type);
101         if (0 != ret){
102                 MAS_LOGE("[ERROR] Fail to get recording audio source type, ret(%d)", ret);
103                 *type = cached;
104         } else if (*type) {
105                 strncpy(cached, *type, MAX_LOCAL_VARIABLE_STRING_LEN - 1);
106                 cached[MAX_LOCAL_VARIABLE_STRING_LEN - 1] = '\0';
107         }
108
109         return ret;
110 }
111
112 int CServiceMain::mas_client_send_preprocessing_information(int pid)
113 {
114         int ret = -1;
115         MAS_LOGD("[Enter] pid(%d)", pid);
116
117         boost::optional<std::string> preprocessing_appid =
118                 mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
119         if (preprocessing_appid) {
120                 MAS_LOGD("preprocessing_assistant_appid : %s", (*preprocessing_appid).c_str());
121                 ret = mServiceIpc.send_preprocessing_information(pid, (*preprocessing_appid).c_str());
122         }
123
124         return ret;
125 }
126
127 int CServiceMain::mas_client_send_voice_key_status_change(int pid, ma_voice_key_status_e status)
128 {
129         int ret = -1;
130         MAS_LOGD("[Enter] pid(%d)", pid);
131
132         ret = mServiceIpc.voice_key_status_change(pid, status);
133         if (0 != ret) {
134                 MAS_LOGE("[ERROR] Fail to send voice key status changed information, ret(%d)", ret);
135         }
136         mLastVoiceKeyStatus = status;
137
138         return ret;
139 }
140
141 int CServiceMain::mas_client_send_asr_result(int pid, int event, const char* asr_result)
142 {
143         MAS_LOGD("[Enter] pid(%d), event(%d), asr_result(%s)", pid, event, asr_result);
144         int ret = mServiceIpc.masc_ui_dbus_send_asr_result(pid, event, asr_result);
145         if (0 != ret){
146                 MAS_LOGE("[ERROR] Fail to send asr result, ret(%d)", ret);
147         }
148
149         // if final event is , launch assistant app which is invoked with wakeup word.
150         /* TO_DO */
151         return ret;
152 }
153
154 int CServiceMain::mas_client_send_result(int pid, const char* display_text,
155         const char* utterance_text, const char* result_json)
156 {
157         MAS_LOGD("[Enter] pid(%d), display_text(%s), utterance_text(%s), result_json(%s)", pid, display_text, utterance_text, result_json);
158         int ret = mServiceIpc.masc_ui_dbus_send_result(pid, display_text, utterance_text, result_json);
159         if (0 != ret){
160                 MAS_LOGE("[ERROR] Fail to send result, ret(%d)", ret);
161         }
162
163         const char* pid_appid = NULL;
164         char buf[MAX_APPID_LEN] = {'\0', };
165         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
166                 buf[MAX_APPID_LEN - 1] = '\0';
167                 pid_appid = buf;
168         }
169         mServicePlugin.update_recognition_result(pid_appid, MA_RECOGNITION_RESULT_EVENT_SUCCESS);
170
171         return ret;
172 }
173
174 int CServiceMain::mas_client_send_recognition_result(int pid, int result)
175 {
176         MAS_LOGD("[Enter] pid(%d), result(%d)", pid, result);
177         int ret = mServiceIpc.masc_ui_dbus_send_recognition_result(pid, result);
178         if (0 != ret){
179                 MAS_LOGE("[ERROR] Fail to send recognition result, ret(%d)", ret);
180         }
181
182         const char* pid_appid = NULL;
183         char buf[MAX_APPID_LEN] = {'\0', };
184         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
185                 buf[MAX_APPID_LEN - 1] = '\0';
186                 pid_appid = buf;
187         }
188         mServicePlugin.update_recognition_result(pid_appid, result);
189
190         return ret;
191 }
192
193 int CServiceMain::mas_client_start_streaming_audio_data(int pid, int type)
194 {
195         int ret = -1;
196         switch(type) {
197                 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
198                         ret = mServicePlugin.start_streaming_utterance_data();
199                         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED);
200                         break;
201                 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
202                         ret = mServicePlugin.start_streaming_previous_utterance_data();
203                         /* Preprocessing is not required for previous utterance streaming */
204                         break;
205                 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
206                         ret = mServicePlugin.start_streaming_follow_up_data();
207                         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED);
208                         break;
209         }
210         return ret;
211 }
212
213 int CServiceMain::mas_client_stop_streaming_audio_data(int pid, int type)
214 {
215         int ret = -1;
216         switch(type) {
217                 case MA_AUDIO_STREAMING_DATA_TYPE_CURRENT_UTTERANCE:
218                         ret = mServicePlugin.stop_streaming_utterance_data();
219                         break;
220                 case MA_AUDIO_STREAMING_DATA_TYPE_PREVIOUS_UTTERANCE:
221                         ret = mServicePlugin.stop_streaming_previous_utterance_data();
222                         break;
223                 case MA_AUDIO_STREAMING_DATA_TYPE_FOLLOW_UP_SPEECH:
224                         ret = mServicePlugin.stop_streaming_follow_up_data();
225                         break;
226         }
227         return ret;
228 }
229
230 int CServiceMain::mas_client_update_voice_feedback_state(int pid, int state)
231 {
232         const char* pid_appid = NULL;
233         char buf[MAX_APPID_LEN] = {'\0', };
234         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
235                 buf[MAX_APPID_LEN - 1] = '\0';
236                 pid_appid = buf;
237         }
238         mServicePlugin.update_voice_feedback_state(pid_appid, state);
239         return 0;
240 }
241
242 int CServiceMain::mas_client_set_assistant_specific_command(int pid, const char *command)
243 {
244         const char* pid_appid = NULL;
245         char buf[MAX_APPID_LEN] = {'\0', };
246         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
247                 buf[MAX_APPID_LEN - 1] = '\0';
248                 pid_appid = buf;
249         }
250         mServicePlugin.set_assistant_specific_command(pid_appid, command);
251         return 0;
252 }
253
254 int CServiceMain::mas_client_set_background_volume(int pid, double ratio)
255 {
256         const char* pid_appid = NULL;
257         char buf[MAX_APPID_LEN] = {'\0', };
258         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
259                 buf[MAX_APPID_LEN - 1] = '\0';
260                 pid_appid = buf;
261         }
262         mServicePlugin.set_background_volume(pid_appid, ratio);
263         return 0;
264 }
265
266 int CServiceMain::mas_client_set_preprocessing_allow_mode(int pid, ma_preprocessing_allow_mode_e mode, const char* appid)
267 {
268         const char* pid_appid = NULL;
269         char buf[MAX_APPID_LEN] = {'\0', };
270         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
271                 buf[MAX_APPID_LEN - 1] = '\0';
272                 pid_appid = buf;
273         }
274
275         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
276                 if (mClientInfo[loop].used) {
277                         if (pid_appid && strncmp(pid_appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
278                                 mClientInfo[loop].preprocessing_allow_mode = mode;
279                                 if (appid) {
280                                         strncpy(mClientInfo[loop].preprocessing_allow_appid, appid, MAX_APPID_LEN);
281                                         mClientInfo[loop].preprocessing_allow_appid[MAX_APPID_LEN - 1] = '\0';
282                                 } else {
283                                         mClientInfo[loop].preprocessing_allow_appid[0] = '\0';
284                                 }
285                         }
286                 }
287         }
288
289         mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED);
290
291         return 0;
292 }
293
294 int CServiceMain::mas_client_send_preprocessing_result(int pid, bool result)
295 {
296         const char* pid_appid = NULL;
297         char buf[MAX_APPID_LEN] = {'\0', };
298         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
299                 buf[MAX_APPID_LEN - 1] = '\0';
300                 pid_appid = buf;
301         }
302         if (!is_current_preprocessing_assistant(pid_appid)) return -1;
303
304         const char *current_maclient_appid = NULL;
305         if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
306                 current_maclient_appid = mClientInfo[mCurrentClientInfo].appid;
307         }
308
309         if (result) {
310                 MAS_LOGD("Preprocessing succeeded, bring (%s) to foreground", pid_appid);
311                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED);
312         } else {
313                 MAS_LOGD("Preprocessing failed, bring (%s) to foreground", current_maclient_appid);
314                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED);
315         }
316
317         if (current_maclient_appid) {
318                 int pid = mClientManager.find_client_pid_by_appid(
319                         std::string{current_maclient_appid});
320                 mServiceIpc.send_preprocessing_result(pid, result);
321         }
322
323         return 0;
324 }
325
326 int CServiceMain::mas_client_set_wake_word_audio_require_flag(int pid, bool require)
327 {
328         const char* pid_appid = NULL;
329         char buf[MAX_APPID_LEN] = {'\0', };
330         if (AUL_R_OK == aul_app_get_appid_bypid(pid, buf, sizeof(buf))) {
331                 buf[MAX_APPID_LEN - 1] = '\0';
332                 pid_appid = buf;
333         }
334
335         mServicePlugin.set_wake_word_audio_require_flag(pid_appid, require);
336         return 0;
337 }
338
339 int CServiceMain::mas_client_set_assistant_language(int pid, const char* language)
340 {
341         const char* pid_appid = NULL;
342         char buf[MAX_APPID_LEN] = {'\0', };
343         int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
344         if (AUL_R_OK == ret) {
345                 buf[MAX_APPID_LEN - 1] = '\0';
346                 pid_appid = buf;
347         }
348
349         mServicePlugin.set_assistant_language(pid_appid, language);
350         return 0;
351 }
352
353 int CServiceMain::mas_client_add_wake_word(int pid, const char* wake_word, const char* language)
354 {
355         const char* pid_appid = NULL;
356         char buf[MAX_APPID_LEN] = {'\0', };
357         int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
358         if (AUL_R_OK == ret) {
359                 buf[MAX_APPID_LEN - 1] = '\0';
360                 pid_appid = buf;
361         }
362
363         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
364                 if (mClientInfo[loop].used &&
365                         0 == strncmp(buf, mClientInfo[loop].appid, MAX_APPID_LEN)) {
366                         ret = mServiceConfig.add_custom_wake_word(wake_word, language,
367                                 mClientInfo[loop].wakeup_word,
368                                 mClientInfo[loop].wakeup_language);
369                         if (0 == ret) {
370                                 mServiceConfig.save_custom_wake_words(pid_appid,
371                                         mClientInfo[loop].wakeup_word,
372                                         mClientInfo[loop].wakeup_language);
373                         } else {
374                                 LOGE("add new wake word failed!");
375                                 return -1;
376                         }
377                 }
378         }
379
380         mServicePlugin.add_assistant_wakeup_word(pid_appid, wake_word, language);
381         return 0;
382 }
383
384 int CServiceMain::mas_client_remove_wake_word(int pid, const char* wake_word, const char* language)
385 {
386         const char* pid_appid = NULL;
387         char buf[MAX_APPID_LEN] = {'\0', };
388         int ret = aul_app_get_appid_bypid(pid, buf, sizeof(buf));
389         if (AUL_R_OK == ret) {
390                 buf[MAX_APPID_LEN - 1] = '\0';
391                 pid_appid = buf;
392         }
393
394         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
395                 if (mClientInfo[loop].used &&
396                         0 == strncmp(buf, mClientInfo[loop].appid, MAX_APPID_LEN)) {
397                         ret = mServiceConfig.remove_custom_wake_word(wake_word, language,
398                                 mClientInfo[loop].wakeup_word,
399                                 mClientInfo[loop].wakeup_language);
400                         if (0 == ret) {
401                                 mServiceConfig.save_custom_wake_words(pid_appid,
402                                         mClientInfo[loop].wakeup_word,
403                                         mClientInfo[loop].wakeup_language);
404                         }
405                 }
406         }
407
408         mServicePlugin.remove_assistant_wakeup_word(pid_appid, wake_word, language);
409         return 0;
410 }
411
412 int CServiceMain::mas_ui_client_initialize(int pid)
413 {
414         MAS_LOGD("[Enter] pid(%d)", pid);
415
416         return 0;
417 }
418
419 int CServiceMain::mas_ui_client_deinitialize(int pid)
420 {
421         MAS_LOGD("[Enter] pid(%d)", pid);
422
423         return 0;
424 }
425
426 int CServiceMain::mas_ui_client_change_assistant(const char* appid)
427 {
428         MAS_LOGD("[Enter]");
429
430         if (NULL == appid) {
431                 MAS_LOGE("NULL parameter");
432                 return -1;
433         }
434
435         bool use_custom_ui = mas_get_client_custom_ui_option_by_appid(appid);
436         mServiceIpc.masc_ui_dbus_enable_common_ui(!use_custom_ui);
437
438         mas_set_current_client_by_appid(appid);
439         int pid = mas_get_client_pid_by_appid(appid);
440         if (pid != -1) {
441                 mas_bring_client_to_foreground(appid);
442                 mas_client_send_preprocessing_information(pid);
443                 if (MA_VOICE_KEY_STATUS_PRESSED == mLastVoiceKeyStatus) {
444                         mas_client_send_voice_key_status_change(pid, mLastVoiceKeyStatus);
445                 }
446
447                 mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
448                 MAS_LOGD("MA Client with appid %s exists, requesting speech data", (appid ? appid : "NULL"));
449                 /*
450                 int ret = mServicePlugin.start_streaming_utterance_data();
451                 if (0 != ret) {
452                         MAS_LOGE("[ERROR] Fail to start streaming utterance data(%d)", ret);
453                 }
454                 */
455         } else {
456                 // Appropriate MA Client not available, trying to launch new one
457                 MAS_LOGD("MA Client with appid %s does not exist, launching client", (appid ? appid : "NULL"));
458
459                 /* The appid parameter might not exist after this function call, so we use appid string in our mClientInfo */
460                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
461                         if (mClientInfo[loop].used &&
462                                 0 < strlen(mClientInfo[loop].appid) &&
463                                 0 < strlen(mClientInfo[loop].wakeup_word[0])) {
464                                 if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
465                                         mas_launch_client_by_appid(mClientInfo[loop].appid, CLIENT_LAUNCH_MODE_ACTIVATION);
466                                 }
467                         }
468                 }
469         }
470
471         return 0;
472 }
473
474 static int mas_assistant_info_cb(ma_assistant_info_s* info, void* user_data) {
475         int ret = -1;
476         CServiceMain* service_main = static_cast<CServiceMain*>(user_data);
477         if (service_main) {
478                 ret = service_main->add_assistant_info(info);
479         }
480         return ret;
481 }
482
483 int CServiceMain::add_assistant_info(ma_assistant_info_s* info) {
484         MAS_LOGD("__mas_assistant_info_cb called");
485
486         if (NULL == info) {
487                 MAS_LOGE("info NULL, returning");
488                 return -1;
489         }
490         if (NULL == info->app_id) {
491                 MAS_LOGE("app_id NULL, returning");
492                 return -1;
493         }
494
495         int index = -1;
496         int loop = 0;
497         while(-1 == index && loop < MAX_MACLIENT_INFO_NUM) {
498                 if (false == mClientInfo[loop].used) {
499                         index = loop;
500                 }
501                 loop++;
502         }
503         if (-1 != index) {
504                 mClientInfo[index].used = true;
505                 mClientInfo[index].preprocessing_allow_mode = MA_PREPROCESSING_ALLOW_NONE;
506                 mClientInfo[index].preprocessing_allow_appid[0] = '\0';
507                 MAS_LOGD("app_id(%s)", info->app_id);
508                 strncpy(mClientInfo[index].appid, info->app_id, MAX_APPID_LEN);
509                 mClientInfo[index].appid[MAX_APPID_LEN - 1] = '\0';
510
511                 if (is_current_preprocessing_assistant(mClientInfo[index].appid)) {
512                         mCurrentPreprocessingClientInfo = index;
513                 }
514
515                 for (loop = 0;loop < MAX_WAKEUP_WORDS_NUM;loop++) {
516                         if (loop < info->cnt_wakeup && info->wakeup_list[loop]) {
517                                 MAS_LOGD("wakeup_list(%d)(%s)(%s)", loop, info->wakeup_list[loop], info->wakeup_language[loop]);
518                                 strncpy(mClientInfo[index].wakeup_word[loop], info->wakeup_list[loop], MAX_WAKEUP_WORD_LEN);
519                                 mClientInfo[index].wakeup_word[loop][MAX_WAKEUP_WORD_LEN - 1] = '\0';
520                                 if (info->wakeup_language[loop]) {
521                                         strncpy(mClientInfo[index].wakeup_language[loop], info->wakeup_language[loop], MAX_SUPPORTED_LANGUAGE_LEN);
522                                         mClientInfo[index].wakeup_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
523                                 } else {
524                                         strncpy(mClientInfo[index].wakeup_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
525                                 }
526                         } else {
527                                 strncpy(mClientInfo[index].wakeup_word[loop], "", MAX_WAKEUP_WORD_LEN);
528                         }
529                 }
530
531                 for (loop = 0;loop < MAX_SUPPORTED_LANGUAGES_NUM;loop++) {
532                         if (loop < info->cnt_lang && info->supported_lang[loop]) {
533                                 MAS_LOGD("supported_lang(%d)(%s)", loop, info->supported_lang[loop]);
534                                 strncpy(mClientInfo[index].supported_language[loop], info->supported_lang[loop], MAX_SUPPORTED_LANGUAGE_LEN);
535                                 mClientInfo[index].supported_language[loop][MAX_SUPPORTED_LANGUAGE_LEN - 1] = '\0';
536                         } else {
537                                 strncpy(mClientInfo[index].supported_language[loop], "", MAX_SUPPORTED_LANGUAGE_LEN);
538                         }
539                 }
540
541                 MAS_LOGD("wakeup_engine(%s)", info->wakeup_engine);
542                 if (info->wakeup_engine) {
543                         strncpy(mClientInfo[index].wakeup_engine, info->wakeup_engine, MAX_APPID_LEN);
544                         mClientInfo[index].wakeup_engine[MAX_APPID_LEN - 1] = '\0';
545                 } else {
546                         mClientInfo[index].wakeup_engine[0] = '\0';
547                         MAS_LOGW("Wakeup engine information not provided for : %s", info->app_id);
548                 }
549                 mClientInfo[index].custom_ui_option = info->custom_ui_option;
550
551                 MAS_LOGD("voice_key_support_mode(%d)", info->voice_key_support_mode);
552                 mClientInfo[index].voice_key_support_mode = info->voice_key_support_mode;
553                 MAS_LOGD("voice_key_tap_duration(%f)", info->voice_key_tap_duration);
554                 mClientInfo[index].voice_key_tap_duration = info->voice_key_tap_duration;
555         } else {
556                 MAS_LOGD("Couldn't find an empty slot for storing assistant info");
557         }
558
559         MAS_LOGD("__mas_assistant_info_cb end");
560
561         return 0;
562 }
563
564 static void active_state_changed_cb(std::string key, void* user_data)
565 {
566         IPreferenceManager* manager = static_cast<IPreferenceManager*>(user_data);
567         if (nullptr == manager) return;
568
569         boost::optional<bool> activated =
570                 manager->get_bool(MULTI_ASSISTANT_SETTINGS_ACTIVATED);
571         if (activated) {
572                 MAS_LOGD("multi-assistant active state : %d\n", *activated);
573
574                 CServicePlugin *plugin = nullptr;
575                 if (g_service_main) {
576                         plugin = g_service_main->get_service_plugin();
577                 }
578                 if (plugin) {
579                         if (*activated) {
580                                 plugin->activate();
581                         } else {
582                                 plugin->deactivate();
583                         }
584                 } else {
585                         MAS_LOGE("Could not change plugin state : %p %p", g_service_main, plugin);
586                 }
587         }
588 }
589
590 int CServiceMain::initialize_service_plugin(void)
591 {
592         if (0 != mServicePlugin.initialize()) {
593                 MAS_LOGE("Fail to ws intialize");
594                 return -1;
595         }
596
597         if (0 != mServicePlugin.set_language(mCurrentLanguage.c_str())) {
598                 MAS_LOGE("Fail to ws set language");
599                 return -1;
600         }
601
602         if (0 == mServiceConfig.get_assistant_info(mas_assistant_info_cb, this)) {
603                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
604                         int inner_loop;
605                         if (mClientInfo[loop].used &&
606                                 0 < strlen(mClientInfo[loop].appid)) {
607                                 mServiceConfig.load_custom_wake_words(mClientInfo[loop].appid,
608                                         mClientInfo[loop].wakeup_word, mClientInfo[loop].wakeup_language);
609                                 if (0 < strlen(mClientInfo[loop].wakeup_engine)) {
610                                         mServicePlugin.set_assistant_wakeup_engine(
611                                                 mClientInfo[loop].appid,
612                                                 mClientInfo[loop].wakeup_engine);
613                                 }
614                                 for (inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
615                                         if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
616                                                 MAS_LOGD("Registering wakeup word %s for app %s",
617                                                         mClientInfo[loop].wakeup_word[inner_loop], mClientInfo[loop].appid);
618                                                 if (0 != mServicePlugin.add_assistant_wakeup_word(
619                                                         mClientInfo[loop].appid,
620                                                         mClientInfo[loop].wakeup_word[inner_loop],
621                                                         mClientInfo[loop].wakeup_language[inner_loop])) {
622                                                         MAS_LOGE("Fail to add assistant's wakeup word");
623                                                 }
624                                         }
625                                 }
626                                 for (inner_loop = 0; inner_loop < MAX_SUPPORTED_LANGUAGE_NUM; inner_loop++) {
627                                         if (0 < strlen(mClientInfo[loop].supported_language[inner_loop])) {
628                                                 MAS_LOGD("Adding language %s for app %s",
629                                                         mClientInfo[loop].supported_language[inner_loop], mClientInfo[loop].appid);
630                                                 if (0 != mServicePlugin.add_assistant_language(
631                                                         mClientInfo[loop].appid,
632                                                         mClientInfo[loop].supported_language[inner_loop])) {
633                                                         MAS_LOGE("Fail to add assistant's language");
634                                                 }
635                                         }
636                                 }
637                         }
638                 }
639         } else {
640                 MAS_LOGE("Fail to load assistant info");
641         }
642
643         if (0 != mServicePlugin.set_callbacks()) {
644                 MAS_LOGE("Fail to set callbacks");
645                 return -1;
646         }
647
648         return 0;
649 }
650
651 int CServiceMain::deinitialize_service_plugin(void)
652 {
653         MAS_LOGI("[ENTER]");
654         if (0 != mServicePlugin.deactivate()) {
655                 MAS_LOGE("Fail to deactivate");
656         }
657         if (0 != mServicePlugin.deinitialize()) {
658                 MAS_LOGE("Fail to deinitialize");
659         }
660         MAS_LOGI("[END]");
661         return 0;
662 }
663
664 int CServiceMain::process_activated_setting()
665 {
666         if (mPreferenceManager.register_changed_callback(
667                 MULTI_ASSISTANT_SETTINGS_ACTIVATED, active_state_changed_cb, &mPreferenceManager)) {
668                 /* Activate / deactivate according to the vconf key setting */
669                 active_state_changed_cb(std::string{}, &mPreferenceManager);
670         } else {
671 #ifdef ENABLE_MULTI_ASSISTANT_BY_DEFAULT
672                 /* Multi-assistant needs to be enabled by default, unless disabled explicitly */
673                 mServicePlugin.activate();
674                 const char *default_assistant = NULL;
675                 if (0 == mServicePlugin.get_default_assistant(&default_assistant)) {
676                         if (NULL == default_assistant) {
677                                 if (mClientInfo[0].used) {
678                                         default_assistant = mClientInfo[0].appid;
679                                         MAS_LOGW("No default assistant, setting %s as default", default_assistant);
680                                         mServicePlugin.set_default_assistant(default_assistant);
681                                 } else {
682                                         MAS_LOGE("No default assistant, and no assistant installed");
683                                 }
684                         }
685                 }
686 #endif
687         }
688         return 0;
689 }
690
691 int CServiceMain::mas_get_current_client_pid()
692 {
693         int ret = -1;
694         if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
695                 const char *appid = mClientInfo[mCurrentClientInfo].appid;
696                 if (appid) {
697                         ret = mClientManager.find_client_pid_by_appid(std::string{appid});
698                 }
699         }
700         return ret;
701 }
702
703 int CServiceMain::mas_get_current_preprocessing_client_pid()
704 {
705         int ret = -1;
706         if (mCurrentPreprocessingClientInfo >= 0 && mCurrentPreprocessingClientInfo < MAX_MACLIENT_INFO_NUM) {
707                 const char *appid = mClientInfo[mCurrentPreprocessingClientInfo].appid;
708                 if (appid) {
709                         ret = mClientManager.find_client_pid_by_appid(std::string{appid});
710                 }
711         }
712         return ret;
713 }
714
715 int CServiceMain::mas_get_client_pid_by_appid(const char *appid)
716 {
717         int ret = -1;
718
719         if (appid) {
720                 ret = mClientManager.find_client_pid_by_appid(std::string{appid});
721         }
722
723         int status = aul_app_get_status_bypid(ret);
724         if (-1 != ret && 0 > status) {
725                 MAS_LOGE("The PID for %s was %d, but it seems to be terminated : %d",
726                         (appid ? appid : "NULL"), ret, status);
727                 on_deinitialize(ret);
728                 ret = -1;
729         }
730
731         return ret;
732 }
733
734 bool CServiceMain::mas_get_client_custom_ui_option_by_appid(const char *appid)
735 {
736         bool ret = false;
737         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
738                 if (mClientInfo[loop].used &&
739                         0 < strlen(mClientInfo[loop].appid) &&
740                         0 < strlen(mClientInfo[loop].wakeup_word[0])) {
741                         if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
742                                 ret = mClientInfo[loop].custom_ui_option;
743                         }
744                 }
745         }
746         return ret;
747 }
748
749 int CServiceMain::mas_get_client_pid_by_wakeup_word(const char *wakeup_word)
750 {
751         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
752         return mas_get_client_pid_by_appid(appid);
753 }
754
755 const char* CServiceMain::mas_get_client_appid_by_wakeup_word(const char *wakeup_word)
756 {
757         int loop;
758         const char *appid = NULL;
759
760         if (NULL == wakeup_word) return NULL;
761
762         for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
763                 if (mClientInfo[loop].used &&
764                         0 < strlen(mClientInfo[loop].appid)) {
765                         for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
766                                 if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
767                                         if (0 == strncmp(wakeup_word, mClientInfo[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
768                                                 appid = mClientInfo[loop].appid;
769                                         }
770                                 }
771                         }
772                 }
773         }
774
775         /* Perform extended search, by eliminating blank characters */
776         if (NULL == appid) {
777                 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && NULL == appid; loop++) {
778                         if (mClientInfo[loop].used &&
779                                 0 < strlen(mClientInfo[loop].appid)) {
780                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
781                                         if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
782                                                 char comparand[MAX_WAKEUP_WORD_LEN];
783                                                 int comparand_index = 0;
784                                                 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
785                                                         if (' ' != mClientInfo[loop].wakeup_word[inner_loop][index]) {
786                                                                 comparand[comparand_index++] = mClientInfo[loop].wakeup_word[inner_loop][index];
787                                                         }
788                                                 }
789                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
790                                                         appid = mClientInfo[loop].appid;
791                                                 }
792                                         }
793                                 }
794                         }
795                 }
796         }
797
798         return appid;
799 }
800
801 int CServiceMain::mas_set_current_client_by_wakeup_word(const char *wakeup_word)
802 {
803         int loop;
804         int ret = -1;
805         int prev_selection = mCurrentClientInfo;
806
807         for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
808                 if (mClientInfo[loop].used &&
809                         0 < strlen(mClientInfo[loop].appid)) {
810                         for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
811                                 if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
812                                         if (0 == strncmp(wakeup_word, mClientInfo[loop].wakeup_word[inner_loop], MAX_WAKEUP_WORD_LEN)) {
813                                                 mCurrentClientInfo = loop;
814                                                 ret = 0;
815                                         }
816                                 }
817                         }
818                 }
819         }
820         /* Perform extended search, by eliminating blank characters */
821         if (ret == -1) {
822                 for (loop = 0; loop < MAX_MACLIENT_INFO_NUM && -1 == ret; loop++) {
823                         if (mClientInfo[loop].used &&
824                                 0 < strlen(mClientInfo[loop].appid)) {
825                                 for (int inner_loop = 0; inner_loop < MAX_WAKEUP_WORDS_NUM; inner_loop++) {
826                                         if (0 < strlen(mClientInfo[loop].wakeup_word[inner_loop])) {
827                                                 char comparand[MAX_WAKEUP_WORD_LEN];
828                                                 int comparand_index = 0;
829                                                 for (int index = 0; index < MAX_WAKEUP_WORD_LEN; index++) {
830                                                         if (' ' != mClientInfo[loop].wakeup_word[inner_loop][index]) {
831                                                                 comparand[comparand_index++] = mClientInfo[loop].wakeup_word[inner_loop][index];
832                                                         }
833                                                 }
834                                                 if (0 == strncmp(wakeup_word, comparand, MAX_WAKEUP_WORD_LEN)) {
835                                                         mCurrentClientInfo = loop;
836                                                         ret = 0;
837                                                 }
838                                         }
839                                 }
840                         }
841                 }
842         }
843
844         if (mCurrentClientInfo != prev_selection) {
845                 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
846                         int pid = mas_get_client_pid_by_appid(mClientInfo[prev_selection].appid);
847                         mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
848                 }
849         }
850
851         return ret;
852 }
853
854 int CServiceMain::mas_set_current_client_by_appid(const char *appid)
855 {
856         int ret = -1;
857         int prev_selection = mCurrentClientInfo;
858
859         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
860                 if (mClientInfo[loop].used &&
861                         0 < strlen(mClientInfo[loop].appid) &&
862                         0 < strlen(mClientInfo[loop].wakeup_word[0])) {
863                         if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
864                                 mCurrentClientInfo = loop;
865                                 ret = 0;
866                         }
867                 }
868         }
869
870         if (mCurrentClientInfo != prev_selection) {
871                 if (prev_selection >= 0 && prev_selection < MAX_MACLIENT_INFO_NUM) {
872                         int pid = mas_get_client_pid_by_appid(mClientInfo[prev_selection].appid);
873                         mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_INACTIVE);
874                 }
875         }
876
877         return ret;
878 }
879
880 int CServiceMain::mas_launch_client_by_appid(const char *appid, CLIENT_LAUNCH_MODE launch_mode)
881 {
882         if (NULL == appid || 0 == strlen(appid)) {
883                 MAS_LOGE("appid invalid, failed launching MA Client");
884                 return -1;
885         }
886
887         if (CLIENT_LAUNCH_MODE_PRELAUNCH == launch_mode) {
888                 if (1 == aul_app_is_running(appid)) {
889                         MAS_LOGE("appid %s is already running, no need for a prelaunch", appid);
890                         return -1;
891                 }
892         }
893
894         bundle *b = NULL;
895         b = bundle_create();
896         if (NULL == b) {
897                 MAS_LOGE("Failed creating bundle for aul operation");
898                 return -1;
899         }
900
901         int result = aul_svc_set_background_launch(b,
902                 (CLIENT_LAUNCH_MODE_PRELAUNCH == launch_mode ? TRUE : FALSE));
903         if (result < AUL_R_OK) {
904                 MAS_LOGE("ERROR : aul_svc_set_background_launch failed. app_id [%s] bundle[%p] result[%d : %s]",
905                         appid, b, result, get_error_message(result));
906         }
907
908         result = aul_launch_app_async(appid, b);
909         if (result < AUL_R_OK) {
910                 MAS_LOGE("ERROR : aul_launch_app_async failed. app_id [%s] bundle[%p] result[%d : %s]",
911                         appid, b, result, get_error_message(result));
912         }
913
914         if (CLIENT_LAUNCH_MODE_ACTIVATION == launch_mode) {
915                 bool found = false;
916                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
917                         if (mClientInfo[loop].used &&
918                                 0 < strlen(mClientInfo[loop].appid)) {
919                                 if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
920                                         mWakeupClientAppId = mClientInfo[loop].appid;
921                                         found = true;
922                                 }
923                         }
924                 }
925                 MAS_LOGD("mWakeupClientAppId : %s, %d", mWakeupClientAppId.c_str(), found);
926         }
927
928         if (b) bundle_free(b);
929         b = NULL;
930
931         return result;
932 }
933
934 int CServiceMain::mas_bring_client_to_foreground(const char* appid)
935 {
936         /* Bring MA client to foreground - is there a better way other than launching? */
937         if (NULL == appid || 0 == strlen(appid)) {
938                 MAS_LOGE("appid invalid, failed launching MA Client");
939                 return -1;
940         }
941
942         bundle *b = NULL;
943         b = bundle_create();
944         if (NULL == b) {
945                 MAS_LOGE("Failed creating bundle for aul operation");
946                 return -1;
947         }
948
949         int result = aul_launch_app(appid, b);
950         if (result < AUL_R_OK) {
951                 MAS_LOGE("ERROR : aul_launch_app failed. app_id [%s] bundle[%p] result[%d : %s]",
952                         appid, b, result, get_error_message(result));
953         }
954
955         if (b) bundle_free(b);
956         b = NULL;
957
958         return result;
959 }
960
961 int CServiceMain::mas_launch_client_by_wakeup_word(const char *wakeup_word)
962 {
963         const char *appid = mas_get_client_appid_by_wakeup_word(wakeup_word);
964         return mas_launch_client_by_appid(appid, CLIENT_LAUNCH_MODE_ACTIVATION);
965 }
966
967 int CServiceMain::mas_prelaunch_default_assistant()
968 {
969         /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
970         boost::optional<bool> prelaunch_mode =
971                 mPreferenceManager.get_bool(WAKEUP_SETTINGS_KEY_PRELAUNCH_MODE);
972         if (prelaunch_mode && *prelaunch_mode) {
973                 const char *default_assistant = NULL;
974                 if (0 == mServicePlugin.get_default_assistant(&default_assistant)) {
975                         if (0 == aul_app_is_running(default_assistant)) {
976                                 MAS_LOGD("prelaunching default_assistant_appid : %s", default_assistant);
977                                 mas_launch_client_by_appid(default_assistant, CLIENT_LAUNCH_MODE_PRELAUNCH);
978                         }
979                 }
980         }
981         return 0;
982 }
983
984 int CServiceMain::mas_update_voice_key_support_mode()
985 {
986         /* CHECK NEEDED : should the code segment below and activation logic above be moved to wakeup manger? */
987         bool successful = false;
988         const char *default_assistant = NULL;
989         if (0 == mServicePlugin.get_default_assistant(&default_assistant)) {
990                 for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
991                         if (mClientInfo[loop].used) {
992                                 if (default_assistant &&
993                                         strncmp(default_assistant, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
994                                         float duration = mClientInfo[loop].voice_key_tap_duration;
995                                         if (0.0f < duration) {
996                                                 mServicePlugin.set_voice_key_tap_duration(duration);
997                                         } else {
998                                                 mServicePlugin.unset_voice_key_tap_duration();
999                                         }
1000                                         mServicePlugin.set_voice_key_support_mode(
1001                                                 mClientInfo[loop].voice_key_support_mode);
1002                                         successful = true;
1003                                 }
1004                         }
1005                 }
1006         }
1007
1008         if (!successful) {
1009                 mServicePlugin.unset_voice_key_tap_duration();
1010                 mServicePlugin.set_voice_key_support_mode(VOICE_KEY_SUPPORT_MODE_NONE);
1011         }
1012         return 0;
1013 }
1014
1015 ma_preprocessing_allow_mode_e CServiceMain::get_preprocessing_allow_mode(const char* appid)
1016 {
1017         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM; loop++) {
1018                 if (appid && mClientInfo[loop].used) {
1019                         if (strncmp(appid, mClientInfo[loop].appid, MAX_APPID_LEN) == 0) {
1020                                 return mClientInfo[loop].preprocessing_allow_mode;
1021                         }
1022                 }
1023         }
1024         return MA_PREPROCESSING_ALLOW_NONE;
1025 }
1026
1027 /* This might need to be read from settings in the future, but using macro for now */
1028 //#define BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1029
1030 int CServiceMain::mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT event)
1031 {
1032         const char* current_maclient_appid = NULL;
1033         const char* preprocessing_allow_appid = NULL;
1034         if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
1035                 current_maclient_appid = mClientInfo[mCurrentClientInfo].appid;
1036                 preprocessing_allow_appid = mClientInfo[mCurrentClientInfo].preprocessing_allow_appid;
1037         }
1038         ma_preprocessing_allow_mode_e mode = get_preprocessing_allow_mode(current_maclient_appid);
1039
1040         switch (event) {
1041                 case PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED:
1042                 {
1043 #ifndef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1044                         /* If there is no need to bring preprocessing assistant to front,
1045                                 current_maclient should always be brought to front */
1046                         mas_bring_client_to_foreground(current_maclient_appid);
1047 #endif
1048                         mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1049                         if (check_preprocessing_assistant_exists()) {
1050                                 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1051                                         MA_PREPROCESSING_ALLOW_ALL == mode) {
1052                                         if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1053                                                 mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1054                                         }
1055                                 }
1056                         } else {
1057 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1058                                 /* If preprocessing assistant does not exist, there is no way to enable
1059                                         preprocessing assistant, so bring current maclient to front right away */
1060                                 mas_bring_client_to_foreground(current_maclient_appid);
1061 #endif
1062                         }
1063                 }
1064                 break;
1065                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_ALLOW_MODE_CHANGED:
1066                 {
1067                         mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED;
1068                         /* Enable preprocessing mode only if the preprocessing assistant exists */
1069                         if (check_preprocessing_assistant_exists()) {
1070                                 if (MA_PREPROCESSING_ALLOW_UTTERANCE == mode ||
1071                                         MA_PREPROCESSING_ALLOW_ALL == mode) {
1072                                         if (is_current_preprocessing_assistant(preprocessing_allow_appid)) {
1073                                                 mCurrentPreprocessingState = PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED;
1074                                         }
1075                                 }
1076                         }
1077                 }
1078                 break;
1079                 case PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED:
1080                 {
1081                         if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_ENABLED == mCurrentPreprocessingState) {
1082                                 mCurrentPreprocessingState = PREPROCESSING_STATE_PREPROCESSING_UTTERANCE;
1083                         } else if (PREPROCESSING_STATE_WAKEUP_PREPROCESS_DISABLED == mCurrentPreprocessingState) {
1084                                 /* If preprocessing assistant does not exist, the current_maclient
1085                                         would have been brought to front already on wakeup event */
1086 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1087                                 if (check_preprocessing_assistant_exists()) {
1088                                         mas_bring_client_to_foreground(current_maclient_appid);
1089                                 }
1090 #endif
1091                                 mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1092                         }
1093                 }
1094                 break;
1095                 case PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED:
1096                 {
1097                         mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1098                         if (check_preprocessing_assistant_exists()) {
1099                                 if (MA_PREPROCESSING_ALLOW_FOLLOW_UP == mode ||
1100                                         MA_PREPROCESSING_ALLOW_ALL == mode) {
1101                                         mCurrentPreprocessingState = PREPROCESSING_STATE_PREPROCESSING_FOLLOW_UP;
1102                                 }
1103                         }
1104                 }
1105                 break;
1106                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_SUCCEEDED:
1107                 {
1108 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1109                         if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == mCurrentPreprocessingState ||
1110                                 PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == mCurrentPreprocessingState) {
1111                                 boost::optional<std::string> preprocessing_assistant =
1112                                         mPreferenceManager.get_bool(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
1113                                 if (preprocessing_assistant) {
1114                                         MAS_LOGD("preprocessing_assistant_appid : %s", (*preprocessing_assistant).c_str());
1115                                         mas_bring_client_to_foreground((*preprocessing_assistant).c_str());
1116                                 }
1117                         }
1118 #endif
1119                         mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1120                 }
1121                 break;
1122                 case PREPROCESSING_STATE_EVENT_PREPROCESSING_FAILED:
1123                 {
1124 #ifdef BRING_PREPROCESSING_ASSISTANT_TO_FRONT
1125                         if (PREPROCESSING_STATE_EVENT_UTTERANCE_STREAMING_STARTED == mCurrentPreprocessingState ||
1126                                 PREPROCESSING_STATE_EVENT_FOLLOW_UP_STREAMING_STARTED == mCurrentPreprocessingState) {
1127                                 mas_bring_client_to_foreground(current_maclient_appid);
1128                         }
1129 #endif
1130                         mCurrentPreprocessingState = PREPROCESSING_STATE_NONE;
1131                 }
1132                 break;
1133         }
1134         return 0;
1135 }
1136
1137 int CServiceMain::mas_set_current_service_state(ma_service_state_e state)
1138 {
1139         mCurrentServiceState = state;
1140
1141         ma_client_s *data = NULL;
1142
1143         int count = mClientManager.get_client_num();
1144         int i;
1145
1146         for (i = 0; i < count; i++) {
1147                 int pid = mClientManager.find_client_pid_by_index(i);
1148
1149                 if (-1 != pid) {
1150                         int ret = mServiceIpc.service_state_change(pid, state);
1151                         if (0 != ret) {
1152                                 MAS_LOGE("[ERROR] Fail to set service state change to %d, ret(%d)", pid, ret);
1153                         }
1154                 }
1155         }
1156         return 0;
1157 }
1158
1159 ma_service_state_e CServiceMain::mas_get_current_service_state()
1160 {
1161         return mCurrentServiceState;
1162 }
1163
1164 bool CServiceMain::is_valid_wakeup_engine(const char* appid)
1165 {
1166         for (int loop = 0; loop < MAX_MACLIENT_INFO_NUM;loop++) {
1167                 if (mClientInfo[loop].used) {
1168                         LOGD("comparing appid : %s %s", mClientInfo[loop].wakeup_engine, appid);
1169                         if (0 == strncmp(mClientInfo[loop].wakeup_engine, appid, MAX_APPID_LEN)) {
1170                                 return true;
1171                         }
1172                 }
1173         }
1174         return false;
1175 }
1176
1177 int pkg_app_list_cb(const pkgmgrinfo_appinfo_h handle, void *user_data)
1178 {
1179         if (nullptr == g_service_main) return -1;
1180
1181         char *appid = NULL;
1182
1183         int ret = pkgmgrinfo_appinfo_get_appid(handle, &appid);
1184         if (PMINFO_R_OK == ret && NULL != appid) {
1185                 int *result = (int*)user_data;
1186                 if (result) {
1187                         bool exists = g_service_main->is_valid_wakeup_engine(appid);
1188                         if (exists) {
1189                                 *result = 1;
1190                         }
1191                 }
1192         } else {
1193                 LOGE("pkgmgrinfo_appinfo_get_appid failed! error code=%d", ret);
1194         }
1195
1196         return 0;
1197 }
1198
1199 /*
1200 INFO: Package install/update/uninstall scenario
1201 Install and Uninstall are obviously simple.
1202    Install: just INSTALL
1203    Uninstall: just UNINSTALL
1204 Update package (change the source codes and Run As again), there are four scenarios:
1205 1. UPDATE
1206    Source code change
1207 2. UNINSTALL -> INSTALL
1208    This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Check "Enable Project specific settings"
1209    and change Application ID in tizen-manifest.xml file and Run As.
1210 3. UPDATE -> INSTALL
1211    This happens when Tizen IDE Property > Tizen SDK > Rapid Development Support > Uncheck "Enable Project specific settings"
1212    and change Application ID in tizen-manifest.xml file and Run As.
1213    At UPDATE event, pkgid (package parameter) is invalid...
1214 4. UPDATE
1215    Exceptionally, only UPDATE can be called when Application ID in tizen-manifest.xml file is changed.
1216    At UPDATE event, pkgid (package parameter) is valid, and only appid is changed; the previous appid is invalid.
1217 */
1218 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)
1219 {
1220         CServiceMain* service_main = static_cast<CServiceMain*>(user_data);
1221
1222         int ret = 0;
1223         uid_t uid = getuid();
1224         pkgmgrinfo_pkginfo_h handle = NULL;
1225         static bool in_progress = false;
1226         bool should_exit = false;
1227
1228         if (!package || !type)
1229                 return;
1230
1231         if (PACKAGE_MANAGER_EVENT_TYPE_UPDATE != event_type &&
1232                 PACKAGE_MANAGER_EVENT_TYPE_INSTALL != event_type &&
1233                 PACKAGE_MANAGER_EVENT_TYPE_UNINSTALL != event_type)
1234                 return;
1235
1236         if (PACKAGE_MANAGER_EVENT_STATE_STARTED != event_state &&
1237                 PACKAGE_MANAGER_EVENT_STATE_COMPLETED != event_state)
1238                 return;
1239
1240         bool user = false;
1241         MAS_LOGD("type=%s package=%s event_type=%d event_state=%d progress=%d error=%d",
1242                 type, package, event_type, event_state, progress, error);
1243         ret = pkgmgrinfo_pkginfo_get_pkginfo(package, &handle);
1244         if (ret != PMINFO_R_OK || NULL == handle) {
1245                 MAS_LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid());
1246                 /* Try to get in user packages */
1247                 user = true;
1248                 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(package, uid, &handle);
1249                 if (ret != PMINFO_R_OK || NULL == handle) {
1250                         MAS_LOGW("Failed to call pkgmgrinfo_pkginfo_get_pkginfo & get_usr_pkginfo(\"%s\",~) returned %d, uid : %d", package, ret, getuid());
1251                         return;
1252                 }
1253         }
1254
1255         if (user) {
1256                 /* Try to get in user packages */
1257                 pkgmgrinfo_appinfo_get_usr_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret, uid);
1258         }  else {
1259                 /* Try to get in global packages */
1260                 pkgmgrinfo_appinfo_get_list(handle, PMINFO_ALL_APP, pkg_app_list_cb, (void *)&ret);
1261         }
1262         if (1 == ret) {
1263                 if (PACKAGE_MANAGER_EVENT_STATE_STARTED == event_state) {
1264                         MAS_LOGI("processing PACKAGE_MANAGER_EVENT_STATE_STARTED event : %d", event_type);
1265                         if (false == in_progress) {
1266                                 in_progress = true;
1267                                 if (service_main) {
1268                                         service_main->deinitialize_service_plugin();
1269                                 } else {
1270                                         MAS_LOGE("service_main is NULL");
1271                                 }
1272                         }
1273                 } else if (PACKAGE_MANAGER_EVENT_STATE_COMPLETED == event_state) {
1274                         MAS_LOGI("processing PACKAGE_MANAGER_EVENT_STATE_COMPLETED event : %d", event_type);
1275                         if (false == in_progress) {
1276                                 if (service_main) {
1277                                         service_main->deinitialize_service_plugin();
1278                                 } else {
1279                                         MAS_LOGE("service_main is NULL");
1280                                 }
1281                         }
1282                         /*
1283                         if (service_main) {
1284                                 service_main->initialize_service_plugin();
1285                                 service_main->process_activated_setting();
1286                         } else {
1287                                 MAS_LOGE("service_main is NULL");
1288                         }
1289                         */
1290                         should_exit = true;
1291                         in_progress = false;
1292                 }
1293         }
1294
1295         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
1296
1297         if (should_exit) {
1298                 LOGI("Now restarting multi-assistant-service for reloading updated modules");
1299                 service_app_exit();
1300         }
1301
1302         return;
1303 }
1304
1305 bool CServiceMain::app_create(void *data)
1306 {
1307         // Todo: add your code here.
1308         MAS_LOGD("[Enter] Service app create");
1309
1310         g_service_main = this;
1311
1312         mClientManager.set_application_manager(&mApplicationManager);
1313
1314         mServiceIpc.set_client_manager(&mClientManager);
1315         mServiceIpc.set_service_ipc_observer(this);
1316
1317         mServicePlugin.set_service_ipc(&mServiceIpc);
1318         mServicePlugin.set_service_main(this);
1319
1320         int ret = mServiceIpc.open_connection();
1321         if (0 != ret) {
1322                 MAS_LOGE("[ERROR] Fail to open connection");
1323         }
1324
1325         initialize_service_plugin();
1326
1327         process_activated_setting();
1328
1329         mas_prelaunch_default_assistant();
1330         mas_update_voice_key_support_mode();
1331
1332         /* For the case of preprocessing assistant, it always have to be launched beforehand */
1333         boost::optional<std::string> preprocessing_assistant =
1334                 mPreferenceManager.get_string(WAKEUP_SETTINGS_KEY_PREPROCESSING_ASSISTANT_APPID);
1335         if (preprocessing_assistant) {
1336                 MAS_LOGD("prelaunching preprocessing_assistant_appid : %s", (*preprocessing_assistant).c_str());
1337                 mas_launch_client_by_appid((*preprocessing_assistant).c_str(), CLIENT_LAUNCH_MODE_PRELAUNCH);
1338         }
1339
1340         if (!mPackageManagerHandle) {
1341                 int ret = package_manager_create(&mPackageManagerHandle);
1342                 if (ret == PACKAGE_MANAGER_ERROR_NONE) {
1343                         ret = package_manager_set_event_cb(mPackageManagerHandle, _package_manager_event_cb, this);
1344                         if (ret == PACKAGE_MANAGER_ERROR_NONE) {
1345                                 LOGD("package_manager_set_event_cb succeeded.");
1346                         } else {
1347                                 LOGE("package_manager_set_event_cb failed(%d)", ret);
1348                         }
1349                 } else {
1350                         LOGE("package_manager_create failed(%d)", ret);
1351                 }
1352         }
1353
1354         return true;
1355 }
1356
1357 void CServiceMain::app_terminate(void *data)
1358 {
1359         MAS_LOGI("[ENTER]");
1360         if (mPackageManagerHandle) {
1361                 package_manager_unset_event_cb(mPackageManagerHandle);
1362                 package_manager_destroy(mPackageManagerHandle);
1363                 mPackageManagerHandle = NULL;
1364         }
1365
1366         deinitialize_service_plugin();
1367
1368         mPreferenceManager.unregister_changed_callback(
1369                 MULTI_ASSISTANT_SETTINGS_ACTIVATED, active_state_changed_cb);
1370
1371         int ret = mServiceIpc.close_connection();
1372         if (0 != ret) {
1373                 MAS_LOGE("[ERROR] Fail to close connection");
1374         }
1375
1376         g_service_main = nullptr;
1377
1378         MAS_LOGI("[END]");
1379         return;
1380 }
1381
1382 int CServiceMain::on_initialize(int pid) {
1383         MAS_LOGD("[Enter] pid(%d)", pid);
1384
1385         char appid[MAX_APPID_LEN] = {'\0', };
1386         if (AUL_R_OK == aul_app_get_appid_bypid(pid, appid, sizeof(appid))) {
1387                 appid[MAX_APPID_LEN - 1] = '\0';
1388
1389                 MAS_LOGD("appid for pid %d is : %s", pid, (appid ? appid : "Unknown"));
1390
1391                 /* Remove existing client that has same appid, if there's any */
1392                 mClientManager.destroy_client_by_appid(appid);
1393
1394                 /* And remove a client that has same pid also */
1395                 mClientManager.destroy_client_by_pid(pid);
1396
1397                 mClientManager.create_client(pid, appid);
1398
1399                 const char *current_maclient_appid = NULL;
1400                 if (mCurrentClientInfo >= 0 && mCurrentClientInfo < MAX_MACLIENT_INFO_NUM) {
1401                         current_maclient_appid = mClientInfo[mCurrentClientInfo].appid;
1402                 }
1403
1404                 mas_client_send_preprocessing_information(pid);
1405                 if (MA_VOICE_KEY_STATUS_PRESSED == mLastVoiceKeyStatus) {
1406                         mas_client_send_voice_key_status_change(pid, mLastVoiceKeyStatus);
1407                 }
1408                 if (current_maclient_appid && 0 == strncmp(current_maclient_appid, appid, MAX_APPID_LEN)) {
1409                         MAS_LOGD("MA client with current maclient appid connected!");
1410
1411                         if (0 == mWakeupClientAppId.compare(appid)) {
1412                                 mWakeupClientAppId.clear();
1413                                 mServiceIpc.active_state_change(pid, MA_ACTIVE_STATE_ACTIVE);
1414                                 mas_process_preprocessing_state_event(PREPROCESSING_STATE_EVENT_ASSISTANT_ACTIVATED);
1415                         } else {
1416                                 MAS_LOGE("[ERROR] mWakeupClientAppId and appid differ : %s %s",
1417                                         mWakeupClientAppId.c_str(), appid);
1418                         }
1419                 } else {
1420                         MAS_LOGD("MA client connected, but its appid does not match with current maclient");
1421                 }
1422
1423                 mServiceIpc.service_state_change(pid, mas_get_current_service_state());
1424         } else {
1425                 MAS_LOGE("[ERROR] Fail to retrieve appid");
1426         }
1427
1428         return 0;
1429 }
1430
1431 int CServiceMain::on_deinitialize(int pid) {
1432         MAS_LOGD("[Enter] pid(%d)", pid);
1433         mClientManager.destroy_client_by_pid(pid);
1434         return 0;
1435 }
1436
1437 int CServiceMain::on_get_audio_format(int pid, int& rate, int& channel, int& audio_type) {
1438         int main_rate, main_channel, main_audio_type;
1439         int ret = mas_client_get_audio_format(pid,
1440                 &main_rate, &main_channel, &main_audio_type);
1441         rate = main_rate;
1442         channel = main_channel;
1443         audio_type = main_audio_type;
1444         return ret;
1445 }
1446
1447 int CServiceMain::on_get_audio_source_type(int pid, std::string& type) {
1448         char *main_type = nullptr;
1449         int ret = mas_client_get_audio_source_type(pid, &main_type);
1450         if (0 == ret && main_type) {
1451                 type = std::string{main_type};
1452         }
1453         return ret;
1454 }
1455
1456 int CServiceMain::on_send_asr_result(int pid, int event, std::string asr_result) {
1457         return mas_client_send_asr_result(pid, event, asr_result.c_str());
1458 }
1459
1460 int CServiceMain::on_send_result(int pid, std::string display_text,
1461         std::string utterance_text, std::string result_json) {
1462         return mas_client_send_result(pid,
1463                 display_text.c_str(), utterance_text.c_str(), result_json.c_str());
1464 }
1465
1466 int CServiceMain::on_send_recognition_result(int pid, int result) {
1467         return mas_client_send_recognition_result(pid, result);
1468 }
1469
1470 int CServiceMain::on_start_streaming_audio_data(int pid, int type) {
1471         return mas_client_start_streaming_audio_data(pid, type);
1472 }
1473
1474 int CServiceMain::on_stop_streaming_audio_data(int pid, int type) {
1475         return mas_client_stop_streaming_audio_data(pid, type);
1476 }
1477
1478 int CServiceMain::on_update_voice_feedback_state(int pid, int state) {
1479         return mas_client_update_voice_feedback_state(pid, state);
1480 }
1481
1482 int CServiceMain::on_send_assistant_specific_command(int pid, std::string command) {
1483         return mas_client_set_assistant_specific_command(pid, command.c_str());
1484 }
1485
1486 int CServiceMain::on_set_background_volume(int pid, double ratio) {
1487         return mas_client_set_background_volume(pid, ratio);
1488 }
1489
1490 int CServiceMain::on_set_preprocessing_allow_mode(int pid, int mode, std::string app_id) {
1491         return mas_client_set_preprocessing_allow_mode(pid,
1492                 static_cast<ma_preprocessing_allow_mode_e>(mode), app_id.c_str());
1493 }
1494
1495 int CServiceMain::on_send_preprocessing_result(int pid, int result) {
1496         return mas_client_send_preprocessing_result(pid, result);
1497 }
1498
1499 int CServiceMain::on_set_wake_word_audio_require_flag(int pid, int require) {
1500         return mas_client_set_wake_word_audio_require_flag(pid, require);
1501 }
1502
1503 int CServiceMain::on_set_assistant_language(int pid, std::string language) {
1504         return mas_client_set_assistant_language(pid, language.c_str());
1505 }
1506
1507 int CServiceMain::on_add_wake_word(int pid, std::string wake_word, std::string language) {
1508         return mas_client_add_wake_word(pid, wake_word.c_str(), language.c_str());
1509 }
1510
1511 int CServiceMain::on_remove_wake_word(int pid, std::string wake_word, std::string language) {
1512         return mas_client_remove_wake_word(pid, wake_word.c_str(), language.c_str());
1513 }
1514
1515 int CServiceMain::on_ui_initialize(int pid)
1516 {
1517         return mas_ui_client_initialize(pid);
1518 }
1519
1520 int CServiceMain::on_ui_deinitialize(int pid)
1521 {
1522         return mas_ui_client_deinitialize(pid);
1523 }
1524
1525 int CServiceMain::on_ui_change_assistant(std::string app_id)
1526 {
1527         return mas_ui_client_change_assistant(app_id.c_str());
1528 }