2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.voiceinteraction;
19 import android.Manifest;
20 import android.app.ActivityManager;
21 import android.app.AppGlobals;
22 import android.content.ComponentName;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.IPackageManager;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.content.pm.ServiceInfo;
31 import android.content.res.Configuration;
32 import android.content.res.Resources;
33 import android.database.ContentObserver;
34 import android.hardware.soundtrigger.IRecognitionStatusCallback;
35 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
36 import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
37 import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
38 import android.os.Binder;
39 import android.os.Bundle;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.Parcel;
43 import android.os.RemoteException;
44 import android.os.SystemProperties;
45 import android.os.UserHandle;
46 import android.provider.Settings;
47 import android.service.voice.IVoiceInteractionService;
48 import android.service.voice.IVoiceInteractionSession;
49 import android.service.voice.VoiceInteractionService;
50 import android.service.voice.VoiceInteractionServiceInfo;
51 import android.speech.RecognitionService;
52 import android.text.TextUtils;
53 import android.util.Slog;
55 import com.android.internal.app.IVoiceInteractionManagerService;
56 import com.android.internal.app.IVoiceInteractor;
57 import com.android.internal.content.PackageMonitor;
58 import com.android.internal.os.BackgroundThread;
59 import com.android.server.SystemService;
60 import com.android.server.UiThread;
62 import java.io.FileDescriptor;
63 import java.io.PrintWriter;
64 import java.util.List;
67 * SystemService that publishes an IVoiceInteractionManagerService.
69 public class VoiceInteractionManagerService extends SystemService {
70 static final String TAG = "VoiceInteractionManagerService";
71 static final boolean DEBUG = false;
73 final Context mContext;
74 final ContentResolver mResolver;
75 final DatabaseHelper mDbHelper;
76 final SoundTriggerHelper mSoundTriggerHelper;
78 public VoiceInteractionManagerService(Context context) {
81 mResolver = context.getContentResolver();
82 mDbHelper = new DatabaseHelper(context);
83 mSoundTriggerHelper = new SoundTriggerHelper(context);
84 mServiceStub = new VoiceInteractionManagerServiceStub();
88 public void onStart() {
89 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub);
93 public void onBootPhase(int phase) {
94 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
95 mServiceStub.systemRunning(isSafeMode());
100 public void onStartUser(int userHandle) {
101 mServiceStub.initForUser(userHandle);
105 public void onSwitchUser(int userHandle) {
106 mServiceStub.switchUser(userHandle);
109 // implementation entry point and binder service
110 private final VoiceInteractionManagerServiceStub mServiceStub;
112 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
114 VoiceInteractionManagerServiceImpl mImpl;
116 private boolean mSafeMode;
117 private int mCurUser;
118 private final boolean mEnableService;
120 VoiceInteractionManagerServiceStub() {
121 mEnableService = shouldEnableService(mContext.getResources());
125 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
126 throws RemoteException {
128 return super.onTransact(code, data, reply, flags);
129 } catch (RuntimeException e) {
130 // The activity manager only throws security exceptions, so let's
132 if (!(e instanceof SecurityException)) {
133 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e);
139 public void initForUser(int userHandle) {
140 if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle);
141 String curInteractorStr = Settings.Secure.getStringForUser(
142 mContext.getContentResolver(),
143 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
144 ComponentName curRecognizer = getCurRecognizer(userHandle);
145 VoiceInteractionServiceInfo curInteractorInfo = null;
146 if (curInteractorStr == null && curRecognizer != null && mEnableService) {
147 // If there is no interactor setting, that means we are upgrading
148 // from an older platform version. If the current recognizer is not
149 // set or matches the preferred recognizer, then we want to upgrade
150 // the user to have the default voice interaction service enabled.
151 // Note that we don't do this for low-RAM devices, since we aren't
152 // supporting voice interaction services there.
153 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer);
154 if (curInteractorInfo != null) {
155 // Looks good! We'll apply this one. To make it happen, we clear the
156 // recognizer so that we don't think we have anything set and will
157 // re-apply the settings.
158 curRecognizer = null;
162 // If we are on a svelte device, make sure an interactor is not currently
163 // enabled; if it is, turn it off.
164 if (!mEnableService && curInteractorStr != null) {
165 if (!TextUtils.isEmpty(curInteractorStr)) {
166 setCurInteractor(null, userHandle);
167 curInteractorStr = "";
171 if (curRecognizer != null) {
172 // If we already have at least a recognizer, then we probably want to
173 // leave things as they are... unless something has disappeared.
174 IPackageManager pm = AppGlobals.getPackageManager();
175 ServiceInfo interactorInfo = null;
176 ServiceInfo recognizerInfo = null;
177 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr)
178 ? ComponentName.unflattenFromString(curInteractorStr) : null;
180 recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle);
181 if (curInteractor != null) {
182 interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle);
184 } catch (RemoteException e) {
186 // If the apps for the currently set components still exist, then all is okay.
187 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) {
192 // Initializing settings, look for an interactor first (but only on non-svelte).
193 if (curInteractorInfo == null && mEnableService) {
194 curInteractorInfo = findAvailInteractor(userHandle, null);
197 if (curInteractorInfo != null) {
198 // Eventually it will be an error to not specify this.
199 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName,
200 curInteractorInfo.getServiceInfo().name), userHandle);
201 if (curInteractorInfo.getRecognitionService() != null) {
203 new ComponentName(curInteractorInfo.getServiceInfo().packageName,
204 curInteractorInfo.getRecognitionService()), userHandle);
209 // No voice interactor, we'll just set up a simple recognizer.
210 curRecognizer = findAvailRecognizer(null, userHandle);
211 if (curRecognizer != null) {
212 if (curInteractorInfo == null) {
213 setCurInteractor(null, userHandle);
215 setCurRecognizer(curRecognizer, userHandle);
219 private boolean shouldEnableService(Resources res) {
220 // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag.
221 return !ActivityManager.isLowRamDeviceStatic()
222 || res.getBoolean(com.android.internal.R.bool.config_forceEnableVoiceInteractionService);
225 public void systemRunning(boolean safeMode) {
226 mSafeMode = safeMode;
228 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(),
229 UserHandle.ALL, true);
230 new SettingsObserver(UiThread.getHandler());
232 synchronized (this) {
233 mCurUser = ActivityManager.getCurrentUser();
234 switchImplementationIfNeededLocked(false);
238 public void switchUser(int userHandle) {
239 synchronized (this) {
240 mCurUser = userHandle;
241 switchImplementationIfNeededLocked(false);
245 void switchImplementationIfNeededLocked(boolean force) {
247 String curService = Settings.Secure.getStringForUser(
248 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser);
249 ComponentName serviceComponent = null;
250 if (curService != null && !curService.isEmpty()) {
252 serviceComponent = ComponentName.unflattenFromString(curService);
253 } catch (RuntimeException e) {
254 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e);
255 serviceComponent = null;
258 if (force || mImpl == null || mImpl.mUser != mCurUser
259 || !mImpl.mComponent.equals(serviceComponent)) {
260 mSoundTriggerHelper.stopAllRecognitions();
262 mImpl.shutdownLocked();
264 if (serviceComponent != null) {
265 mImpl = new VoiceInteractionManagerServiceImpl(mContext,
266 UiThread.getHandler(), this, mCurUser, serviceComponent);
275 VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) {
276 List<ResolveInfo> available =
277 mContext.getPackageManager().queryIntentServicesAsUser(
278 new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle);
279 int numAvailable = available.size();
281 if (numAvailable == 0) {
282 Slog.w(TAG, "no available voice interaction services found for user " + userHandle);
285 // Find first system package. We never want to allow third party services to
286 // be automatically selected, because those require approval of the user.
287 VoiceInteractionServiceInfo foundInfo = null;
288 for (int i=0; i<numAvailable; i++) {
289 ServiceInfo cur = available.get(i).serviceInfo;
290 if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
291 ComponentName comp = new ComponentName(cur.packageName, cur.name);
293 VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
294 mContext.getPackageManager(), comp, userHandle);
295 if (info.getParseError() == null) {
296 if (recognizer == null || info.getServiceInfo().packageName.equals(
297 recognizer.getPackageName())) {
298 if (foundInfo == null) {
301 Slog.w(TAG, "More than one voice interaction service, "
304 foundInfo.getServiceInfo().packageName,
305 foundInfo.getServiceInfo().name)
307 + new ComponentName(cur.packageName, cur.name));
311 Slog.w(TAG, "Bad interaction service " + comp + ": "
312 + info.getParseError());
314 } catch (PackageManager.NameNotFoundException e) {
315 Slog.w(TAG, "Failure looking up interaction service " + comp);
316 } catch (RemoteException e) {
325 ComponentName getCurInteractor(int userHandle) {
326 String curInteractor = Settings.Secure.getStringForUser(
327 mContext.getContentResolver(),
328 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
329 if (TextUtils.isEmpty(curInteractor)) {
332 if (DEBUG) Slog.i(TAG, "getCurInteractor curInteractor=" + curInteractor
333 + " user=" + userHandle);
334 return ComponentName.unflattenFromString(curInteractor);
337 void setCurInteractor(ComponentName comp, int userHandle) {
338 Settings.Secure.putStringForUser(mContext.getContentResolver(),
339 Settings.Secure.VOICE_INTERACTION_SERVICE,
340 comp != null ? comp.flattenToShortString() : "", userHandle);
341 if (DEBUG) Slog.i(TAG, "setCurInteractor comp=" + comp
342 + " user=" + userHandle);
345 ComponentName findAvailRecognizer(String prefPackage, int userHandle) {
346 List<ResolveInfo> available =
347 mContext.getPackageManager().queryIntentServicesAsUser(
348 new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle);
349 int numAvailable = available.size();
351 if (numAvailable == 0) {
352 Slog.w(TAG, "no available voice recognition services found for user " + userHandle);
355 if (prefPackage != null) {
356 for (int i=0; i<numAvailable; i++) {
357 ServiceInfo serviceInfo = available.get(i).serviceInfo;
358 if (prefPackage.equals(serviceInfo.packageName)) {
359 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
363 if (numAvailable > 1) {
364 Slog.w(TAG, "more than one voice recognition service found, picking first");
367 ServiceInfo serviceInfo = available.get(0).serviceInfo;
368 return new ComponentName(serviceInfo.packageName, serviceInfo.name);
372 ComponentName getCurRecognizer(int userHandle) {
373 String curRecognizer = Settings.Secure.getStringForUser(
374 mContext.getContentResolver(),
375 Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle);
376 if (TextUtils.isEmpty(curRecognizer)) {
379 if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer
380 + " user=" + userHandle);
381 return ComponentName.unflattenFromString(curRecognizer);
384 void setCurRecognizer(ComponentName comp, int userHandle) {
385 Settings.Secure.putStringForUser(mContext.getContentResolver(),
386 Settings.Secure.VOICE_RECOGNITION_SERVICE,
387 comp != null ? comp.flattenToShortString() : "", userHandle);
388 if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp
389 + " user=" + userHandle);
393 public void startSession(IVoiceInteractionService service, Bundle args) {
394 synchronized (this) {
395 if (mImpl == null || mImpl.mService == null
396 || service.asBinder() != mImpl.mService.asBinder()) {
397 throw new SecurityException(
398 "Caller is not the current voice interaction service");
400 final int callingPid = Binder.getCallingPid();
401 final int callingUid = Binder.getCallingUid();
402 final long caller = Binder.clearCallingIdentity();
404 mImpl.startSessionLocked(callingPid, callingUid, args);
406 Binder.restoreCallingIdentity(caller);
412 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
413 IVoiceInteractor interactor) {
414 synchronized (this) {
416 throw new SecurityException(
417 "deliverNewSession without running voice interaction service");
419 final int callingPid = Binder.getCallingPid();
420 final int callingUid = Binder.getCallingUid();
421 final long caller = Binder.clearCallingIdentity();
423 return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session,
426 Binder.restoreCallingIdentity(caller);
432 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
433 synchronized (this) {
435 Slog.w(TAG, "startVoiceActivity without running voice interaction service");
436 return ActivityManager.START_CANCELED;
438 final int callingPid = Binder.getCallingPid();
439 final int callingUid = Binder.getCallingUid();
440 final long caller = Binder.clearCallingIdentity();
441 if (!SystemProperties.getBoolean("persist.test.voice_interaction", false)) {
442 throw new SecurityException("Voice interaction not supported");
445 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token,
446 intent, resolvedType);
448 Binder.restoreCallingIdentity(caller);
454 public void finish(IBinder token) {
455 synchronized (this) {
457 Slog.w(TAG, "finish without running voice interaction service");
460 final int callingPid = Binder.getCallingPid();
461 final int callingUid = Binder.getCallingUid();
462 final long caller = Binder.clearCallingIdentity();
464 mImpl.finishLocked(callingPid, callingUid, token);
466 Binder.restoreCallingIdentity(caller);
471 //----------------- Model management APIs --------------------------------//
474 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
475 synchronized (this) {
476 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
477 != PackageManager.PERMISSION_GRANTED) {
478 throw new SecurityException("Caller does not hold the permission "
479 + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
483 if (bcp47Locale == null) {
484 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
487 final int callingUid = UserHandle.getCallingUserId();
488 final long caller = Binder.clearCallingIdentity();
490 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
492 Binder.restoreCallingIdentity(caller);
497 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
498 synchronized (this) {
499 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
500 != PackageManager.PERMISSION_GRANTED) {
501 throw new SecurityException("Caller does not hold the permission "
502 + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
505 throw new IllegalArgumentException("Model must not be null");
509 final long caller = Binder.clearCallingIdentity();
511 if (mDbHelper.updateKeyphraseSoundModel(model)) {
512 synchronized (this) {
513 // Notify the voice interaction service of a change in sound models.
514 if (mImpl != null && mImpl.mService != null) {
515 mImpl.notifySoundModelsChangedLocked();
518 return SoundTriggerHelper.STATUS_OK;
520 return SoundTriggerHelper.STATUS_ERROR;
523 Binder.restoreCallingIdentity(caller);
528 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
529 synchronized (this) {
530 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
531 != PackageManager.PERMISSION_GRANTED) {
532 throw new SecurityException("Caller does not hold the permission "
533 + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
537 if (bcp47Locale == null) {
538 throw new IllegalArgumentException(
539 "Illegal argument(s) in deleteKeyphraseSoundModel");
542 final int callingUid = UserHandle.getCallingUserId();
543 final long caller = Binder.clearCallingIdentity();
544 boolean deleted = false;
546 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
547 return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR;
550 synchronized (this) {
551 // Notify the voice interaction service of a change in sound models.
552 if (mImpl != null && mImpl.mService != null) {
553 mImpl.notifySoundModelsChangedLocked();
557 Binder.restoreCallingIdentity(caller);
561 //----------------- SoundTrigger APIs --------------------------------//
563 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId,
564 String bcp47Locale) {
565 synchronized (this) {
566 if (mImpl == null || mImpl.mService == null
567 || service.asBinder() != mImpl.mService.asBinder()) {
568 throw new SecurityException(
569 "Caller is not the current voice interaction service");
573 if (bcp47Locale == null) {
574 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase");
577 final int callingUid = UserHandle.getCallingUserId();
578 final long caller = Binder.clearCallingIdentity();
580 KeyphraseSoundModel model =
581 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
582 return model != null;
584 Binder.restoreCallingIdentity(caller);
589 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) {
590 // Allow the call if this is the current voice interaction service.
591 synchronized (this) {
592 if (mImpl == null || mImpl.mService == null
593 || service == null || service.asBinder() != mImpl.mService.asBinder()) {
594 throw new SecurityException(
595 "Caller is not the current voice interaction service");
598 final long caller = Binder.clearCallingIdentity();
600 return mSoundTriggerHelper.moduleProperties;
602 Binder.restoreCallingIdentity(caller);
608 public int startRecognition(IVoiceInteractionService service, int keyphraseId,
609 String bcp47Locale, IRecognitionStatusCallback callback,
610 RecognitionConfig recognitionConfig) {
611 // Allow the call if this is the current voice interaction service.
612 synchronized (this) {
613 if (mImpl == null || mImpl.mService == null
614 || service == null || service.asBinder() != mImpl.mService.asBinder()) {
615 throw new SecurityException(
616 "Caller is not the current voice interaction service");
619 if (callback == null || recognitionConfig == null || bcp47Locale == null) {
620 throw new IllegalArgumentException("Illegal argument(s) in startRecognition");
624 int callingUid = UserHandle.getCallingUserId();
625 final long caller = Binder.clearCallingIdentity();
627 KeyphraseSoundModel soundModel =
628 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale);
629 if (soundModel == null
630 || soundModel.uuid == null
631 || soundModel.keyphrases == null) {
632 Slog.w(TAG, "No matching sound model found in startRecognition");
633 return SoundTriggerHelper.STATUS_ERROR;
635 return mSoundTriggerHelper.startRecognition(
636 keyphraseId, soundModel, callback, recognitionConfig);
639 Binder.restoreCallingIdentity(caller);
644 public int stopRecognition(IVoiceInteractionService service, int keyphraseId,
645 IRecognitionStatusCallback callback) {
646 // Allow the call if this is the current voice interaction service.
647 synchronized (this) {
648 if (mImpl == null || mImpl.mService == null
649 || service == null || service.asBinder() != mImpl.mService.asBinder()) {
650 throw new SecurityException(
651 "Caller is not the current voice interaction service");
655 final long caller = Binder.clearCallingIdentity();
657 return mSoundTriggerHelper.stopRecognition(keyphraseId, callback);
659 Binder.restoreCallingIdentity(caller);
664 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
665 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
666 != PackageManager.PERMISSION_GRANTED) {
667 pw.println("Permission Denial: can't dump PowerManager from from pid="
668 + Binder.getCallingPid()
669 + ", uid=" + Binder.getCallingUid());
672 synchronized (this) {
673 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n");
674 pw.println(" mEnableService: " + mEnableService);
676 pw.println(" (No active implementation)");
679 mImpl.dumpLocked(fd, pw, args);
681 mSoundTriggerHelper.dump(fd, pw, args);
684 class SettingsObserver extends ContentObserver {
685 SettingsObserver(Handler handler) {
687 ContentResolver resolver = mContext.getContentResolver();
688 resolver.registerContentObserver(Settings.Secure.getUriFor(
689 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this);
692 @Override public void onChange(boolean selfChange) {
693 synchronized (VoiceInteractionManagerServiceStub.this) {
694 switchImplementationIfNeededLocked(false);
699 PackageMonitor mPackageMonitor = new PackageMonitor() {
701 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
702 return super.onHandleForceStop(intent, packages, uid, doit);
706 public void onHandleUserStop(Intent intent, int userHandle) {
710 public void onSomePackagesChanged() {
711 int userHandle = getChangingUserId();
712 if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle);
714 ComponentName curInteractor = getCurInteractor(userHandle);
715 ComponentName curRecognizer = getCurRecognizer(userHandle);
716 if (curRecognizer == null) {
717 // Could a new recognizer appear when we don't have one pre-installed?
718 if (anyPackagesAppearing()) {
719 curRecognizer = findAvailRecognizer(null, userHandle);
720 if (curRecognizer != null) {
721 setCurRecognizer(curRecognizer, userHandle);
727 if (curInteractor != null) {
728 int change = isPackageDisappearing(curInteractor.getPackageName());
729 if (change == PACKAGE_PERMANENT_CHANGE) {
730 // The currently set interactor is permanently gone; fall back to
731 // the default config.
732 setCurInteractor(null, userHandle);
733 setCurRecognizer(null, userHandle);
734 initForUser(userHandle);
738 change = isPackageAppearing(curInteractor.getPackageName());
739 if (change != PACKAGE_UNCHANGED) {
740 // If current interactor is now appearing, for any reason, then
741 // restart our connection with it.
742 if (mImpl != null && curInteractor.getPackageName().equals(
743 mImpl.mComponent.getPackageName())) {
744 switchImplementationIfNeededLocked(true);
750 // There is no interactor, so just deal with a simple recognizer.
751 int change = isPackageDisappearing(curRecognizer.getPackageName());
752 if (change == PACKAGE_PERMANENT_CHANGE
753 || change == PACKAGE_TEMPORARY_CHANGE) {
754 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
756 } else if (isPackageModified(curRecognizer.getPackageName())) {
757 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
758 userHandle), userHandle);