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