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
17package com.android.server.voiceinteraction;
18
19import android.Manifest;
20import android.app.ActivityManager;
21import android.app.ActivityManagerInternal;
22import android.app.AppGlobals;
23import android.content.ComponentName;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.IPackageManager;
29import android.content.pm.PackageManager;
30import android.content.pm.PackageManagerInternal;
31import android.content.pm.ResolveInfo;
32import android.content.pm.ServiceInfo;
33import android.content.res.Resources;
34import android.database.ContentObserver;
35import android.hardware.soundtrigger.IRecognitionStatusCallback;
36import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
37import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
38import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
39import android.os.Binder;
40import android.os.Bundle;
41import android.os.Handler;
42import android.os.IBinder;
43import android.os.Parcel;
44import android.os.RemoteCallbackList;
45import android.os.RemoteException;
46import android.os.UserHandle;
47import android.provider.Settings;
48import android.service.voice.IVoiceInteractionService;
49import android.service.voice.IVoiceInteractionSession;
50import android.service.voice.VoiceInteractionManagerInternal;
51import android.service.voice.VoiceInteractionService;
52import android.service.voice.VoiceInteractionServiceInfo;
53import android.service.voice.VoiceInteractionSession;
54import android.speech.RecognitionService;
55import android.text.TextUtils;
56import android.util.Log;
57import android.util.Slog;
58
59import com.android.internal.app.IVoiceInteractionSessionListener;
60import com.android.internal.app.IVoiceInteractionManagerService;
61import com.android.internal.app.IVoiceInteractionSessionShowCallback;
62import com.android.internal.app.IVoiceInteractor;
63import com.android.internal.content.PackageMonitor;
64import com.android.internal.os.BackgroundThread;
65import com.android.internal.util.DumpUtils;
66import com.android.server.LocalServices;
67import com.android.server.SystemService;
68import com.android.server.UiThread;
69import com.android.server.soundtrigger.SoundTriggerInternal;
70
71import java.io.FileDescriptor;
72import java.io.PrintWriter;
73import java.util.List;
74import java.util.TreeSet;
75
76/**
77 * SystemService that publishes an IVoiceInteractionManagerService.
78 */
79public 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
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
119    public void onStart() {
120        publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
121        publishLocalService(VoiceInteractionManagerInternal.class, new LocalService());
122    }
123
124    @Override
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
134    public void onStartUser(int userHandle) {
135        mServiceStub.initForUser(userHandle);
136    }
137
138    @Override
139    public void onUnlockUser(int userHandle) {
140        mServiceStub.initForUser(userHandle);
141        mServiceStub.switchImplementationIfNeeded(false);
142    }
143
144    @Override
145    public void onSwitchUser(int userHandle) {
146        mServiceStub.switchUser(userHandle);
147    }
148
149    class LocalService extends VoiceInteractionManagerInternal {
150        @Override
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
160        public boolean supportsLocalVoiceInteraction() {
161            return VoiceInteractionManagerService.this.mServiceStub.supportsLocalVoiceInteraction();
162        }
163
164        @Override
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
185        VoiceInteractionManagerServiceStub() {
186            mEnableService = shouldEnableService(mContext.getResources());
187        }
188
189        // TODO: VI Make sure the caller is the current user or profile
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
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
226        public boolean supportsLocalVoiceInteraction() {
227            if (mImpl == null) return false;
228
229            return mImpl.supportsLocalVoiceInteraction();
230        }
231
232        @Override
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
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
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
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
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
376        public void switchUser(int userHandle) {
377            synchronized (this) {
378                mCurUser = userHandle;
379                switchImplementationIfNeededLocked(false);
380            }
381        }
382
383        void switchImplementationIfNeeded(boolean force) {
384            synchronized (this) {
385                switchImplementationIfNeededLocked(force);
386            }
387        }
388
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
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
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
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
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
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
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
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
557        void resetCurAssistant(int userHandle) {
558            Settings.Secure.putStringForUser(mContext.getContentResolver(),
559                    Settings.Secure.ASSISTANT, null, userHandle);
560        }
561
562        @Override
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 {
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
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