VoiceInteractionManagerService.java revision 8cf8f71644643601fe8c3e9538fd00412b1ae8b1
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 17package com.android.server.voiceinteraction; 18 19import android.Manifest; 20import android.app.ActivityManager; 21import android.app.AppGlobals; 22import android.content.ComponentName; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.pm.ApplicationInfo; 27import android.content.pm.IPackageManager; 28import android.content.pm.PackageManager; 29import android.content.pm.ResolveInfo; 30import android.content.pm.ServiceInfo; 31import android.database.ContentObserver; 32import android.hardware.soundtrigger.IRecognitionStatusCallback; 33import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; 34import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; 35import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; 36import android.os.Binder; 37import android.os.Bundle; 38import android.os.Handler; 39import android.os.IBinder; 40import android.os.Parcel; 41import android.os.RemoteException; 42import android.os.SystemProperties; 43import android.os.UserHandle; 44import android.provider.Settings; 45import android.service.voice.IVoiceInteractionService; 46import android.service.voice.IVoiceInteractionSession; 47import android.service.voice.VoiceInteractionService; 48import android.service.voice.VoiceInteractionServiceInfo; 49import android.speech.RecognitionService; 50import android.text.TextUtils; 51import android.util.Slog; 52 53import com.android.internal.app.IVoiceInteractionManagerService; 54import com.android.internal.app.IVoiceInteractor; 55import com.android.internal.content.PackageMonitor; 56import com.android.internal.os.BackgroundThread; 57import com.android.server.SystemService; 58import com.android.server.UiThread; 59 60import java.io.FileDescriptor; 61import java.io.PrintWriter; 62import java.util.List; 63 64/** 65 * SystemService that publishes an IVoiceInteractionManagerService. 66 */ 67public class VoiceInteractionManagerService extends SystemService { 68 static final String TAG = "VoiceInteractionManagerService"; 69 static final boolean DEBUG = false; 70 71 final Context mContext; 72 final ContentResolver mResolver; 73 final DatabaseHelper mDbHelper; 74 final SoundTriggerHelper mSoundTriggerHelper; 75 76 public VoiceInteractionManagerService(Context context) { 77 super(context); 78 mContext = context; 79 mResolver = context.getContentResolver(); 80 mDbHelper = new DatabaseHelper(context); 81 mSoundTriggerHelper = new SoundTriggerHelper(context); 82 } 83 84 @Override 85 public void onStart() { 86 publishBinderService(Context.VOICE_INTERACTION_MANAGER_SERVICE, mServiceStub); 87 } 88 89 @Override 90 public void onBootPhase(int phase) { 91 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { 92 mServiceStub.systemRunning(isSafeMode()); 93 } 94 } 95 96 @Override 97 public void onStartUser(int userHandle) { 98 mServiceStub.initForUser(userHandle); 99 } 100 101 @Override 102 public void onSwitchUser(int userHandle) { 103 mServiceStub.switchUser(userHandle); 104 } 105 106 // implementation entry point and binder service 107 private final VoiceInteractionManagerServiceStub mServiceStub 108 = new VoiceInteractionManagerServiceStub(); 109 110 class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub { 111 112 VoiceInteractionManagerServiceImpl mImpl; 113 114 private boolean mSafeMode; 115 private int mCurUser; 116 117 @Override 118 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 119 throws RemoteException { 120 try { 121 return super.onTransact(code, data, reply, flags); 122 } catch (RuntimeException e) { 123 // The activity manager only throws security exceptions, so let's 124 // log all others. 125 if (!(e instanceof SecurityException)) { 126 Slog.wtf(TAG, "VoiceInteractionManagerService Crash", e); 127 } 128 throw e; 129 } 130 } 131 132 public void initForUser(int userHandle) { 133 if (DEBUG) Slog.i(TAG, "initForUser user=" + userHandle); 134 String curInteractorStr = Settings.Secure.getStringForUser( 135 mContext.getContentResolver(), 136 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 137 ComponentName curRecognizer = getCurRecognizer(userHandle); 138 VoiceInteractionServiceInfo curInteractorInfo = null; 139 if (curInteractorStr == null && curRecognizer != null) { 140 // If there is no interactor setting, that means we are upgrading 141 // from an older platform version. If the current recognizer is not 142 // set or matches the preferred recognizer, then we want to upgrade 143 // the user to have the default voice interaction service enabled. 144 curInteractorInfo = findAvailInteractor(userHandle, curRecognizer); 145 if (curInteractorInfo != null) { 146 // Looks good! We'll apply this one. To make it happen, we clear the 147 // recognizer so that we don't think we have anything set and will 148 // re-apply the settings. 149 curRecognizer = null; 150 } 151 } 152 153 if (curRecognizer != null) { 154 // If we already have at least a recognizer, then we probably want to 155 // leave things as they are... unless something has disappeared. 156 IPackageManager pm = AppGlobals.getPackageManager(); 157 ServiceInfo interactorInfo = null; 158 ServiceInfo recognizerInfo = null; 159 ComponentName curInteractor = !TextUtils.isEmpty(curInteractorStr) 160 ? ComponentName.unflattenFromString(curInteractorStr) : null; 161 try { 162 recognizerInfo = pm.getServiceInfo(curRecognizer, 0, userHandle); 163 if (curInteractor != null) { 164 interactorInfo = pm.getServiceInfo(curInteractor, 0, userHandle); 165 } 166 } catch (RemoteException e) { 167 } 168 // If the apps for the currently set components still exist, then all is okay. 169 if (recognizerInfo != null && (curInteractor == null || interactorInfo != null)) { 170 return; 171 } 172 } 173 174 // Initializing settings, look for an interactor first. 175 if (curInteractorInfo == null) { 176 curInteractorInfo = findAvailInteractor(userHandle, null); 177 } 178 if (curInteractorInfo != null) { 179 // Eventually it will be an error to not specify this. 180 setCurInteractor(new ComponentName(curInteractorInfo.getServiceInfo().packageName, 181 curInteractorInfo.getServiceInfo().name), userHandle); 182 if (curInteractorInfo.getRecognitionService() != null) { 183 setCurRecognizer( 184 new ComponentName(curInteractorInfo.getServiceInfo().packageName, 185 curInteractorInfo.getRecognitionService()), userHandle); 186 return; 187 } 188 } 189 190 // No voice interactor, we'll just set up a simple recognizer. 191 curRecognizer = findAvailRecognizer(null, userHandle); 192 if (curRecognizer != null) { 193 if (curInteractorInfo == null) { 194 setCurInteractor(null, userHandle); 195 } 196 setCurRecognizer(curRecognizer, userHandle); 197 } 198 } 199 200 public void systemRunning(boolean safeMode) { 201 mSafeMode = safeMode; 202 203 mPackageMonitor.register(mContext, BackgroundThread.getHandler().getLooper(), 204 UserHandle.ALL, true); 205 new SettingsObserver(UiThread.getHandler()); 206 207 synchronized (this) { 208 mCurUser = ActivityManager.getCurrentUser(); 209 switchImplementationIfNeededLocked(false); 210 } 211 } 212 213 public void switchUser(int userHandle) { 214 synchronized (this) { 215 mCurUser = userHandle; 216 switchImplementationIfNeededLocked(false); 217 } 218 } 219 220 void switchImplementationIfNeededLocked(boolean force) { 221 if (!mSafeMode) { 222 String curService = Settings.Secure.getStringForUser( 223 mResolver, Settings.Secure.VOICE_INTERACTION_SERVICE, mCurUser); 224 ComponentName serviceComponent = null; 225 if (curService != null && !curService.isEmpty()) { 226 try { 227 serviceComponent = ComponentName.unflattenFromString(curService); 228 } catch (RuntimeException e) { 229 Slog.wtf(TAG, "Bad voice interaction service name " + curService, e); 230 serviceComponent = null; 231 } 232 } 233 if (force || mImpl == null || mImpl.mUser != mCurUser 234 || !mImpl.mComponent.equals(serviceComponent)) { 235 mSoundTriggerHelper.stopAllRecognitions(); 236 if (mImpl != null) { 237 mImpl.shutdownLocked(); 238 } 239 if (serviceComponent != null) { 240 mImpl = new VoiceInteractionManagerServiceImpl(mContext, 241 UiThread.getHandler(), this, mCurUser, serviceComponent); 242 mImpl.startLocked(); 243 } else { 244 mImpl = null; 245 } 246 } 247 } 248 } 249 250 VoiceInteractionServiceInfo findAvailInteractor(int userHandle, ComponentName recognizer) { 251 List<ResolveInfo> available = 252 mContext.getPackageManager().queryIntentServicesAsUser( 253 new Intent(VoiceInteractionService.SERVICE_INTERFACE), 0, userHandle); 254 int numAvailable = available.size(); 255 256 if (numAvailable == 0) { 257 Slog.w(TAG, "no available voice interaction services found for user " + userHandle); 258 return null; 259 } else { 260 // Find first system package. We never want to allow third party services to 261 // be automatically selected, because those require approval of the user. 262 VoiceInteractionServiceInfo foundInfo = null; 263 for (int i=0; i<numAvailable; i++) { 264 ServiceInfo cur = available.get(i).serviceInfo; 265 if ((cur.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { 266 ComponentName comp = new ComponentName(cur.packageName, cur.name); 267 try { 268 VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo( 269 mContext.getPackageManager(), comp, userHandle); 270 if (info.getParseError() == null) { 271 if (recognizer == null || info.getServiceInfo().packageName.equals( 272 recognizer.getPackageName())) { 273 if (foundInfo == null) { 274 foundInfo = info; 275 } else { 276 Slog.w(TAG, "More than one voice interaction service, " 277 + "picking first " 278 + new ComponentName( 279 foundInfo.getServiceInfo().packageName, 280 foundInfo.getServiceInfo().name) 281 + " over " 282 + new ComponentName(cur.packageName, cur.name)); 283 } 284 } 285 } else { 286 Slog.w(TAG, "Bad interaction service " + comp + ": " 287 + info.getParseError()); 288 } 289 } catch (PackageManager.NameNotFoundException e) { 290 Slog.w(TAG, "Failure looking up interaction service " + comp); 291 } catch (RemoteException e) { 292 } 293 } 294 } 295 296 return foundInfo; 297 } 298 } 299 300 ComponentName getCurInteractor(int userHandle) { 301 String curInteractor = Settings.Secure.getStringForUser( 302 mContext.getContentResolver(), 303 Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle); 304 if (TextUtils.isEmpty(curInteractor)) { 305 return null; 306 } 307 if (DEBUG) Slog.i(TAG, "getCurInteractor curInteractor=" + curInteractor 308 + " user=" + userHandle); 309 return ComponentName.unflattenFromString(curInteractor); 310 } 311 312 void setCurInteractor(ComponentName comp, int userHandle) { 313 Settings.Secure.putStringForUser(mContext.getContentResolver(), 314 Settings.Secure.VOICE_INTERACTION_SERVICE, 315 comp != null ? comp.flattenToShortString() : "", userHandle); 316 if (DEBUG) Slog.i(TAG, "setCurInteractor comp=" + comp 317 + " user=" + userHandle); 318 } 319 320 ComponentName findAvailRecognizer(String prefPackage, int userHandle) { 321 List<ResolveInfo> available = 322 mContext.getPackageManager().queryIntentServicesAsUser( 323 new Intent(RecognitionService.SERVICE_INTERFACE), 0, userHandle); 324 int numAvailable = available.size(); 325 326 if (numAvailable == 0) { 327 Slog.w(TAG, "no available voice recognition services found for user " + userHandle); 328 return null; 329 } else { 330 if (prefPackage != null) { 331 for (int i=0; i<numAvailable; i++) { 332 ServiceInfo serviceInfo = available.get(i).serviceInfo; 333 if (prefPackage.equals(serviceInfo.packageName)) { 334 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 335 } 336 } 337 } 338 if (numAvailable > 1) { 339 Slog.w(TAG, "more than one voice recognition service found, picking first"); 340 } 341 342 ServiceInfo serviceInfo = available.get(0).serviceInfo; 343 return new ComponentName(serviceInfo.packageName, serviceInfo.name); 344 } 345 } 346 347 ComponentName getCurRecognizer(int userHandle) { 348 String curRecognizer = Settings.Secure.getStringForUser( 349 mContext.getContentResolver(), 350 Settings.Secure.VOICE_RECOGNITION_SERVICE, userHandle); 351 if (TextUtils.isEmpty(curRecognizer)) { 352 return null; 353 } 354 if (DEBUG) Slog.i(TAG, "getCurRecognizer curRecognizer=" + curRecognizer 355 + " user=" + userHandle); 356 return ComponentName.unflattenFromString(curRecognizer); 357 } 358 359 void setCurRecognizer(ComponentName comp, int userHandle) { 360 Settings.Secure.putStringForUser(mContext.getContentResolver(), 361 Settings.Secure.VOICE_RECOGNITION_SERVICE, 362 comp != null ? comp.flattenToShortString() : "", userHandle); 363 if (DEBUG) Slog.i(TAG, "setCurRecognizer comp=" + comp 364 + " user=" + userHandle); 365 } 366 367 @Override 368 public void startSession(IVoiceInteractionService service, Bundle args) { 369 synchronized (this) { 370 if (mImpl == null || mImpl.mService == null 371 || service.asBinder() != mImpl.mService.asBinder()) { 372 throw new SecurityException( 373 "Caller is not the current voice interaction service"); 374 } 375 final int callingPid = Binder.getCallingPid(); 376 final int callingUid = Binder.getCallingUid(); 377 final long caller = Binder.clearCallingIdentity(); 378 try { 379 mImpl.startSessionLocked(callingPid, callingUid, args); 380 } finally { 381 Binder.restoreCallingIdentity(caller); 382 } 383 } 384 } 385 386 @Override 387 public boolean deliverNewSession(IBinder token, IVoiceInteractionSession session, 388 IVoiceInteractor interactor) { 389 synchronized (this) { 390 if (mImpl == null) { 391 throw new SecurityException( 392 "deliverNewSession without running voice interaction service"); 393 } 394 final int callingPid = Binder.getCallingPid(); 395 final int callingUid = Binder.getCallingUid(); 396 final long caller = Binder.clearCallingIdentity(); 397 try { 398 return mImpl.deliverNewSessionLocked(callingPid, callingUid, token, session, 399 interactor); 400 } finally { 401 Binder.restoreCallingIdentity(caller); 402 } 403 } 404 } 405 406 @Override 407 public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) { 408 synchronized (this) { 409 if (mImpl == null) { 410 Slog.w(TAG, "startVoiceActivity without running voice interaction service"); 411 return ActivityManager.START_CANCELED; 412 } 413 final int callingPid = Binder.getCallingPid(); 414 final int callingUid = Binder.getCallingUid(); 415 final long caller = Binder.clearCallingIdentity(); 416 if (!SystemProperties.getBoolean("persist.test.voice_interaction", false)) { 417 throw new SecurityException("Voice interaction not supported"); 418 } 419 try { 420 return mImpl.startVoiceActivityLocked(callingPid, callingUid, token, 421 intent, resolvedType); 422 } finally { 423 Binder.restoreCallingIdentity(caller); 424 } 425 } 426 } 427 428 @Override 429 public void finish(IBinder token) { 430 synchronized (this) { 431 if (mImpl == null) { 432 Slog.w(TAG, "finish without running voice interaction service"); 433 return; 434 } 435 final int callingPid = Binder.getCallingPid(); 436 final int callingUid = Binder.getCallingUid(); 437 final long caller = Binder.clearCallingIdentity(); 438 try { 439 mImpl.finishLocked(callingPid, callingUid, token); 440 } finally { 441 Binder.restoreCallingIdentity(caller); 442 } 443 } 444 } 445 446 //----------------- Model management APIs --------------------------------// 447 448 @Override 449 public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 450 synchronized (this) { 451 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 452 != PackageManager.PERMISSION_GRANTED) { 453 throw new SecurityException("Caller does not hold the permission " 454 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 455 } 456 } 457 458 if (bcp47Locale == null) { 459 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); 460 } 461 462 final int callingUid = UserHandle.getCallingUserId(); 463 final long caller = Binder.clearCallingIdentity(); 464 try { 465 return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 466 } finally { 467 Binder.restoreCallingIdentity(caller); 468 } 469 } 470 471 @Override 472 public int updateKeyphraseSoundModel(KeyphraseSoundModel model) { 473 synchronized (this) { 474 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 475 != PackageManager.PERMISSION_GRANTED) { 476 throw new SecurityException("Caller does not hold the permission " 477 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 478 } 479 if (model == null) { 480 throw new IllegalArgumentException("Model must not be null"); 481 } 482 } 483 484 final long caller = Binder.clearCallingIdentity(); 485 try { 486 if (mDbHelper.updateKeyphraseSoundModel(model)) { 487 synchronized (this) { 488 // Notify the voice interaction service of a change in sound models. 489 if (mImpl != null && mImpl.mService != null) { 490 mImpl.notifySoundModelsChangedLocked(); 491 } 492 } 493 return SoundTriggerHelper.STATUS_OK; 494 } else { 495 return SoundTriggerHelper.STATUS_ERROR; 496 } 497 } finally { 498 Binder.restoreCallingIdentity(caller); 499 } 500 } 501 502 @Override 503 public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) { 504 synchronized (this) { 505 if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 506 != PackageManager.PERMISSION_GRANTED) { 507 throw new SecurityException("Caller does not hold the permission " 508 + Manifest.permission.MANAGE_VOICE_KEYPHRASES); 509 } 510 } 511 512 if (bcp47Locale == null) { 513 throw new IllegalArgumentException( 514 "Illegal argument(s) in deleteKeyphraseSoundModel"); 515 } 516 517 final int callingUid = UserHandle.getCallingUserId(); 518 final long caller = Binder.clearCallingIdentity(); 519 boolean deleted = false; 520 try { 521 deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 522 return deleted ? SoundTriggerHelper.STATUS_OK : SoundTriggerHelper.STATUS_ERROR; 523 } finally { 524 if (deleted) { 525 synchronized (this) { 526 // Notify the voice interaction service of a change in sound models. 527 if (mImpl != null && mImpl.mService != null) { 528 mImpl.notifySoundModelsChangedLocked(); 529 } 530 } 531 } 532 Binder.restoreCallingIdentity(caller); 533 } 534 } 535 536 //----------------- SoundTrigger APIs --------------------------------// 537 @Override 538 public boolean isEnrolledForKeyphrase(IVoiceInteractionService service, int keyphraseId, 539 String bcp47Locale) { 540 synchronized (this) { 541 if (mImpl == null || mImpl.mService == null 542 || service.asBinder() != mImpl.mService.asBinder()) { 543 throw new SecurityException( 544 "Caller is not the current voice interaction service"); 545 } 546 } 547 548 if (bcp47Locale == null) { 549 throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); 550 } 551 552 final int callingUid = UserHandle.getCallingUserId(); 553 final long caller = Binder.clearCallingIdentity(); 554 try { 555 KeyphraseSoundModel model = 556 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 557 return model != null; 558 } finally { 559 Binder.restoreCallingIdentity(caller); 560 } 561 } 562 563 @Override 564 public ModuleProperties getDspModuleProperties(IVoiceInteractionService service) { 565 // Allow the call if this is the current voice interaction service. 566 synchronized (this) { 567 if (mImpl == null || mImpl.mService == null 568 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 569 throw new SecurityException( 570 "Caller is not the current voice interaction service"); 571 } 572 573 final long caller = Binder.clearCallingIdentity(); 574 try { 575 return mSoundTriggerHelper.moduleProperties; 576 } finally { 577 Binder.restoreCallingIdentity(caller); 578 } 579 } 580 } 581 582 @Override 583 public int startRecognition(IVoiceInteractionService service, int keyphraseId, 584 String bcp47Locale, IRecognitionStatusCallback callback, 585 RecognitionConfig recognitionConfig) { 586 // Allow the call if this is the current voice interaction service. 587 synchronized (this) { 588 if (mImpl == null || mImpl.mService == null 589 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 590 throw new SecurityException( 591 "Caller is not the current voice interaction service"); 592 } 593 594 if (callback == null || recognitionConfig == null || bcp47Locale == null) { 595 throw new IllegalArgumentException("Illegal argument(s) in startRecognition"); 596 } 597 } 598 599 int callingUid = UserHandle.getCallingUserId(); 600 final long caller = Binder.clearCallingIdentity(); 601 try { 602 KeyphraseSoundModel soundModel = 603 mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); 604 if (soundModel == null 605 || soundModel.uuid == null 606 || soundModel.keyphrases == null) { 607 Slog.w(TAG, "No matching sound model found in startRecognition"); 608 return SoundTriggerHelper.STATUS_ERROR; 609 } else { 610 return mSoundTriggerHelper.startRecognition( 611 keyphraseId, soundModel, callback, recognitionConfig); 612 } 613 } finally { 614 Binder.restoreCallingIdentity(caller); 615 } 616 } 617 618 @Override 619 public int stopRecognition(IVoiceInteractionService service, int keyphraseId, 620 IRecognitionStatusCallback callback) { 621 // Allow the call if this is the current voice interaction service. 622 synchronized (this) { 623 if (mImpl == null || mImpl.mService == null 624 || service == null || service.asBinder() != mImpl.mService.asBinder()) { 625 throw new SecurityException( 626 "Caller is not the current voice interaction service"); 627 } 628 } 629 630 final long caller = Binder.clearCallingIdentity(); 631 try { 632 return mSoundTriggerHelper.stopRecognition(keyphraseId, callback); 633 } finally { 634 Binder.restoreCallingIdentity(caller); 635 } 636 } 637 638 @Override 639 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 640 if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP) 641 != PackageManager.PERMISSION_GRANTED) { 642 pw.println("Permission Denial: can't dump PowerManager from from pid=" 643 + Binder.getCallingPid() 644 + ", uid=" + Binder.getCallingUid()); 645 return; 646 } 647 synchronized (this) { 648 pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)\n"); 649 if (mImpl == null) { 650 pw.println(" (No active implementation)"); 651 return; 652 } 653 mImpl.dumpLocked(fd, pw, args); 654 } 655 mSoundTriggerHelper.dump(fd, pw, args); 656 } 657 658 class SettingsObserver extends ContentObserver { 659 SettingsObserver(Handler handler) { 660 super(handler); 661 ContentResolver resolver = mContext.getContentResolver(); 662 resolver.registerContentObserver(Settings.Secure.getUriFor( 663 Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); 664 } 665 666 @Override public void onChange(boolean selfChange) { 667 synchronized (VoiceInteractionManagerServiceStub.this) { 668 switchImplementationIfNeededLocked(false); 669 } 670 } 671 } 672 673 PackageMonitor mPackageMonitor = new PackageMonitor() { 674 @Override 675 public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { 676 return super.onHandleForceStop(intent, packages, uid, doit); 677 } 678 679 @Override 680 public void onHandleUserStop(Intent intent, int userHandle) { 681 } 682 683 @Override 684 public void onSomePackagesChanged() { 685 int userHandle = getChangingUserId(); 686 if (DEBUG) Slog.i(TAG, "onSomePackagesChanged user=" + userHandle); 687 688 ComponentName curInteractor = getCurInteractor(userHandle); 689 ComponentName curRecognizer = getCurRecognizer(userHandle); 690 if (curRecognizer == null) { 691 // Could a new recognizer appear when we don't have one pre-installed? 692 if (anyPackagesAppearing()) { 693 curRecognizer = findAvailRecognizer(null, userHandle); 694 if (curRecognizer != null) { 695 setCurRecognizer(curRecognizer, userHandle); 696 } 697 } 698 return; 699 } 700 701 if (curInteractor != null) { 702 int change = isPackageDisappearing(curInteractor.getPackageName()); 703 if (change == PACKAGE_PERMANENT_CHANGE) { 704 // The currently set interactor is permanently gone; fall back to 705 // the default config. 706 setCurInteractor(null, userHandle); 707 setCurRecognizer(null, userHandle); 708 initForUser(userHandle); 709 return; 710 } 711 712 change = isPackageAppearing(curInteractor.getPackageName()); 713 if (change != PACKAGE_UNCHANGED) { 714 // If current interactor is now appearing, for any reason, then 715 // restart our connection with it. 716 if (mImpl != null && curInteractor.getPackageName().equals( 717 mImpl.mComponent.getPackageName())) { 718 switchImplementationIfNeededLocked(true); 719 } 720 } 721 return; 722 } 723 724 // There is no interactor, so just deal with a simple recognizer. 725 int change = isPackageDisappearing(curRecognizer.getPackageName()); 726 if (change == PACKAGE_PERMANENT_CHANGE 727 || change == PACKAGE_TEMPORARY_CHANGE) { 728 setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); 729 730 } else if (isPackageModified(curRecognizer.getPackageName())) { 731 setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), 732 userHandle), userHandle); 733 } 734 } 735 }; 736 } 737} 738