1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.voiceinteraction;
18 
19 import android.Manifest;
20 import android.app.ActivityManager;
21 import android.app.ActivityManagerInternal;
22 import android.app.AppGlobals;
23 import android.content.ComponentName;
24 import android.content.ContentResolver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.IPackageManager;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManagerInternal;
31 import android.content.pm.ResolveInfo;
32 import android.content.pm.ServiceInfo;
33 import android.content.res.Resources;
34 import android.database.ContentObserver;
35 import android.hardware.soundtrigger.IRecognitionStatusCallback;
36 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
37 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
38 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
39 import android.os.Binder;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.Parcel;
44 import android.os.RemoteCallbackList;
45 import android.os.RemoteException;
46 import android.os.UserHandle;
47 import android.provider.Settings;
48 import android.service.voice.IVoiceInteractionService;
49 import android.service.voice.IVoiceInteractionSession;
50 import android.service.voice.VoiceInteractionManagerInternal;
51 import android.service.voice.VoiceInteractionService;
52 import android.service.voice.VoiceInteractionServiceInfo;
53 import android.service.voice.VoiceInteractionSession;
54 import android.speech.RecognitionService;
55 import android.text.TextUtils;
56 import android.util.Log;
57 import android.util.Slog;
58 
59 import com.android.internal.app.IVoiceInteractionSessionListener;
60 import com.android.internal.app.IVoiceInteractionManagerService;
61 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
62 import com.android.internal.app.IVoiceInteractor;
63 import com.android.internal.content.PackageMonitor;
64 import com.android.internal.os.BackgroundThread;
65 import com.android.internal.util.DumpUtils;
66 import com.android.server.LocalServices;
67 import com.android.server.SystemService;
68 import com.android.server.UiThread;
69 import com.android.server.soundtrigger.SoundTriggerInternal;
70 
71 import java.io.FileDescriptor;
72 import java.io.PrintWriter;
73 import java.util.List;
74 import java.util.TreeSet;
75 
76 /**
77  * SystemService that publishes an IVoiceInteractionManagerService.
78  */
79 public class VoiceInteractionManagerService extends SystemService {
80     static final String TAG = "VoiceInteractionManagerService";
81     static final boolean DEBUG = false;
82 
83     final Context mContext;
84     final ContentResolver mResolver;
85     final DatabaseHelper mDbHelper;
86     final ActivityManagerInternal mAmInternal;
87     final TreeSet<Integer> mLoadedKeyphraseIds;
88     SoundTriggerInternal mSoundTriggerInternal;
89 
90     private final RemoteCallbackList<IVoiceInteractionSessionListener>
91             mVoiceInteractionSessionListeners = new RemoteCallbackList<>();
92 
VoiceInteractionManagerService(Context context)93     public VoiceInteractionManagerService(Context context) {
94         super(context);
95         mContext = context;
96         mResolver = context.getContentResolver();
97         mDbHelper = new DatabaseHelper(context);
98         mServiceStub = new VoiceInteractionManagerServiceStub();
99         mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
100         mLoadedKeyphraseIds = new TreeSet<Integer>();
101 
102         PackageManagerInternal packageManagerInternal = LocalServices.getService(
103                 PackageManagerInternal.class);
104         packageManagerInternal.setVoiceInteractionPackagesProvider(
105                 new PackageManagerInternal.PackagesProvider() {
106             @Override
107             public String[] getPackages(int userId) {
108                 mServiceStub.initForUser(userId);
109                 ComponentName interactor = mServiceStub.getCurInteractor(userId);
110                 if (interactor != null) {
111                     return new String[] {interactor.getPackageName()};
112                 }
113                 return null;
114             }
115         });
116     }
117 
118     @Override
onStart()119     public void onStart() {
120         publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
121         publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
122     }
123 
124     @Override
onBootPhase(int phase)125     public void onBootPhase(int phase) {
126         if (PHASE_SYSTEM_SERVICES_READY == phase) {
127             mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
128         } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
129             mServiceStub.systemRunning(isSafeMode());
130         }
131     }
132 
133     @Override
onStartUser(int userHandle)134     public void onStartUser(int userHandle) {
135         mServiceStub.initForUser(userHandle);
136     }
137 
138     @Override
onUnlockUser(int userHandle)139     public void onUnlockUser(int userHandle) {
140         mServiceStub.initForUser(userHandle);
141         mServiceStub.switchImplementationIfNeeded(false);
142     }
143 
144     @Override
onSwitchUser(int userHandle)145     public void onSwitchUser(int userHandle) {
146         mServiceStub.switchUser(userHandle);
147     }
148 
149     class LocalService extends VoiceInteractionManagerInternal {
150         @Override
startLocalVoiceInteraction(IBinder callingActivity, Bundle options)151         public void startLocalVoiceInteraction(IBinder callingActivity, Bundle options) {
152             if (DEBUG) {
153                 Slog.i(TAG, "startLocalVoiceInteraction " + callingActivity);
154             }
155             VoiceInteractionManagerService.this.mServiceStub.startLocalVoiceInteraction(
156                     callingActivity, options);
157         }
158 
159         @Override
supportsLocalVoiceInteraction()160         public boolean supportsLocalVoiceInteraction() {
161             return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction();
162         }
163 
164         @Override
stopLocalVoiceInteraction(IBinder callingActivity)165         public void stopLocalVoiceInteraction(IBinder callingActivity) {
166             if (DEBUG) {
167                 Slog.i(TAG, "stopLocalVoiceInteraction " + callingActivity);
168             }
169             VoiceInteractionManagerService.this.mServiceStub.stopLocalVoiceInteraction(
170                     callingActivity);
171         }
172     }
173 
174     // implementation entry point and binder service
175     private final VoiceInteractionManagerServiceStub mServiceStub;
176 
177     class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
178 
179         VoiceInteractionManagerServiceImpl mImpl;
180 
181         private boolean mSafeMode;
182         private int mCurUser;
183         private final boolean mEnableService;
184 
VoiceInteractionManagerServiceStub()185         VoiceInteractionManagerServiceStub() {
186             mEnableService = shouldEnableService(mContext.getResources());
187         }
188 
189         // TODO: VI Make sure the caller is the current user or profile
startLocalVoiceInteraction(final IBinder token, Bundle options)190         void startLocalVoiceInteraction(final IBinder token, Bundle options) {
191             if (mImpl == null) return;
192 
193             final long caller = Binder.clearCallingIdentity();
194             try {
195                 mImpl.showSessionLocked(options,
196                         VoiceInteractionSession.SHOW_SOURCE_ACTIVITY,
197                         new IVoiceInteractionSessionShowCallback.Stub() {
198                             @Override
199                             public void onFailed() {
200                             }
201 
202                             @Override
203                             public void onShown() {
204                                 mAmInternal.onLocalVoiceInteractionStarted(token,
205                                         mImpl.mActiveSession.mSession,
206                                         mImpl.mActiveSession.mInteractor);
207                             }
208                         },
209                         token);
210             } finally {
211                 Binder.restoreCallingIdentity(caller);
212             }
213         }
214 
stopLocalVoiceInteraction(IBinder callingActivity)215         public void stopLocalVoiceInteraction(IBinder callingActivity) {
216             if (mImpl == null) return;
217 
218             final long caller = Binder.clearCallingIdentity();
219             try {
220                 mImpl.finishLocked(callingActivity, true);
221             } finally {
222                 Binder.restoreCallingIdentity(caller);
223             }
224         }
225 
supportsLocalVoiceInteraction()226         public boolean supportsLocalVoiceInteraction() {
227             if (mImpl == null) return false;
228 
229             return mImpl.supportsLocalVoiceInteraction();
230         }
231 
232         @Override
onTransact(int code, Parcel data, Parcel reply, int flags)233         public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
234                 throws RemoteException {
235             try {
236                 return super.onTransact(code, data, reply, flags);
237             } catch (RuntimeException e) {
238                 // The activity manager only throws security exceptions, so let's
239                 // log all others.
240                 if (!(e instanceof SecurityException)) {
241                     Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
242                 }
243                 throw e;
244             }
245         }
246 
initForUser(int userHandle)247         public void initForUser(int userHandle) {
248             if (DEBUG) Slog.d(TAG, "**************** initForUser user=" + userHandle);
249             String curInteractorStr = Settings.Secure.getStringForUser(
250                     mContext.getContentResolver(),
251                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
252             ComponentName curRecognizer = getCurRecognizer(userHandle);
253             VoiceInteractionServiceInfo curInteractorInfo = null;
254             if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr
255                     + " curRecognizer=" + curRecognizer);
256             if (curInteractorStr == null && curRecognizer != null && mEnableService) {
257                 // If there is no interactor setting, that means we are upgrading
258                 // from an older platform version.  If the current recognizer is not
259                 // set or matches the preferred recognizer, then we want to upgrade
260                 // the user to have the default voice interaction service enabled.
261                 // Note that we don't do this for low-RAM devices, since we aren't
262                 // supporting voice interaction services there.
263                 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer.getPackageName());
264                 if (curInteractorInfo != null) {
265                     // Looks good!  We'll apply this one.  To make it happen, we clear the
266                     // recognizer so that we don't think we have anything set and will
267                     // re-apply the settings.
268                     if (DEBUG) Slog.d(TAG, "No set interactor, found avail: "
269                             + curInteractorInfo.getServiceInfo().name);
270                     curRecognizer = null;
271                 }
272             }
273 
274             // If forceInteractorPackage exists, try to apply the interactor from this package if
275             // possible and ignore the regular interactor setting.
276             String forceInteractorPackage =
277                     getForceVoiceInteractionServicePackage(mContext.getResources());
278             if (forceInteractorPackage != null) {
279                 curInteractorInfo = findAvailInteractor(userHandle, forceInteractorPackage);
280                 if (curInteractorInfo != null) {
281                     // We'll apply this one. Clear the recognizer and re-apply the settings.
282                     curRecognizer = null;
283                 }
284             }
285 
286             // If we are on a svelte device, make sure an interactor is not currently
287             // enabled; if it is, turn it off.
288             if (!mEnableService && curInteractorStr != null) {
289                 if (!TextUtils.isEmpty(curInteractorStr)) {
290                     if (DEBUG) Slog.d(TAG, "Svelte device; disabling interactor");
291                     setCurInteractor(null, userHandle);
292                     curInteractorStr = "";
293                 }
294             }
295 
296             if (curRecognizer != null) {
297                 // If we already have at least a recognizer, then we probably want to
298                 // leave things as they are...  unless something has disappeared.
299                 IPackageManager pm = AppGlobals.getPackageManager();
300                 ServiceInfo interactorInfo = null;
301                 ServiceInfo recognizerInfo = null;
302                 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr)
303                         ? ComponentName.unflattenFromString(curInteractorStr) : null;
304                 try {
305                     recognizerInfo = pm.getServiceInfo(curRecognizer,
306                             PackageManager.MATCH_DIRECT_BOOT_AWARE
307                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
308                     if (curInteractor != null) {
309                         interactorInfo = pm.getServiceInfo(curInteractor,
310                                 PackageManager.MATCH_DIRECT_BOOT_AWARE
311                                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
312                     }
313                 } catch (RemoteException e) {
314                 }
315                 // If the apps for the currently set components still exist, then all is okay.
316                 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
317                     if (DEBUG) Slog.d(TAG, "Current interactor/recognizer okay, done!");
318                     return;
319                 }
320                 if (DEBUG) Slog.d(TAG, "Bad recognizer (" + recognizerInfo + ") or interactor ("
321                         + interactorInfo + ")");
322             }
323 
324             // Initializing settings, look for an interactor first (but only on non-svelte).
325             if (curInteractorInfo == null && mEnableService) {
326                 curInteractorInfo = findAvailInteractor(userHandle, null);
327             }
328 
329             if (curInteractorInfo != null) {
330                 // Eventually it will be an error to not specify this.
331                 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
332                         curInteractorInfo.getServiceInfo().name), userHandle);
333                 if (curInteractorInfo.getRecognitionService() != null) {
334                     setCurRecognizer(
335                             new ComponentName(curInteractorInfo.getServiceInfo().packageName,
336                                     curInteractorInfo.getRecognitionService()), userHandle);
337                     return;
338                 }
339             }
340 
341             // No voice interactor, we'll just set up a simple recognizer.
342             curRecognizer = findAvailRecognizer(null, userHandle);
343             if (curRecognizer != null) {
344                 if (curInteractorInfo == null) {
345                     setCurInteractor(null, userHandle);
346                 }
347                 setCurRecognizer(curRecognizer, userHandle);
348             }
349         }
350 
shouldEnableService(Resources res)351         private boolean shouldEnableService(Resources res) {
352             // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag.
353             return !ActivityManager.isLowRamDeviceStatic() ||
354                     getForceVoiceInteractionServicePackage(res) != null;
355         }
356 
getForceVoiceInteractionServicePackage(Resources res)357         private String getForceVoiceInteractionServicePackage(Resources res) {
358             String interactorPackage =
359                     res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
360             return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
361         }
362 
systemRunning(boolean safeMode)363         public void systemRunning(boolean safeMode) {
364             mSafeMode = safeMode;
365 
366             mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
367                     UserHandle.ALL, true);
368             new SettingsObserver(UiThread.getHandler());
369 
370             synchronized (this) {
371                 mCurUser = ActivityManager.getCurrentUser();
372                 switchImplementationIfNeededLocked(false);
373             }
374         }
375 
switchUser(int userHandle)376         public void switchUser(int userHandle) {
377             synchronized (this) {
378                 mCurUser = userHandle;
379                 switchImplementationIfNeededLocked(false);
380             }
381         }
382 
switchImplementationIfNeeded(boolean force)383         void switchImplementationIfNeeded(boolean force) {
384             synchronized (this) {
385                 switchImplementationIfNeededLocked(force);
386             }
387         }
388 
switchImplementationIfNeededLocked(boolean force)389         void switchImplementationIfNeededLocked(boolean force) {
390             if (!mSafeMode) {
391                 String curService = Settings.Secure.getStringForUser(
392                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
393                 ComponentName serviceComponent = null;
394                 ServiceInfo serviceInfo = null;
395                 if (curService != null && !curService.isEmpty()) {
396                     try {
397                         serviceComponent = ComponentName.unflattenFromString(curService);
398                         serviceInfo = AppGlobals.getPackageManager()
399                                 .getServiceInfo(serviceComponent, 0, mCurUser);
400                     } catch (RuntimeException | RemoteException e) {
401                         Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
402                         serviceComponent = null;
403                         serviceInfo = null;
404                     }
405                 }
406 
407                 if (force || mImpl == null || mImpl.mUser != mCurUser
408                         || !mImpl.mComponent.equals(serviceComponent)) {
409                     unloadAllKeyphraseModels();
410                     if (mImpl != null) {
411                         mImpl.shutdownLocked();
412                     }
413                     if (serviceComponent != null && serviceInfo != null) {
414                         mImpl = new VoiceInteractionManagerServiceImpl(mContext,
415                                 UiThread.getHandler(), this, mCurUser, serviceComponent);
416                         mImpl.startLocked();
417                     } else {
418                         mImpl = null;
419                     }
420                 }
421             }
422         }
423 
findAvailInteractor(int userHandle, String packageName)424         VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) {
425             List<ResolveInfo> available =
426                     mContext.getPackageManager().queryIntentServicesAsUser(
427                             new Intent(VoiceInteractionService.SERVICE_INTERFACE),
428                             PackageManager.MATCH_DIRECT_BOOT_AWARE
429                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
430                                     | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userHandle);
431             int numAvailable = available.size();
432 
433             if (numAvailable == 0) {
434                 Slog.w(TAG, "no available voice interaction services found for user " + userHandle);
435                 return null;
436             } else {
437                 // Find first system package.  We never want to allow third party services to
438                 // be automatically selected, because those require approval of the user.
439                 VoiceInteractionServiceInfo foundInfo = null;
440                 for (int i=0; i<numAvailable; i++) {
441                     ServiceInfo cur = available.get(i).serviceInfo;
442                     if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
443                         ComponentName comp = new ComponentName(cur.packageName, cur.name);
444                         try {
445                             VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
446                                     mContext.getPackageManager(), comp, userHandle);
447                             if (info.getParseError() == null) {
448                                 if (packageName == null || info.getServiceInfo().packageName.equals(
449                                         packageName)) {
450                                     if (foundInfo == null) {
451                                         foundInfo = info;
452                                     } else {
453                                         Slog.w(TAG, "More than one voice interaction service, "
454                                                 + "picking first "
455                                                 + new ComponentName(
456                                                         foundInfo.getServiceInfo().packageName,
457                                                         foundInfo.getServiceInfo().name)
458                                                 + " over "
459                                                 + new ComponentName(cur.packageName, cur.name));
460                                     }
461                                 }
462                             } else {
463                                 Slog.w(TAG, "Bad interaction service " + comp + ": "
464                                         + info.getParseError());
465                             }
466                         } catch (PackageManager.NameNotFoundException e) {
467                             Slog.w(TAG, "Failure looking up interaction service " + comp);
468                         }
469                     }
470                 }
471 
472                 return foundInfo;
473             }
474         }
475 
getCurInteractor(int userHandle)476         ComponentName getCurInteractor(int userHandle) {
477             String curInteractor = Settings.Secure.getStringForUser(
478                     mContext.getContentResolver(),
479                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
480             if (TextUtils.isEmpty(curInteractor)) {
481                 return null;
482             }
483             if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor
484                     + " user=" + userHandle);
485             return ComponentName.unflattenFromString(curInteractor);
486         }
487 
setCurInteractor(ComponentName comp, int userHandle)488         void setCurInteractor(ComponentName comp, int userHandle) {
489             Settings.Secure.putStringForUser(mContext.getContentResolver(),
490                     Settings.Secure.VOICE_INTERACTION_SERVICE,
491                     comp != null ? comp.flattenToShortString() : "", userHandle);
492             if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp
493                     + " user=" + userHandle);
494         }
495 
findAvailRecognizer(String prefPackage, int userHandle)496         ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
497             List<ResolveInfo> available =
498                     mContext.getPackageManager().queryIntentServicesAsUser(
499                             new Intent(RecognitionService.SERVICE_INTERFACE),
500                             PackageManager.MATCH_DIRECT_BOOT_AWARE
501                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
502             int numAvailable = available.size();
503 
504             if (numAvailable == 0) {
505                 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
506                 return null;
507             } else {
508                 if (prefPackage != null) {
509                     for (int i=0; i<numAvailable; i++) {
510                         ServiceInfo serviceInfo = available.get(i).serviceInfo;
511                         if (prefPackage.equals(serviceInfo.packageName)) {
512                             return new ComponentName(serviceInfo.packageName, serviceInfo.name);
513                         }
514                     }
515                 }
516                 if (numAvailable > 1) {
517                     Slog.w(TAG, "more than one voice recognition service found, picking first");
518                 }
519 
520                 ServiceInfo serviceInfo = available.get(0).serviceInfo;
521                 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
522             }
523         }
524 
getCurRecognizer(int userHandle)525         ComponentName getCurRecognizer(int userHandle) {
526             String curRecognizer = Settings.Secure.getStringForUser(
527                     mContext.getContentResolver(),
528                     Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
529             if (TextUtils.isEmpty(curRecognizer)) {
530                 return null;
531             }
532             if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
533                     + " user=" + userHandle);
534             return ComponentName.unflattenFromString(curRecognizer);
535         }
536 
setCurRecognizer(ComponentName comp, int userHandle)537         void setCurRecognizer(ComponentName comp, int userHandle) {
538             Settings.Secure.putStringForUser(mContext.getContentResolver(),
539                     Settings.Secure.VOICE_RECOGNITION_SERVICE,
540                     comp != null ? comp.flattenToShortString() : "", userHandle);
541             if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp
542                     + " user=" + userHandle);
543         }
544 
getCurAssistant(int userHandle)545         ComponentName getCurAssistant(int userHandle) {
546             String curAssistant = Settings.Secure.getStringForUser(
547                     mContext.getContentResolver(),
548                     Settings.Secure.ASSISTANT, userHandle);
549             if (TextUtils.isEmpty(curAssistant)) {
550                 return null;
551             }
552             if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
553                     + " user=" + userHandle);
554             return ComponentName.unflattenFromString(curAssistant);
555         }
556 
resetCurAssistant(int userHandle)557         void resetCurAssistant(int userHandle) {
558             Settings.Secure.putStringForUser(mContext.getContentResolver(),
559                     Settings.Secure.ASSISTANT, null, userHandle);
560         }
561 
562         @Override
showSession(IVoiceInteractionService service, Bundle args, int flags)563         public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
564             synchronized (this) {
565                 if (mImpl == null || mImpl.mService == null
566                         || service.asBinder() != mImpl.mService.asBinder()) {
567                     throw new SecurityException(
568                             "Caller is not the current voice interaction service");
569                 }
570                 final long caller = Binder.clearCallingIdentity();
571                 try {
572                     mImpl.showSessionLocked(args, flags, null, null);
573                 } finally {
574                     Binder.restoreCallingIdentity(caller);
575                 }
576             }
577         }
578 
579         @Override
deliverNewSession(IBinder token, IVoiceInteractionSession session, IVoiceInteractor interactor)580         public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
581                 IVoiceInteractor interactor) {
582             synchronized (this) {
583                 if (mImpl == null) {
584                     throw new SecurityException(
585                             "deliverNewSession without running voice interaction service");
586                 }
587                 final long caller = Binder.clearCallingIdentity();
588                 try {
589                     return mImpl.deliverNewSessionLocked(token, session, interactor);
590                 } finally {
591                     Binder.restoreCallingIdentity(caller);
592                 }
593             }
594         }
595 
596         @Override
showSessionFromSession(IBinder token, Bundle sessionArgs, int flags)597         public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
598             synchronized (this) {
599                 if (mImpl == null) {
600                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
601                     return false;
602                 }
603                 final long caller = Binder.clearCallingIdentity();
604                 try {
605                     return mImpl.showSessionLocked(sessionArgs, flags, null, null);
606                 } finally {
607                     Binder.restoreCallingIdentity(caller);
608                 }
609             }
610         }
611 
612         @Override
hideSessionFromSession(IBinder token)613         public boolean hideSessionFromSession(IBinder token) {
614             synchronized (this) {
615                 if (mImpl == null) {
616                     Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
617                     return false;
618                 }
619                 final long caller = Binder.clearCallingIdentity();
620                 try {
621                     return mImpl.hideSessionLocked();
622                 } finally {
623                     Binder.restoreCallingIdentity(caller);
624                 }
625             }
626         }
627 
628         @Override
startVoiceActivity(IBinder token, Intent intent, String resolvedType)629         public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
630             synchronized (this) {
631                 if (mImpl == null) {
632                     Slog.w(TAG, "startVoiceActivity without running voice interaction service");
633                     return ActivityManager.START_CANCELED;
634                 }
635                 final int callingPid = Binder.getCallingPid();
636                 final int callingUid = Binder.getCallingUid();
637                 final long caller = Binder.clearCallingIdentity();
638                 try {
639                     return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
640                             intent, resolvedType);
641                 } finally {
642                     Binder.restoreCallingIdentity(caller);
643                 }
644             }
645         }
646 
647         @Override
startAssistantActivity(IBinder token, Intent intent, String resolvedType)648         public int startAssistantActivity(IBinder token, Intent intent, String resolvedType) {
649             synchronized (this) {
650                 if (mImpl == null) {
651                     Slog.w(TAG, "startAssistantActivity without running voice interaction service");
652                     return ActivityManager.START_CANCELED;
653                 }
654                 final int callingPid = Binder.getCallingPid();
655                 final int callingUid = Binder.getCallingUid();
656                 final long caller = Binder.clearCallingIdentity();
657                 try {
658                     return mImpl.startAssistantActivityLocked(callingPid, callingUid, token,
659                             intent, resolvedType);
660                 } finally {
661                     Binder.restoreCallingIdentity(caller);
662                 }
663             }
664         }
665 
666         @Override
setKeepAwake(IBinder token, boolean keepAwake)667         public void setKeepAwake(IBinder token, boolean keepAwake) {
668             synchronized (this) {
669                 if (mImpl == null) {
670                     Slog.w(TAG, "setKeepAwake without running voice interaction service");
671                     return;
672                 }
673                 final long caller = Binder.clearCallingIdentity();
674                 try {
675                     mImpl.setKeepAwakeLocked(token, keepAwake);
676                 } finally {
677                     Binder.restoreCallingIdentity(caller);
678                 }
679             }
680         }
681 
682         @Override
closeSystemDialogs(IBinder token)683         public void closeSystemDialogs(IBinder token) {
684             synchronized (this) {
685                 if (mImpl == null) {
686                     Slog.w(TAG, "closeSystemDialogs without running voice interaction service");
687                     return;
688                 }
689                 final long caller = Binder.clearCallingIdentity();
690                 try {
691                     mImpl.closeSystemDialogsLocked(token);
692                 } finally {
693                     Binder.restoreCallingIdentity(caller);
694                 }
695             }
696         }
697 
698         @Override
finish(IBinder token)699         public void finish(IBinder token) {
700             synchronized (this) {
701                 if (mImpl == null) {
702                     Slog.w(TAG, "finish without running voice interaction service");
703                     return;
704                 }
705                 final long caller = Binder.clearCallingIdentity();
706                 try {
707                     mImpl.finishLocked(token, false);
708                 } finally {
709                     Binder.restoreCallingIdentity(caller);
710                 }
711             }
712         }
713 
714         @Override
setDisabledShowContext(int flags)715         public void setDisabledShowContext(int flags) {
716             synchronized (this) {
717                 if (mImpl == null) {
718                     Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
719                     return;
720                 }
721                 final int callingUid = Binder.getCallingUid();
722                 final long caller = Binder.clearCallingIdentity();
723                 try {
724                     mImpl.setDisabledShowContextLocked(callingUid, flags);
725                 } finally {
726                     Binder.restoreCallingIdentity(caller);
727                 }
728             }
729         }
730 
731         @Override
getDisabledShowContext()732         public int getDisabledShowContext() {
733             synchronized (this) {
734                 if (mImpl == null) {
735                     Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
736                     return 0;
737                 }
738                 final int callingUid = Binder.getCallingUid();
739                 final long caller = Binder.clearCallingIdentity();
740                 try {
741                     return mImpl.getDisabledShowContextLocked(callingUid);
742                 } finally {
743                     Binder.restoreCallingIdentity(caller);
744                 }
745             }
746         }
747 
748         @Override
getUserDisabledShowContext()749         public int getUserDisabledShowContext() {
750             synchronized (this) {
751                 if (mImpl == null) {
752                     Slog.w(TAG,
753                             "getUserDisabledShowContext without running voice interaction service");
754                     return 0;
755                 }
756                 final int callingUid = Binder.getCallingUid();
757                 final long caller = Binder.clearCallingIdentity();
758                 try {
759                     return mImpl.getUserDisabledShowContextLocked(callingUid);
760                 } finally {
761                     Binder.restoreCallingIdentity(caller);
762                 }
763             }
764         }
765 
766         //----------------- Model management APIs --------------------------------//
767 
768         @Override
getKeyphraseSoundModel(int keyphraseId, String bcp47Locale)769         public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
770             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
771 
772             if (bcp47Locale == null) {
773                 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
774             }
775 
776             final int callingUid = UserHandle.getCallingUserId();
777             final long caller = Binder.clearCallingIdentity();
778             try {
779                 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
780             } finally {
781                 Binder.restoreCallingIdentity(caller);
782             }
783         }
784 
785         @Override
updateKeyphraseSoundModel(KeyphraseSoundModel model)786         public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
787             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
788             if (model == null) {
789                 throw new IllegalArgumentException("Model must not be null");
790             }
791 
792             final long caller = Binder.clearCallingIdentity();
793             try {
794                 if (mDbHelper.updateKeyphraseSoundModel(model)) {
795                     synchronized (this) {
796                         // Notify the voice interaction service of a change in sound models.
797                         if (mImpl != null && mImpl.mService != null) {
798                             mImpl.notifySoundModelsChangedLocked();
799                         }
800                     }
801                     return SoundTriggerInternal.STATUS_OK;
802                 } else {
803                     return SoundTriggerInternal.STATUS_ERROR;
804                 }
805             } finally {
806                 Binder.restoreCallingIdentity(caller);
807             }
808         }
809 
810         @Override
deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale)811         public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
812             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
813 
814             if (bcp47Locale == null) {
815                 throw new IllegalArgumentException(
816                         "Illegal argument(s) in deleteKeyphraseSoundModel");
817             }
818 
819             final int callingUid = UserHandle.getCallingUserId();
820             final long caller = Binder.clearCallingIdentity();
821             boolean deleted = false;
822             try {
823                 int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
824                 if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
825                     Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
826                 }
827                 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
828                 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
829             } finally {
830                 if (deleted) {
831                     synchronized (this) {
832                         // Notify the voice interaction service of a change in sound models.
833                         if (mImpl != null && mImpl.mService != null) {
834                             mImpl.notifySoundModelsChangedLocked();
835                         }
836                         mLoadedKeyphraseIds.remove(keyphraseId);
837                     }
838                 }
839                 Binder.restoreCallingIdentity(caller);
840             }
841         }
842 
843         //----------------- SoundTrigger APIs --------------------------------//
844         @Override
isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, String bcp47Locale)845         public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
846                 String bcp47Locale) {
847             synchronized (this) {
848                 if (mImpl == null || mImpl.mService == null
849                         || service.asBinder() != mImpl.mService.asBinder()) {
850                     throw new SecurityException(
851                             "Caller is not the current voice interaction service");
852                 }
853             }
854 
855             if (bcp47Locale == null) {
856                 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
857             }
858 
859             final int callingUid = UserHandle.getCallingUserId();
860             final long caller = Binder.clearCallingIdentity();
861             try {
862                 KeyphraseSoundModel model =
863                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
864                 return model != null;
865             } finally {
866                 Binder.restoreCallingIdentity(caller);
867             }
868         }
869 
870         @Override
getDspModuleProperties(IVoiceInteractionService service)871         public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
872             // Allow the call if this is the current voice interaction service.
873             synchronized (this) {
874                 if (mImpl == null || mImpl.mService == null
875                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
876                     throw new SecurityException(
877                             "Caller is not the current voice interaction service");
878                 }
879 
880                 final long caller = Binder.clearCallingIdentity();
881                 try {
882                     return mSoundTriggerInternal.getModuleProperties();
883                 } finally {
884                     Binder.restoreCallingIdentity(caller);
885                 }
886             }
887         }
888 
889         @Override
startRecognition(IVoiceInteractionService service, int keyphraseId, String bcp47Locale, IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig)890         public int startRecognition(IVoiceInteractionService service, int keyphraseId,
891                 String bcp47Locale, IRecognitionStatusCallback callback,
892                 RecognitionConfig recognitionConfig) {
893             // Allow the call if this is the current voice interaction service.
894             synchronized (this) {
895                 if (mImpl == null || mImpl.mService == null
896                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
897                     throw new SecurityException(
898                             "Caller is not the current voice interaction service");
899                 }
900 
901                 if (callback == null || recognitionConfig == null || bcp47Locale == null) {
902                     throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
903                 }
904             }
905 
906             int callingUid = UserHandle.getCallingUserId();
907             final long caller = Binder.clearCallingIdentity();
908             try {
909                 KeyphraseSoundModel soundModel =
910                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
911                 if (soundModel == null
912                         || soundModel.uuid == null
913                         || soundModel.keyphrases == null) {
914                     Slog.w(TAG, "No matching sound model found in startRecognition");
915                     return SoundTriggerInternal.STATUS_ERROR;
916                 } else {
917                     // Regardless of the status of the start recognition, we need to make sure
918                     // that we unload this model if needed later.
919                     synchronized (this) {
920                         mLoadedKeyphraseIds.add(keyphraseId);
921                     }
922                     return mSoundTriggerInternal.startRecognition(
923                             keyphraseId, soundModel, callback, recognitionConfig);
924                 }
925             } finally {
926                 Binder.restoreCallingIdentity(caller);
927             }
928         }
929 
930         @Override
stopRecognition(IVoiceInteractionService service, int keyphraseId, IRecognitionStatusCallback callback)931         public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
932                 IRecognitionStatusCallback callback) {
933             // Allow the call if this is the current voice interaction service.
934             synchronized (this) {
935                 if (mImpl == null || mImpl.mService == null
936                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
937                     throw new SecurityException(
938                             "Caller is not the current voice interaction service");
939                 }
940             }
941 
942             final long caller = Binder.clearCallingIdentity();
943             try {
944                 return mSoundTriggerInternal.stopRecognition(keyphraseId, callback);
945             } finally {
946                 Binder.restoreCallingIdentity(caller);
947             }
948         }
949 
unloadAllKeyphraseModels()950         private synchronized void unloadAllKeyphraseModels() {
951             for (int keyphraseId : mLoadedKeyphraseIds) {
952                 final long caller = Binder.clearCallingIdentity();
953                 try {
954                     int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
955                     if (status != SoundTriggerInternal.STATUS_OK) {
956                         Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
957                     }
958                 } finally {
959                     Binder.restoreCallingIdentity(caller);
960                 }
961             }
962             mLoadedKeyphraseIds.clear();
963         }
964 
965         @Override
getActiveServiceComponentName()966         public ComponentName getActiveServiceComponentName() {
967             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
968             synchronized (this) {
969                 return mImpl != null ? mImpl.mComponent : null;
970             }
971         }
972 
973         @Override
showSessionForActiveService(Bundle args, int sourceFlags, IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken)974         public boolean showSessionForActiveService(Bundle args, int sourceFlags,
975                 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
976             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
977             synchronized (this) {
978                 if (mImpl == null) {
979                     Slog.w(TAG, "showSessionForActiveService without running voice interaction"
980                             + "service");
981                     return false;
982                 }
983                 final long caller = Binder.clearCallingIdentity();
984                 try {
985                     return mImpl.showSessionLocked(args,
986                             sourceFlags
987                                     | VoiceInteractionSession.SHOW_WITH_ASSIST
988                                     | VoiceInteractionSession.SHOW_WITH_SCREENSHOT,
989                             showCallback, activityToken);
990                 } finally {
991                     Binder.restoreCallingIdentity(caller);
992                 }
993             }
994         }
995 
996         @Override
hideCurrentSession()997         public void hideCurrentSession() throws RemoteException {
998             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
999             synchronized (this) {
1000                 if (mImpl == null) {
1001                     return;
1002                 }
1003                 final long caller = Binder.clearCallingIdentity();
1004                 try {
1005                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
1006                         try {
1007                             mImpl.mActiveSession.mSession.closeSystemDialogs();
1008                         } catch (RemoteException e) {
1009                             Log.w(TAG, "Failed to call closeSystemDialogs", e);
1010                         }
1011                     }
1012                 } finally {
1013                     Binder.restoreCallingIdentity(caller);
1014                 }
1015             }
1016         }
1017 
1018         @Override
launchVoiceAssistFromKeyguard()1019         public void launchVoiceAssistFromKeyguard() {
1020             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1021             synchronized (this) {
1022                 if (mImpl == null) {
1023                     Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction"
1024                             + "service");
1025                     return;
1026                 }
1027                 final long caller = Binder.clearCallingIdentity();
1028                 try {
1029                     mImpl.launchVoiceAssistFromKeyguard();
1030                 } finally {
1031                     Binder.restoreCallingIdentity(caller);
1032                 }
1033             }
1034         }
1035 
1036         @Override
isSessionRunning()1037         public boolean isSessionRunning() {
1038             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1039             synchronized (this) {
1040                 return mImpl != null && mImpl.mActiveSession != null;
1041             }
1042         }
1043 
1044         @Override
activeServiceSupportsAssist()1045         public boolean activeServiceSupportsAssist() {
1046             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1047             synchronized (this) {
1048                 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist();
1049             }
1050         }
1051 
1052         @Override
activeServiceSupportsLaunchFromKeyguard()1053         public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException {
1054             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1055             synchronized (this) {
1056                 return mImpl != null && mImpl.mInfo != null
1057                         && mImpl.mInfo.getSupportsLaunchFromKeyguard();
1058             }
1059         }
1060 
1061         @Override
onLockscreenShown()1062         public void onLockscreenShown() {
1063             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1064             synchronized (this) {
1065                 if (mImpl == null) {
1066                     return;
1067                 }
1068                 final long caller = Binder.clearCallingIdentity();
1069                 try {
1070                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
1071                         try {
1072                             mImpl.mActiveSession.mSession.onLockscreenShown();
1073                         } catch (RemoteException e) {
1074                             Log.w(TAG, "Failed to call onLockscreenShown", e);
1075                         }
1076                     }
1077                 } finally {
1078                     Binder.restoreCallingIdentity(caller);
1079                 }
1080             }
1081         }
1082 
1083         @Override
registerVoiceInteractionSessionListener( IVoiceInteractionSessionListener listener)1084         public void registerVoiceInteractionSessionListener(
1085                 IVoiceInteractionSessionListener listener) {
1086             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
1087             synchronized (this) {
1088                 mVoiceInteractionSessionListeners.register(listener);
1089             }
1090         }
1091 
onSessionShown()1092         public void onSessionShown() {
1093             synchronized (this) {
1094                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
1095                 for (int i = 0; i < size; ++i) {
1096                     final IVoiceInteractionSessionListener listener =
1097                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
1098                     try {
1099                         listener.onVoiceSessionShown();
1100                     } catch (RemoteException e) {
1101                         Slog.e(TAG, "Error delivering voice interaction open event.", e);
1102                     }
1103                 }
1104                 mVoiceInteractionSessionListeners.finishBroadcast();
1105             }
1106         }
1107 
onSessionHidden()1108         public void onSessionHidden() {
1109             synchronized (this) {
1110                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
1111                 for (int i = 0; i < size; ++i) {
1112                     final IVoiceInteractionSessionListener listener =
1113                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
1114                     try {
1115                         listener.onVoiceSessionHidden();
1116 
1117                     } catch (RemoteException e) {
1118                         Slog.e(TAG, "Error delivering voice interaction closed event.", e);
1119                     }
1120                 }
1121                 mVoiceInteractionSessionListeners.finishBroadcast();
1122             }
1123         }
1124 
1125         @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1126         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1127             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1128             synchronized (this) {
1129                 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
1130                 pw.println("  mEnableService: " + mEnableService);
1131                 if (mImpl == null) {
1132                     pw.println("  (No active implementation)");
1133                     return;
1134                 }
1135                 mImpl.dumpLocked(fd, pw, args);
1136             }
1137             mSoundTriggerInternal.dump(fd, pw, args);
1138         }
1139 
enforceCallingPermission(String permission)1140         private void enforceCallingPermission(String permission) {
1141             if (mContext.checkCallingOrSelfPermission(permission)
1142                     != PackageManager.PERMISSION_GRANTED) {
1143                 throw new SecurityException("Caller does not hold the permission " + permission);
1144             }
1145         }
1146 
1147         class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)1148             SettingsObserver(Handler handler) {
1149                 super(handler);
1150                 ContentResolver resolver = mContext.getContentResolver();
1151                 resolver.registerContentObserver(Settings.Secure.getUriFor(
1152                         Settings.Secure.VOICE_INTERACTION_SERVICE), false, this,
1153                         UserHandle.USER_ALL);
1154             }
1155 
onChange(boolean selfChange)1156             @Override public void onChange(boolean selfChange) {
1157                 synchronized (VoiceInteractionManagerServiceStub.this) {
1158                     switchImplementationIfNeededLocked(false);
1159                 }
1160             }
1161         }
1162 
1163         PackageMonitor mPackageMonitor = new PackageMonitor() {
1164             @Override
1165             public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
1166                 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit);
1167 
1168                 int userHandle = UserHandle.getUserId(uid);
1169                 ComponentName curInteractor = getCurInteractor(userHandle);
1170                 ComponentName curRecognizer = getCurRecognizer(userHandle);
1171                 boolean hit = false;
1172                 for (String pkg : packages) {
1173                     if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) {
1174                         hit = true;
1175                         break;
1176                     } else if (curRecognizer != null
1177                             && pkg.equals(curRecognizer.getPackageName())) {
1178                         hit = true;
1179                         break;
1180                     }
1181                 }
1182                 if (hit && doit) {
1183                     // The user is force stopping our current interactor/recognizer.
1184                     // Clear the current settings and restore default state.
1185                     synchronized (VoiceInteractionManagerServiceStub.this) {
1186                         unloadAllKeyphraseModels();
1187                         if (mImpl != null) {
1188                             mImpl.shutdownLocked();
1189                             mImpl = null;
1190                         }
1191                         setCurInteractor(null, userHandle);
1192                         setCurRecognizer(null, userHandle);
1193                         resetCurAssistant(userHandle);
1194                         initForUser(userHandle);
1195                         switchImplementationIfNeededLocked(true);
1196                     }
1197                 }
1198                 return hit;
1199             }
1200 
1201             @Override
1202             public void onHandleUserStop(Intent intent, int userHandle) {
1203             }
1204 
1205             @Override
1206             public void onPackageModified(String pkgName) {
1207                 // If the package modified is not in the current user, then don't bother making
1208                 // any changes as we are going to do any initialization needed when we switch users.
1209                 if (mCurUser != getChangingUserId()) {
1210                     return;
1211                 }
1212                 // Package getting updated will be handled by {@link #onSomePackagesChanged}.
1213                 if (isPackageAppearing(pkgName) != PACKAGE_UNCHANGED) {
1214                     return;
1215                 }
1216                 final ComponentName curInteractor = getCurInteractor(mCurUser);
1217                 if (curInteractor == null) {
1218                     final VoiceInteractionServiceInfo availInteractorInfo
1219                             = findAvailInteractor(mCurUser, pkgName);
1220                     if (availInteractorInfo != null) {
1221                         final ComponentName availInteractor = new ComponentName(
1222                                 availInteractorInfo.getServiceInfo().packageName,
1223                                 availInteractorInfo.getServiceInfo().name);
1224                         setCurInteractor(availInteractor, mCurUser);
1225                         if (getCurRecognizer(mCurUser) == null &&
1226                                 availInteractorInfo.getRecognitionService() != null) {
1227                             setCurRecognizer(new ComponentName(
1228                                     availInteractorInfo.getServiceInfo().packageName,
1229                                     availInteractorInfo.getRecognitionService()), mCurUser);
1230                         }
1231                     }
1232                 } else {
1233                     if (didSomePackagesChange()) {
1234                         // Package is changed
1235                         if (curInteractor != null && pkgName.equals(
1236                                 curInteractor.getPackageName())) {
1237                             switchImplementationIfNeeded(true);
1238                         }
1239                     } else {
1240                         // Only some components are changed
1241                         if (curInteractor != null
1242                                 && isComponentModified(curInteractor.getClassName())) {
1243                             switchImplementationIfNeeded(true);
1244                         }
1245                     }
1246                 }
1247             }
1248 
1249             @Override
1250             public void onSomePackagesChanged() {
1251                 int userHandle = getChangingUserId();
1252                 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
1253 
1254                 synchronized (VoiceInteractionManagerServiceStub.this) {
1255                     ComponentName curInteractor = getCurInteractor(userHandle);
1256                     ComponentName curRecognizer = getCurRecognizer(userHandle);
1257                     ComponentName curAssistant = getCurAssistant(userHandle);
1258                     if (curRecognizer == null) {
1259                         // Could a new recognizer appear when we don't have one pre-installed?
1260                         if (anyPackagesAppearing()) {
1261                             curRecognizer = findAvailRecognizer(null, userHandle);
1262                             if (curRecognizer != null) {
1263                                 setCurRecognizer(curRecognizer, userHandle);
1264                             }
1265                         }
1266                         return;
1267                     }
1268 
1269                     if (curInteractor != null) {
1270                         int change = isPackageDisappearing(curInteractor.getPackageName());
1271                         if (change == PACKAGE_PERMANENT_CHANGE) {
1272                             // The currently set interactor is permanently gone; fall back to
1273                             // the default config.
1274                             setCurInteractor(null, userHandle);
1275                             setCurRecognizer(null, userHandle);
1276                             resetCurAssistant(userHandle);
1277                             initForUser(userHandle);
1278                             return;
1279                         }
1280 
1281                         change = isPackageAppearing(curInteractor.getPackageName());
1282                         if (change != PACKAGE_UNCHANGED) {
1283                             // If current interactor is now appearing, for any reason, then
1284                             // restart our connection with it.
1285                             if (mImpl != null && curInteractor.getPackageName().equals(
1286                                     mImpl.mComponent.getPackageName())) {
1287                                 switchImplementationIfNeededLocked(true);
1288                             }
1289                         }
1290                         return;
1291                     }
1292 
1293                     if (curAssistant != null) {
1294                         int change = isPackageDisappearing(curAssistant.getPackageName());
1295                         if (change == PACKAGE_PERMANENT_CHANGE) {
1296                             // If the currently set assistant is being removed, then we should
1297                             // reset back to the default state (which is probably that we prefer
1298                             // to have the default full voice interactor enabled).
1299                             setCurInteractor(null, userHandle);
1300                             setCurRecognizer(null, userHandle);
1301                             resetCurAssistant(userHandle);
1302                             initForUser(userHandle);
1303                             return;
1304                         }
1305                     }
1306 
1307                     // There is no interactor, so just deal with a simple recognizer.
1308                     int change = isPackageDisappearing(curRecognizer.getPackageName());
1309                     if (change == PACKAGE_PERMANENT_CHANGE
1310                             || change == PACKAGE_TEMPORARY_CHANGE) {
1311                         setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
1312 
1313                     } else if (isPackageModified(curRecognizer.getPackageName())) {
1314                         setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
1315                                 userHandle), userHandle);
1316                     }
1317                 }
1318             }
1319         };
1320     }
1321 }
1322