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.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