Home | History | Annotate | Download | only in voiceinteraction
      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 
     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);
    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(Context context) {
    352             // VoiceInteractionService should not be enabled on any low RAM devices
    353             // or devices that have not declared the recognition feature, unless the
    354             // device's configuration has explicitly set the config flag for a fixed
    355             // voice interaction service.
    356             return (!ActivityManager.isLowRamDeviceStatic()
    357                             && context.getPackageManager().hasSystemFeature(
    358                                     PackageManager.FEATURE_VOICE_RECOGNIZERS)) ||
    359                     getForceVoiceInteractionServicePackage(context.getResources()) != null;
    360         }
    361 
    362         private String getForceVoiceInteractionServicePackage(Resources res) {
    363             String interactorPackage =
    364                     res.getString(com.android.internal.R.string.config_forceVoiceInteractionServicePackage);
    365             return TextUtils.isEmpty(interactorPackage) ? null : interactorPackage;
    366         }
    367 
    368         public void systemRunning(boolean safeMode) {
    369             mSafeMode = safeMode;
    370 
    371             mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
    372                     UserHandle.ALL, true);
    373             new SettingsObserver(UiThread.getHandler());
    374 
    375             synchronized (this) {
    376                 mCurUser = ActivityManager.getCurrentUser();
    377                 switchImplementationIfNeededLocked(false);
    378             }
    379         }
    380 
    381         public void switchUser(int userHandle) {
    382             synchronized (this) {
    383                 mCurUser = userHandle;
    384                 switchImplementationIfNeededLocked(false);
    385             }
    386         }
    387 
    388         void switchImplementationIfNeeded(boolean force) {
    389             synchronized (this) {
    390                 switchImplementationIfNeededLocked(force);
    391             }
    392         }
    393 
    394         void switchImplementationIfNeededLocked(boolean force) {
    395             if (!mSafeMode) {
    396                 String curService = Settings.Secure.getStringForUser(
    397                         mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
    398                 ComponentName serviceComponent = null;
    399                 ServiceInfo serviceInfo = null;
    400                 if (curService != null && !curService.isEmpty()) {
    401                     try {
    402                         serviceComponent = ComponentName.unflattenFromString(curService);
    403                         serviceInfo = AppGlobals.getPackageManager()
    404                                 .getServiceInfo(serviceComponent, 0, mCurUser);
    405                     } catch (RuntimeException | RemoteException e) {
    406                         Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
    407                         serviceComponent = null;
    408                         serviceInfo = null;
    409                     }
    410                 }
    411 
    412                 if (force || mImpl == null || mImpl.mUser != mCurUser
    413                         || !mImpl.mComponent.equals(serviceComponent)) {
    414                     unloadAllKeyphraseModels();
    415                     if (mImpl != null) {
    416                         mImpl.shutdownLocked();
    417                     }
    418                     if (serviceComponent != null && serviceInfo != null) {
    419                         mImpl = new VoiceInteractionManagerServiceImpl(mContext,
    420                                 UiThread.getHandler(), this, mCurUser, serviceComponent);
    421                         mImpl.startLocked();
    422                     } else {
    423                         mImpl = null;
    424                     }
    425                 }
    426             }
    427         }
    428 
    429         VoiceInteractionServiceInfo findAvailInteractor(int userHandle, String packageName) {
    430             List<ResolveInfo> available =
    431                     mContext.getPackageManager().queryIntentServicesAsUser(
    432                             new Intent(VoiceInteractionService.SERVICE_INTERFACE),
    433                             PackageManager.MATCH_DIRECT_BOOT_AWARE
    434                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
    435                                     | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userHandle);
    436             int numAvailable = available.size();
    437 
    438             if (numAvailable == 0) {
    439                 Slog.w(TAG, "no available voice interaction services found for user " + userHandle);
    440                 return null;
    441             } else {
    442                 // Find first system package.  We never want to allow third party services to
    443                 // be automatically selected, because those require approval of the user.
    444                 VoiceInteractionServiceInfo foundInfo = null;
    445                 for (int i=0; i<numAvailable; i++) {
    446                     ServiceInfo cur = available.get(i).serviceInfo;
    447                     if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
    448                         ComponentName comp = new ComponentName(cur.packageName, cur.name);
    449                         try {
    450                             VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
    451                                     mContext.getPackageManager(), comp, userHandle);
    452                             if (info.getParseError() == null) {
    453                                 if (packageName == null || info.getServiceInfo().packageName.equals(
    454                                         packageName)) {
    455                                     if (foundInfo == null) {
    456                                         foundInfo = info;
    457                                     } else {
    458                                         Slog.w(TAG, "More than one voice interaction service, "
    459                                                 + "picking first "
    460                                                 + new ComponentName(
    461                                                         foundInfo.getServiceInfo().packageName,
    462                                                         foundInfo.getServiceInfo().name)
    463                                                 + " over "
    464                                                 + new ComponentName(cur.packageName, cur.name));
    465                                     }
    466                                 }
    467                             } else {
    468                                 Slog.w(TAG, "Bad interaction service " + comp + ": "
    469                                         + info.getParseError());
    470                             }
    471                         } catch (PackageManager.NameNotFoundException e) {
    472                             Slog.w(TAG, "Failure looking up interaction service " + comp);
    473                         }
    474                     }
    475                 }
    476 
    477                 return foundInfo;
    478             }
    479         }
    480 
    481         ComponentName getCurInteractor(int userHandle) {
    482             String curInteractor = Settings.Secure.getStringForUser(
    483                     mContext.getContentResolver(),
    484                     Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
    485             if (TextUtils.isEmpty(curInteractor)) {
    486                 return null;
    487             }
    488             if (DEBUG) Slog.d(TAG, "getCurInteractor curInteractor=" + curInteractor
    489                     + " user=" + userHandle);
    490             return ComponentName.unflattenFromString(curInteractor);
    491         }
    492 
    493         void setCurInteractor(ComponentName comp, int userHandle) {
    494             Settings.Secure.putStringForUser(mContext.getContentResolver(),
    495                     Settings.Secure.VOICE_INTERACTION_SERVICE,
    496                     comp != null ? comp.flattenToShortString() : "", userHandle);
    497             if (DEBUG) Slog.d(TAG, "setCurInteractor comp=" + comp
    498                     + " user=" + userHandle);
    499         }
    500 
    501         ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
    502             List<ResolveInfo> available =
    503                     mContext.getPackageManager().queryIntentServicesAsUser(
    504                             new Intent(RecognitionService.SERVICE_INTERFACE),
    505                             PackageManager.MATCH_DIRECT_BOOT_AWARE
    506                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
    507             int numAvailable = available.size();
    508 
    509             if (numAvailable == 0) {
    510                 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
    511                 return null;
    512             } else {
    513                 if (prefPackage != null) {
    514                     for (int i=0; i<numAvailable; i++) {
    515                         ServiceInfo serviceInfo = available.get(i).serviceInfo;
    516                         if (prefPackage.equals(serviceInfo.packageName)) {
    517                             return new ComponentName(serviceInfo.packageName, serviceInfo.name);
    518                         }
    519                     }
    520                 }
    521                 if (numAvailable > 1) {
    522                     Slog.w(TAG, "more than one voice recognition service found, picking first");
    523                 }
    524 
    525                 ServiceInfo serviceInfo = available.get(0).serviceInfo;
    526                 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
    527             }
    528         }
    529 
    530         ComponentName getCurRecognizer(int userHandle) {
    531             String curRecognizer = Settings.Secure.getStringForUser(
    532                     mContext.getContentResolver(),
    533                     Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
    534             if (TextUtils.isEmpty(curRecognizer)) {
    535                 return null;
    536             }
    537             if (DEBUG) Slog.d(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
    538                     + " user=" + userHandle);
    539             return ComponentName.unflattenFromString(curRecognizer);
    540         }
    541 
    542         void setCurRecognizer(ComponentName comp, int userHandle) {
    543             Settings.Secure.putStringForUser(mContext.getContentResolver(),
    544                     Settings.Secure.VOICE_RECOGNITION_SERVICE,
    545                     comp != null ? comp.flattenToShortString() : "", userHandle);
    546             if (DEBUG) Slog.d(TAG, "setCurRecognizer comp=" + comp
    547                     + " user=" + userHandle);
    548         }
    549 
    550         ComponentName getCurAssistant(int userHandle) {
    551             String curAssistant = Settings.Secure.getStringForUser(
    552                     mContext.getContentResolver(),
    553                     Settings.Secure.ASSISTANT, userHandle);
    554             if (TextUtils.isEmpty(curAssistant)) {
    555                 return null;
    556             }
    557             if (DEBUG) Slog.d(TAG, "getCurAssistant curAssistant=" + curAssistant
    558                     + " user=" + userHandle);
    559             return ComponentName.unflattenFromString(curAssistant);
    560         }
    561 
    562         void resetCurAssistant(int userHandle) {
    563             Settings.Secure.putStringForUser(mContext.getContentResolver(),
    564                     Settings.Secure.ASSISTANT, null, userHandle);
    565         }
    566 
    567         @Override
    568         public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
    569             synchronized (this) {
    570                 if (mImpl == null || mImpl.mService == null
    571                         || service.asBinder() != mImpl.mService.asBinder()) {
    572                     throw new SecurityException(
    573                             "Caller is not the current voice interaction service");
    574                 }
    575                 final long caller = Binder.clearCallingIdentity();
    576                 try {
    577                     mImpl.showSessionLocked(args, flags, null, null);
    578                 } finally {
    579                     Binder.restoreCallingIdentity(caller);
    580                 }
    581             }
    582         }
    583 
    584         @Override
    585         public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
    586                 IVoiceInteractor interactor) {
    587             synchronized (this) {
    588                 if (mImpl == null) {
    589                     throw new SecurityException(
    590                             "deliverNewSession without running voice interaction service");
    591                 }
    592                 final long caller = Binder.clearCallingIdentity();
    593                 try {
    594                     return mImpl.deliverNewSessionLocked(token, session, interactor);
    595                 } finally {
    596                     Binder.restoreCallingIdentity(caller);
    597                 }
    598             }
    599         }
    600 
    601         @Override
    602         public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
    603             synchronized (this) {
    604                 if (mImpl == null) {
    605                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
    606                     return false;
    607                 }
    608                 final long caller = Binder.clearCallingIdentity();
    609                 try {
    610                     return mImpl.showSessionLocked(sessionArgs, flags, null, null);
    611                 } finally {
    612                     Binder.restoreCallingIdentity(caller);
    613                 }
    614             }
    615         }
    616 
    617         @Override
    618         public boolean hideSessionFromSession(IBinder token) {
    619             synchronized (this) {
    620                 if (mImpl == null) {
    621                     Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
    622                     return false;
    623                 }
    624                 final long caller = Binder.clearCallingIdentity();
    625                 try {
    626                     return mImpl.hideSessionLocked();
    627                 } finally {
    628                     Binder.restoreCallingIdentity(caller);
    629                 }
    630             }
    631         }
    632 
    633         @Override
    634         public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
    635             synchronized (this) {
    636                 if (mImpl == null) {
    637                     Slog.w(TAG, "startVoiceActivity without running voice interaction service");
    638                     return ActivityManager.START_CANCELED;
    639                 }
    640                 final int callingPid = Binder.getCallingPid();
    641                 final int callingUid = Binder.getCallingUid();
    642                 final long caller = Binder.clearCallingIdentity();
    643                 try {
    644                     return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
    645                             intent, resolvedType);
    646                 } finally {
    647                     Binder.restoreCallingIdentity(caller);
    648                 }
    649             }
    650         }
    651 
    652         @Override
    653         public int startAssistantActivity(IBinder token, Intent intent, String resolvedType) {
    654             synchronized (this) {
    655                 if (mImpl == null) {
    656                     Slog.w(TAG, "startAssistantActivity without running voice interaction service");
    657                     return ActivityManager.START_CANCELED;
    658                 }
    659                 final int callingPid = Binder.getCallingPid();
    660                 final int callingUid = Binder.getCallingUid();
    661                 final long caller = Binder.clearCallingIdentity();
    662                 try {
    663                     return mImpl.startAssistantActivityLocked(callingPid, callingUid, token,
    664                             intent, resolvedType);
    665                 } finally {
    666                     Binder.restoreCallingIdentity(caller);
    667                 }
    668             }
    669         }
    670 
    671         @Override
    672         public void setKeepAwake(IBinder token, boolean keepAwake) {
    673             synchronized (this) {
    674                 if (mImpl == null) {
    675                     Slog.w(TAG, "setKeepAwake without running voice interaction service");
    676                     return;
    677                 }
    678                 final long caller = Binder.clearCallingIdentity();
    679                 try {
    680                     mImpl.setKeepAwakeLocked(token, keepAwake);
    681                 } finally {
    682                     Binder.restoreCallingIdentity(caller);
    683                 }
    684             }
    685         }
    686 
    687         @Override
    688         public void closeSystemDialogs(IBinder token) {
    689             synchronized (this) {
    690                 if (mImpl == null) {
    691                     Slog.w(TAG, "closeSystemDialogs without running voice interaction service");
    692                     return;
    693                 }
    694                 final long caller = Binder.clearCallingIdentity();
    695                 try {
    696                     mImpl.closeSystemDialogsLocked(token);
    697                 } finally {
    698                     Binder.restoreCallingIdentity(caller);
    699                 }
    700             }
    701         }
    702 
    703         @Override
    704         public void finish(IBinder token) {
    705             synchronized (this) {
    706                 if (mImpl == null) {
    707                     Slog.w(TAG, "finish without running voice interaction service");
    708                     return;
    709                 }
    710                 final long caller = Binder.clearCallingIdentity();
    711                 try {
    712                     mImpl.finishLocked(token, false);
    713                 } finally {
    714                     Binder.restoreCallingIdentity(caller);
    715                 }
    716             }
    717         }
    718 
    719         @Override
    720         public void setDisabledShowContext(int flags) {
    721             synchronized (this) {
    722                 if (mImpl == null) {
    723                     Slog.w(TAG, "setDisabledShowContext without running voice interaction service");
    724                     return;
    725                 }
    726                 final int callingUid = Binder.getCallingUid();
    727                 final long caller = Binder.clearCallingIdentity();
    728                 try {
    729                     mImpl.setDisabledShowContextLocked(callingUid, flags);
    730                 } finally {
    731                     Binder.restoreCallingIdentity(caller);
    732                 }
    733             }
    734         }
    735 
    736         @Override
    737         public int getDisabledShowContext() {
    738             synchronized (this) {
    739                 if (mImpl == null) {
    740                     Slog.w(TAG, "getDisabledShowContext without running voice interaction service");
    741                     return 0;
    742                 }
    743                 final int callingUid = Binder.getCallingUid();
    744                 final long caller = Binder.clearCallingIdentity();
    745                 try {
    746                     return mImpl.getDisabledShowContextLocked(callingUid);
    747                 } finally {
    748                     Binder.restoreCallingIdentity(caller);
    749                 }
    750             }
    751         }
    752 
    753         @Override
    754         public int getUserDisabledShowContext() {
    755             synchronized (this) {
    756                 if (mImpl == null) {
    757                     Slog.w(TAG,
    758                             "getUserDisabledShowContext without running voice interaction service");
    759                     return 0;
    760                 }
    761                 final int callingUid = Binder.getCallingUid();
    762                 final long caller = Binder.clearCallingIdentity();
    763                 try {
    764                     return mImpl.getUserDisabledShowContextLocked(callingUid);
    765                 } finally {
    766                     Binder.restoreCallingIdentity(caller);
    767                 }
    768             }
    769         }
    770 
    771         //----------------- Model management APIs --------------------------------//
    772 
    773         @Override
    774         public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
    775             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
    776 
    777             if (bcp47Locale == null) {
    778                 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
    779             }
    780 
    781             final int callingUid = UserHandle.getCallingUserId();
    782             final long caller = Binder.clearCallingIdentity();
    783             try {
    784                 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
    785             } finally {
    786                 Binder.restoreCallingIdentity(caller);
    787             }
    788         }
    789 
    790         @Override
    791         public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
    792             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
    793             if (model == null) {
    794                 throw new IllegalArgumentException("Model must not be null");
    795             }
    796 
    797             final long caller = Binder.clearCallingIdentity();
    798             try {
    799                 if (mDbHelper.updateKeyphraseSoundModel(model)) {
    800                     synchronized (this) {
    801                         // Notify the voice interaction service of a change in sound models.
    802                         if (mImpl != null && mImpl.mService != null) {
    803                             mImpl.notifySoundModelsChangedLocked();
    804                         }
    805                     }
    806                     return SoundTriggerInternal.STATUS_OK;
    807                 } else {
    808                     return SoundTriggerInternal.STATUS_ERROR;
    809                 }
    810             } finally {
    811                 Binder.restoreCallingIdentity(caller);
    812             }
    813         }
    814 
    815         @Override
    816         public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
    817             enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
    818 
    819             if (bcp47Locale == null) {
    820                 throw new IllegalArgumentException(
    821                         "Illegal argument(s) in deleteKeyphraseSoundModel");
    822             }
    823 
    824             final int callingUid = UserHandle.getCallingUserId();
    825             final long caller = Binder.clearCallingIdentity();
    826             boolean deleted = false;
    827             try {
    828                 int unloadStatus = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
    829                 if (unloadStatus != SoundTriggerInternal.STATUS_OK) {
    830                     Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus);
    831                 }
    832                 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
    833                 return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR;
    834             } finally {
    835                 if (deleted) {
    836                     synchronized (this) {
    837                         // Notify the voice interaction service of a change in sound models.
    838                         if (mImpl != null && mImpl.mService != null) {
    839                             mImpl.notifySoundModelsChangedLocked();
    840                         }
    841                         mLoadedKeyphraseIds.remove(keyphraseId);
    842                     }
    843                 }
    844                 Binder.restoreCallingIdentity(caller);
    845             }
    846         }
    847 
    848         //----------------- SoundTrigger APIs --------------------------------//
    849         @Override
    850         public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
    851                 String bcp47Locale) {
    852             synchronized (this) {
    853                 if (mImpl == null || mImpl.mService == null
    854                         || service.asBinder() != mImpl.mService.asBinder()) {
    855                     throw new SecurityException(
    856                             "Caller is not the current voice interaction service");
    857                 }
    858             }
    859 
    860             if (bcp47Locale == null) {
    861                 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
    862             }
    863 
    864             final int callingUid = UserHandle.getCallingUserId();
    865             final long caller = Binder.clearCallingIdentity();
    866             try {
    867                 KeyphraseSoundModel model =
    868                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
    869                 return model != null;
    870             } finally {
    871                 Binder.restoreCallingIdentity(caller);
    872             }
    873         }
    874 
    875         @Override
    876         public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
    877             // Allow the call if this is the current voice interaction service.
    878             synchronized (this) {
    879                 if (mImpl == null || mImpl.mService == null
    880                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
    881                     throw new SecurityException(
    882                             "Caller is not the current voice interaction service");
    883                 }
    884 
    885                 final long caller = Binder.clearCallingIdentity();
    886                 try {
    887                     return mSoundTriggerInternal.getModuleProperties();
    888                 } finally {
    889                     Binder.restoreCallingIdentity(caller);
    890                 }
    891             }
    892         }
    893 
    894         @Override
    895         public int startRecognition(IVoiceInteractionService service, int keyphraseId,
    896                 String bcp47Locale, IRecognitionStatusCallback callback,
    897                 RecognitionConfig recognitionConfig) {
    898             // Allow the call if this is the current voice interaction service.
    899             synchronized (this) {
    900                 if (mImpl == null || mImpl.mService == null
    901                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
    902                     throw new SecurityException(
    903                             "Caller is not the current voice interaction service");
    904                 }
    905 
    906                 if (callback == null || recognitionConfig == null || bcp47Locale == null) {
    907                     throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
    908                 }
    909             }
    910 
    911             int callingUid = UserHandle.getCallingUserId();
    912             final long caller = Binder.clearCallingIdentity();
    913             try {
    914                 KeyphraseSoundModel soundModel =
    915                         mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
    916                 if (soundModel == null
    917                         || soundModel.uuid == null
    918                         || soundModel.keyphrases == null) {
    919                     Slog.w(TAG, "No matching sound model found in startRecognition");
    920                     return SoundTriggerInternal.STATUS_ERROR;
    921                 } else {
    922                     // Regardless of the status of the start recognition, we need to make sure
    923                     // that we unload this model if needed later.
    924                     synchronized (this) {
    925                         mLoadedKeyphraseIds.add(keyphraseId);
    926                     }
    927                     return mSoundTriggerInternal.startRecognition(
    928                             keyphraseId, soundModel, callback, recognitionConfig);
    929                 }
    930             } finally {
    931                 Binder.restoreCallingIdentity(caller);
    932             }
    933         }
    934 
    935         @Override
    936         public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
    937                 IRecognitionStatusCallback callback) {
    938             // Allow the call if this is the current voice interaction service.
    939             synchronized (this) {
    940                 if (mImpl == null || mImpl.mService == null
    941                         || service == null || service.asBinder() != mImpl.mService.asBinder()) {
    942                     throw new SecurityException(
    943                             "Caller is not the current voice interaction service");
    944                 }
    945             }
    946 
    947             final long caller = Binder.clearCallingIdentity();
    948             try {
    949                 return mSoundTriggerInternal.stopRecognition(keyphraseId, callback);
    950             } finally {
    951                 Binder.restoreCallingIdentity(caller);
    952             }
    953         }
    954 
    955         private synchronized void unloadAllKeyphraseModels() {
    956             for (int keyphraseId : mLoadedKeyphraseIds) {
    957                 final long caller = Binder.clearCallingIdentity();
    958                 try {
    959                     int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
    960                     if (status != SoundTriggerInternal.STATUS_OK) {
    961                         Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
    962                     }
    963                 } finally {
    964                     Binder.restoreCallingIdentity(caller);
    965                 }
    966             }
    967             mLoadedKeyphraseIds.clear();
    968         }
    969 
    970         @Override
    971         public ComponentName getActiveServiceComponentName() {
    972             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
    973             synchronized (this) {
    974                 return mImpl != null ? mImpl.mComponent : null;
    975             }
    976         }
    977 
    978         @Override
    979         public boolean showSessionForActiveService(Bundle args, int sourceFlags,
    980                 IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
    981             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
    982             synchronized (this) {
    983                 if (mImpl == null) {
    984                     Slog.w(TAG, "showSessionForActiveService without running voice interaction"
    985                             + "service");
    986                     return false;
    987                 }
    988                 final long caller = Binder.clearCallingIdentity();
    989                 try {
    990                     return mImpl.showSessionLocked(args,
    991                             sourceFlags
    992                                     | VoiceInteractionSession.SHOW_WITH_ASSIST
    993                                     | VoiceInteractionSession.SHOW_WITH_SCREENSHOT,
    994                             showCallback, activityToken);
    995                 } finally {
    996                     Binder.restoreCallingIdentity(caller);
    997                 }
    998             }
    999         }
   1000 
   1001         @Override
   1002         public void hideCurrentSession() throws RemoteException {
   1003             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1004             synchronized (this) {
   1005                 if (mImpl == null) {
   1006                     return;
   1007                 }
   1008                 final long caller = Binder.clearCallingIdentity();
   1009                 try {
   1010                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
   1011                         try {
   1012                             mImpl.mActiveSession.mSession.closeSystemDialogs();
   1013                         } catch (RemoteException e) {
   1014                             Log.w(TAG, "Failed to call closeSystemDialogs", e);
   1015                         }
   1016                     }
   1017                 } finally {
   1018                     Binder.restoreCallingIdentity(caller);
   1019                 }
   1020             }
   1021         }
   1022 
   1023         @Override
   1024         public void launchVoiceAssistFromKeyguard() {
   1025             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1026             synchronized (this) {
   1027                 if (mImpl == null) {
   1028                     Slog.w(TAG, "launchVoiceAssistFromKeyguard without running voice interaction"
   1029                             + "service");
   1030                     return;
   1031                 }
   1032                 final long caller = Binder.clearCallingIdentity();
   1033                 try {
   1034                     mImpl.launchVoiceAssistFromKeyguard();
   1035                 } finally {
   1036                     Binder.restoreCallingIdentity(caller);
   1037                 }
   1038             }
   1039         }
   1040 
   1041         @Override
   1042         public boolean isSessionRunning() {
   1043             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1044             synchronized (this) {
   1045                 return mImpl != null && mImpl.mActiveSession != null;
   1046             }
   1047         }
   1048 
   1049         @Override
   1050         public boolean activeServiceSupportsAssist() {
   1051             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1052             synchronized (this) {
   1053                 return mImpl != null && mImpl.mInfo != null && mImpl.mInfo.getSupportsAssist();
   1054             }
   1055         }
   1056 
   1057         @Override
   1058         public boolean activeServiceSupportsLaunchFromKeyguard() throws RemoteException {
   1059             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1060             synchronized (this) {
   1061                 return mImpl != null && mImpl.mInfo != null
   1062                         && mImpl.mInfo.getSupportsLaunchFromKeyguard();
   1063             }
   1064         }
   1065 
   1066         @Override
   1067         public void onLockscreenShown() {
   1068             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1069             synchronized (this) {
   1070                 if (mImpl == null) {
   1071                     return;
   1072                 }
   1073                 final long caller = Binder.clearCallingIdentity();
   1074                 try {
   1075                     if (mImpl.mActiveSession != null && mImpl.mActiveSession.mSession != null) {
   1076                         try {
   1077                             mImpl.mActiveSession.mSession.onLockscreenShown();
   1078                         } catch (RemoteException e) {
   1079                             Log.w(TAG, "Failed to call onLockscreenShown", e);
   1080                         }
   1081                     }
   1082                 } finally {
   1083                     Binder.restoreCallingIdentity(caller);
   1084                 }
   1085             }
   1086         }
   1087 
   1088         @Override
   1089         public void registerVoiceInteractionSessionListener(
   1090                 IVoiceInteractionSessionListener listener) {
   1091             enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
   1092             synchronized (this) {
   1093                 mVoiceInteractionSessionListeners.register(listener);
   1094             }
   1095         }
   1096 
   1097         public void onSessionShown() {
   1098             synchronized (this) {
   1099                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
   1100                 for (int i = 0; i < size; ++i) {
   1101                     final IVoiceInteractionSessionListener listener =
   1102                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
   1103                     try {
   1104                         listener.onVoiceSessionShown();
   1105                     } catch (RemoteException e) {
   1106                         Slog.e(TAG, "Error delivering voice interaction open event.", e);
   1107                     }
   1108                 }
   1109                 mVoiceInteractionSessionListeners.finishBroadcast();
   1110             }
   1111         }
   1112 
   1113         public void onSessionHidden() {
   1114             synchronized (this) {
   1115                 final int size = mVoiceInteractionSessionListeners.beginBroadcast();
   1116                 for (int i = 0; i < size; ++i) {
   1117                     final IVoiceInteractionSessionListener listener =
   1118                             mVoiceInteractionSessionListeners.getBroadcastItem(i);
   1119                     try {
   1120                         listener.onVoiceSessionHidden();
   1121 
   1122                     } catch (RemoteException e) {
   1123                         Slog.e(TAG, "Error delivering voice interaction closed event.", e);
   1124                     }
   1125                 }
   1126                 mVoiceInteractionSessionListeners.finishBroadcast();
   1127             }
   1128         }
   1129 
   1130         @Override
   1131         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1132             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
   1133             synchronized (this) {
   1134                 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
   1135                 pw.println("  mEnableService: " + mEnableService);
   1136                 if (mImpl == null) {
   1137                     pw.println("  (No active implementation)");
   1138                     return;
   1139                 }
   1140                 mImpl.dumpLocked(fd, pw, args);
   1141             }
   1142             mSoundTriggerInternal.dump(fd, pw, args);
   1143         }
   1144 
   1145         private void enforceCallingPermission(String permission) {
   1146             if (mContext.checkCallingOrSelfPermission(permission)
   1147                     != PackageManager.PERMISSION_GRANTED) {
   1148                 throw new SecurityException("Caller does not hold the permission " + permission);
   1149             }
   1150         }
   1151 
   1152         class SettingsObserver extends ContentObserver {
   1153             SettingsObserver(Handler handler) {
   1154                 super(handler);
   1155                 ContentResolver resolver = mContext.getContentResolver();
   1156                 resolver.registerContentObserver(Settings.Secure.getUriFor(
   1157                         Settings.Secure.VOICE_INTERACTION_SERVICE), false, this,
   1158                         UserHandle.USER_ALL);
   1159             }
   1160 
   1161             @Override public void onChange(boolean selfChange) {
   1162                 synchronized (VoiceInteractionManagerServiceStub.this) {
   1163                     switchImplementationIfNeededLocked(false);
   1164                 }
   1165             }
   1166         }
   1167 
   1168         PackageMonitor mPackageMonitor = new PackageMonitor() {
   1169             @Override
   1170             public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
   1171                 if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit);
   1172 
   1173                 int userHandle = UserHandle.getUserId(uid);
   1174                 ComponentName curInteractor = getCurInteractor(userHandle);
   1175                 ComponentName curRecognizer = getCurRecognizer(userHandle);
   1176                 boolean hit = false;
   1177                 for (String pkg : packages) {
   1178                     if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) {
   1179                         hit = true;
   1180                         break;
   1181                     } else if (curRecognizer != null
   1182                             && pkg.equals(curRecognizer.getPackageName())) {
   1183                         hit = true;
   1184                         break;
   1185                     }
   1186                 }
   1187                 if (hit && doit) {
   1188                     // The user is force stopping our current interactor/recognizer.
   1189                     // Clear the current settings and restore default state.
   1190                     synchronized (VoiceInteractionManagerServiceStub.this) {
   1191                         unloadAllKeyphraseModels();
   1192                         if (mImpl != null) {
   1193                             mImpl.shutdownLocked();
   1194                             mImpl = null;
   1195                         }
   1196                         setCurInteractor(null, userHandle);
   1197                         setCurRecognizer(null, userHandle);
   1198                         resetCurAssistant(userHandle);
   1199                         initForUser(userHandle);
   1200                         switchImplementationIfNeededLocked(true);
   1201                     }
   1202                 }
   1203                 return hit;
   1204             }
   1205 
   1206             @Override
   1207             public void onHandleUserStop(Intent intent, int userHandle) {
   1208             }
   1209 
   1210             @Override
   1211             public void onPackageModified(String pkgName) {
   1212                 // If the package modified is not in the current user, then don't bother making
   1213                 // any changes as we are going to do any initialization needed when we switch users.
   1214                 if (mCurUser != getChangingUserId()) {
   1215                     return;
   1216                 }
   1217                 // Package getting updated will be handled by {@link #onSomePackagesChanged}.
   1218                 if (isPackageAppearing(pkgName) != PACKAGE_UNCHANGED) {
   1219                     return;
   1220                 }
   1221                 final ComponentName curInteractor = getCurInteractor(mCurUser);
   1222                 if (curInteractor == null) {
   1223                     final VoiceInteractionServiceInfo availInteractorInfo
   1224                             = findAvailInteractor(mCurUser, pkgName);
   1225                     if (availInteractorInfo != null) {
   1226                         final ComponentName availInteractor = new ComponentName(
   1227                                 availInteractorInfo.getServiceInfo().packageName,
   1228                                 availInteractorInfo.getServiceInfo().name);
   1229                         setCurInteractor(availInteractor, mCurUser);
   1230                         if (getCurRecognizer(mCurUser) == null &&
   1231                                 availInteractorInfo.getRecognitionService() != null) {
   1232                             setCurRecognizer(new ComponentName(
   1233                                     availInteractorInfo.getServiceInfo().packageName,
   1234                                     availInteractorInfo.getRecognitionService()), mCurUser);
   1235                         }
   1236                     }
   1237                 } else {
   1238                     if (didSomePackagesChange()) {
   1239                         // Package is changed
   1240                         if (curInteractor != null && pkgName.equals(
   1241                                 curInteractor.getPackageName())) {
   1242                             switchImplementationIfNeeded(true);
   1243                         }
   1244                     } else {
   1245                         // Only some components are changed
   1246                         if (curInteractor != null
   1247                                 && isComponentModified(curInteractor.getClassName())) {
   1248                             switchImplementationIfNeeded(true);
   1249                         }
   1250                     }
   1251                 }
   1252             }
   1253 
   1254             @Override
   1255             public void onSomePackagesChanged() {
   1256                 int userHandle = getChangingUserId();
   1257                 if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle);
   1258 
   1259                 synchronized (VoiceInteractionManagerServiceStub.this) {
   1260                     ComponentName curInteractor = getCurInteractor(userHandle);
   1261                     ComponentName curRecognizer = getCurRecognizer(userHandle);
   1262                     ComponentName curAssistant = getCurAssistant(userHandle);
   1263                     if (curRecognizer == null) {
   1264                         // Could a new recognizer appear when we don't have one pre-installed?
   1265                         if (anyPackagesAppearing()) {
   1266                             curRecognizer = findAvailRecognizer(null, userHandle);
   1267                             if (curRecognizer != null) {
   1268                                 setCurRecognizer(curRecognizer, userHandle);
   1269                             }
   1270                         }
   1271                         return;
   1272                     }
   1273 
   1274                     if (curInteractor != null) {
   1275                         int change = isPackageDisappearing(curInteractor.getPackageName());
   1276                         if (change == PACKAGE_PERMANENT_CHANGE) {
   1277                             // The currently set interactor is permanently gone; fall back to
   1278                             // the default config.
   1279                             setCurInteractor(null, userHandle);
   1280                             setCurRecognizer(null, userHandle);
   1281                             resetCurAssistant(userHandle);
   1282                             initForUser(userHandle);
   1283                             return;
   1284                         }
   1285 
   1286                         change = isPackageAppearing(curInteractor.getPackageName());
   1287                         if (change != PACKAGE_UNCHANGED) {
   1288                             // If current interactor is now appearing, for any reason, then
   1289                             // restart our connection with it.
   1290                             if (mImpl != null && curInteractor.getPackageName().equals(
   1291                                     mImpl.mComponent.getPackageName())) {
   1292                                 switchImplementationIfNeededLocked(true);
   1293                             }
   1294                         }
   1295                         return;
   1296                     }
   1297 
   1298                     if (curAssistant != null) {
   1299                         int change = isPackageDisappearing(curAssistant.getPackageName());
   1300                         if (change == PACKAGE_PERMANENT_CHANGE) {
   1301                             // If the currently set assistant is being removed, then we should
   1302                             // reset back to the default state (which is probably that we prefer
   1303                             // to have the default full voice interactor enabled).
   1304                             setCurInteractor(null, userHandle);
   1305                             setCurRecognizer(null, userHandle);
   1306                             resetCurAssistant(userHandle);
   1307                             initForUser(userHandle);
   1308                             return;
   1309                         }
   1310                     }
   1311 
   1312                     // There is no interactor, so just deal with a simple recognizer.
   1313                     int change = isPackageDisappearing(curRecognizer.getPackageName());
   1314                     if (change == PACKAGE_PERMANENT_CHANGE
   1315                             || change == PACKAGE_TEMPORARY_CHANGE) {
   1316                         setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
   1317 
   1318                     } else if (isPackageModified(curRecognizer.getPackageName())) {
   1319                         setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
   1320                                 userHandle), userHandle);
   1321                     }
   1322                 }
   1323             }
   1324         };
   1325     }
   1326 }
   1327