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