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