1 /* 2 * Copyright (C) 2022 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 android.voiceinteraction.cts.services; 18 19 import static android.voiceinteraction.cts.testcore.Helper.KEYPHRASE_LOCALE; 20 import static android.voiceinteraction.cts.testcore.Helper.KEYPHRASE_TEXT; 21 import static android.voiceinteraction.cts.testcore.Helper.WAIT_TIMEOUT_IN_MS; 22 23 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; 24 import android.media.voice.KeyphraseModelManager; 25 import android.os.Bundle; 26 import android.os.Looper; 27 import android.os.PersistableBundle; 28 import android.service.voice.AlwaysOnHotwordDetector; 29 import android.service.voice.HotwordDetector; 30 import android.service.voice.HotwordRejectedResult; 31 import android.service.voice.VisualQueryDetectedResult; 32 import android.service.voice.VisualQueryDetectionServiceFailure; 33 import android.service.voice.VisualQueryDetector; 34 import android.service.voice.VoiceInteractionService; 35 import android.util.Log; 36 import android.voiceinteraction.common.Utils; 37 import android.voiceinteraction.cts.testcore.Helper; 38 39 import androidx.annotation.NonNull; 40 import androidx.annotation.Nullable; 41 42 import java.io.File; 43 import java.io.FileOutputStream; 44 import java.util.concurrent.CountDownLatch; 45 import java.util.concurrent.Executor; 46 import java.util.concurrent.Executors; 47 import java.util.concurrent.TimeUnit; 48 49 /** 50 * The base {@link VoiceInteractionService} that provides the common methods for subclass. 51 */ 52 public abstract class BaseVoiceInteractionService extends VoiceInteractionService { 53 54 private final String mTag = getClass().getSimpleName(); 55 public static final int STATUS_NO_CALLBACK_CALLED = -100; 56 57 // The service instance 58 public static VoiceInteractionService sService; 59 // The CountDownLatch waits for service connect 60 public static CountDownLatch sConnectLatch; 61 public static CountDownLatch sDisconnectLatch; 62 63 // The CountDownLatch waits for onPrepareToShowSession 64 public static CountDownLatch sPrepareToShowSessionLatch; 65 // The CountDownLatch waits for onShowSessionFailed 66 public static CountDownLatch sShowSessionFailedLatch; 67 68 // The CountDownLatch waits for a service init result 69 // TODO: rename to mHotwordDetectionServiceInitializedLatch, keep this name until the 70 // refactor done. The original tests use trigger in many places. To make the mapping asier, 71 // keep the current name now. 72 public CountDownLatch mDetectorInitializedLatch = null; 73 74 VisualQueryDetector mVisualQueryDetector = null; 75 HotwordDetector mSoftwareHotwordDetector = null; 76 // The AlwaysOnHotwordDetector created by createAlwaysOnHotwordDetector() API 77 AlwaysOnHotwordDetector mAlwaysOnHotwordDetector = null; 78 // Throws IllegalStateException when calling createAlwaysOnHotwordDetector() API 79 private boolean mIsCreateDetectorIllegalStateExceptionThrow = false; 80 // Whether the callback of the detector is running on main thread or not 81 private boolean mIsDetectorCallbackRunningOnMainThread = false; 82 // Throws SecurityException when calling createAlwaysOnHotwordDetector() API 83 private boolean mIsCreateDetectorSecurityExceptionThrow = false; 84 private Bundle mPrepareToShowSessionArgs = new Bundle(); 85 private Bundle mShowSessionFailedArgs = new Bundle(); 86 private int mPrepareToShowSessionFlags = -1; 87 // the status of onHotwordDetectionServiceInitialized() 88 int mInitializedStatus = STATUS_NO_CALLBACK_CALLED; 89 90 int mAvailabilityStatus = STATUS_NO_CALLBACK_CALLED; 91 92 93 final HotwordDetector.Callback mNoOpSoftwareDetectorCallback = new HotwordDetector.Callback() { 94 @Override 95 public void onDetected(AlwaysOnHotwordDetector.EventPayload eventPayload) { 96 // no-op 97 } 98 99 @Override 100 public void onError() { 101 // no-op 102 } 103 104 @Override 105 public void onRecognitionPaused() { 106 // no-op 107 } 108 109 @Override 110 public void onRecognitionResumed() { 111 // no-op 112 } 113 114 @Override 115 public void onRejected(HotwordRejectedResult result) { 116 // no-op 117 } 118 119 @Override 120 public void onHotwordDetectionServiceInitialized(int status) { 121 // no-op 122 } 123 124 @Override 125 public void onHotwordDetectionServiceRestarted() { 126 // no-op 127 } 128 }; 129 130 // An AlwaysOnHotwordDetector.Callback no nothing on callback methods 131 final AlwaysOnHotwordDetector.Callback mNoOpHotwordDetectorCallback = 132 new AlwaysOnHotwordDetector.Callback() { 133 @Override 134 public void onAvailabilityChanged(int status) { 135 // no-op 136 } 137 138 @Override 139 public void onDetected(AlwaysOnHotwordDetector.EventPayload eventPayload) { 140 // no-op 141 } 142 143 @Override 144 public void onRejected(@NonNull HotwordRejectedResult result) { 145 // no-op 146 } 147 148 @Override 149 public void onError() { 150 // no-op 151 } 152 153 @Override 154 public void onRecognitionPaused() { 155 // no-op 156 } 157 158 @Override 159 public void onRecognitionResumed() { 160 // no-op 161 } 162 163 @Override 164 public void onHotwordDetectionServiceInitialized(int status) { 165 Log.i(mTag, "onHotwordDetectionServiceInitialized status = " + status); 166 } 167 168 @Override 169 public void onHotwordDetectionServiceRestarted() { 170 // no-op 171 } 172 }; 173 174 // A VisualQueryDetector.Callback no nothing on callback methods 175 final VisualQueryDetector.Callback mNoOpVisualQueryDetectorCallback = 176 new VisualQueryDetector.Callback() { 177 @Override 178 public void onQueryDetected(@NonNull String partialQuery) { 179 //No-op 180 } 181 182 @Override 183 public void onQueryDetected(@NonNull VisualQueryDetectedResult partialResult) { 184 //No-op 185 } 186 187 @Override 188 public void onQueryRejected() { 189 //No-op 190 } 191 192 @Override 193 public void onQueryFinished() { 194 //No-op 195 } 196 197 @Override 198 public void onVisualQueryDetectionServiceInitialized(int status) { 199 Log.i(mTag, "onVisualQueryDetectionServiceInitialized status = " + status); 200 } 201 202 @Override 203 public void onVisualQueryDetectionServiceRestarted() { 204 //No-op 205 } 206 207 @Override 208 public void onFailure( 209 VisualQueryDetectionServiceFailure visualQueryDetectionServiceFailure) { 210 //No-op 211 } 212 213 @Override 214 public void onUnknownFailure(String errorMessage) { 215 //No-op 216 } 217 }; 218 219 220 @Override onReady()221 public void onReady() { 222 super.onReady(); 223 Log.d(mTag, "onReady()"); 224 sService = this; 225 if (sConnectLatch != null) { 226 sConnectLatch.countDown(); 227 } 228 } 229 230 @Override onShutdown()231 public void onShutdown() { 232 super.onShutdown(); 233 Log.d(mTag, "onShutdown()"); 234 if (sDisconnectLatch != null) { 235 sDisconnectLatch.countDown(); 236 } 237 } 238 239 @Override onPrepareToShowSession(Bundle args, int flags)240 public void onPrepareToShowSession(Bundle args, int flags) { 241 Log.d(mTag, "onPrepareToShowSession args = " + args + ", flags =" + flags); 242 if (sPrepareToShowSessionLatch != null) { 243 sPrepareToShowSessionLatch.countDown(); 244 } 245 mPrepareToShowSessionArgs = args; 246 mPrepareToShowSessionFlags = flags; 247 } 248 249 @Override onShowSessionFailed(Bundle args)250 public void onShowSessionFailed(Bundle args) { 251 Log.d(mTag, "onShowSessionFailed args = " + args); 252 if (sShowSessionFailedLatch != null) { 253 sShowSessionFailedLatch.countDown(); 254 } 255 mShowSessionFailedArgs = args; 256 } 257 258 /** 259 * Clear the non-static state of this class 260 */ resetState()261 public void resetState() { 262 mDetectorInitializedLatch = null; 263 mVisualQueryDetector = null; 264 mSoftwareHotwordDetector = null; 265 mAlwaysOnHotwordDetector = null; 266 mIsCreateDetectorIllegalStateExceptionThrow = false; 267 mIsDetectorCallbackRunningOnMainThread = false; 268 mIsCreateDetectorSecurityExceptionThrow = false; 269 mPrepareToShowSessionArgs = new Bundle(); 270 mShowSessionFailedArgs = new Bundle(); 271 mPrepareToShowSessionFlags = -1; 272 mInitializedStatus = STATUS_NO_CALLBACK_CALLED; 273 mAvailabilityStatus = STATUS_NO_CALLBACK_CALLED; 274 } 275 276 /** 277 * Reset the static variables of this service. 278 */ resetStaticValues()279 public static void resetStaticValues() { 280 sService = null; 281 sConnectLatch = null; 282 sDisconnectLatch = null; 283 sPrepareToShowSessionLatch = null; 284 sShowSessionFailedLatch = null; 285 } 286 287 /** 288 * Init the CountDownLatch that is used to wait for service onReady() and onShutdown(). 289 */ initServiceConnectionLatches()290 public static void initServiceConnectionLatches() { 291 sConnectLatch = new CountDownLatch(1); 292 sDisconnectLatch = new CountDownLatch(1); 293 } 294 295 /** 296 * Init the CountDownLatch that is used to wait for onPrepareToShowSession and 297 * onShowSessionFailed 298 */ initShowSessionLatch()299 public static void initShowSessionLatch() { 300 sPrepareToShowSessionLatch = new CountDownLatch(1); 301 sShowSessionFailedLatch = new CountDownLatch(1); 302 } 303 304 /** 305 * Wait for service onReady(). 306 */ waitServiceConnect()307 public static void waitServiceConnect() throws InterruptedException { 308 if (sConnectLatch == null) { 309 throw new AssertionError("Should init connect CountDownLatch"); 310 } 311 if (!sConnectLatch.await(WAIT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS)) { 312 throw new AssertionError("VoiceInteractionService doesn't start."); 313 } 314 sConnectLatch = null; 315 } 316 317 /** 318 * Wait for service onShutdown(). 319 */ waitServiceDisconnect()320 public static void waitServiceDisconnect() throws InterruptedException { 321 if (sDisconnectLatch == null) { 322 throw new AssertionError("Should init disconnect CountDownLatch"); 323 } 324 if (!sDisconnectLatch.await(WAIT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS)) { 325 throw new AssertionError("VoiceInteractionService doesn't shut down."); 326 } 327 sDisconnectLatch = null; 328 } 329 330 /** 331 * Wait for onPrepareToShowSession 332 */ waitOnPrepareToShowSession()333 public static void waitOnPrepareToShowSession() throws InterruptedException { 334 if (sPrepareToShowSessionLatch == null) { 335 throw new AssertionError("Should init prepareToShowSession CountDownLatch"); 336 } 337 if (!sPrepareToShowSessionLatch.await(WAIT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS)) { 338 throw new AssertionError("onPrepareToShowSession has not been triggered"); 339 } 340 sPrepareToShowSessionLatch = null; 341 } 342 343 /** 344 * Wait for onShowSessionFailed 345 */ waitOnShowSessionFailed()346 public static void waitOnShowSessionFailed() throws InterruptedException { 347 if (sShowSessionFailedLatch == null) { 348 throw new AssertionError("Should init showSessionFailed CountDownLatch"); 349 } 350 if (!sShowSessionFailedLatch.await(WAIT_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS)) { 351 throw new AssertionError("onShowSessionFailed has not been triggered"); 352 } 353 sShowSessionFailedLatch = null; 354 } 355 356 /** 357 * Returns {@link VoiceInteractionService} for testing 358 */ getService()359 public static VoiceInteractionService getService() { 360 return sService; 361 } 362 363 /** 364 * Returns if the {@link VoiceInteractionService} is running on the main thread 365 */ isRunningOnMainThread()366 static boolean isRunningOnMainThread() { 367 return Looper.getMainLooper().getThread() == Thread.currentThread(); 368 } 369 370 /** 371 * Returns the {@link Executor} of the detector callback 372 */ getDetectorCallbackExecutor()373 public static Executor getDetectorCallbackExecutor() { 374 return Executors.newSingleThreadExecutor(); 375 } 376 377 /** 378 * Returns if createAlwaysOnHotwordDetector throws IllegalStateException. 379 */ isCreateDetectorIllegalStateExceptionThrow()380 public boolean isCreateDetectorIllegalStateExceptionThrow() { 381 Log.d(mTag, "isCreateDetectorIllegalStateExceptionThrow = " 382 + mIsCreateDetectorIllegalStateExceptionThrow); 383 return mIsCreateDetectorIllegalStateExceptionThrow; 384 } 385 386 /** 387 * Returns if createAlwaysOnHotwordDetector throws SecurityException. 388 */ isCreateDetectorSecurityExceptionThrow()389 public boolean isCreateDetectorSecurityExceptionThrow() { 390 Log.d(mTag, "isCreateDetectorSecurityExceptionThrow = " 391 + mIsCreateDetectorSecurityExceptionThrow); 392 return mIsCreateDetectorSecurityExceptionThrow; 393 } 394 395 /** 396 * Returns if the callback of the detector is running on main thread 397 */ isDetectorCallbackRunningOnMainThread()398 public boolean isDetectorCallbackRunningOnMainThread() { 399 Log.d(mTag, "isDetectorCallbackRunningOnMainThread = " 400 + mIsDetectorCallbackRunningOnMainThread); 401 return mIsDetectorCallbackRunningOnMainThread; 402 } 403 404 /** 405 * Set the value to mIsDetectorCallbackRunningOnMainThread 406 */ setIsDetectorCallbackRunningOnMainThread( boolean isDetectorCallbackRunningOnMainThread)407 public void setIsDetectorCallbackRunningOnMainThread( 408 boolean isDetectorCallbackRunningOnMainThread) { 409 mIsDetectorCallbackRunningOnMainThread = isDetectorCallbackRunningOnMainThread; 410 } 411 412 /** 413 * Returns the Service's AlwaysOnHotwordDetector. 414 */ getAlwaysOnHotwordDetector()415 public AlwaysOnHotwordDetector getAlwaysOnHotwordDetector() { 416 return mAlwaysOnHotwordDetector; 417 } 418 419 /** 420 * Returns the Service's SoftwareHotwordDetector. 421 */ getSoftwareHotwordDetector()422 public HotwordDetector getSoftwareHotwordDetector() { 423 return mSoftwareHotwordDetector; 424 } 425 426 /** 427 * Returns the Service's VisualQueryDetector. 428 */ getVisualQueryDetector()429 public VisualQueryDetector getVisualQueryDetector() { 430 return mVisualQueryDetector; 431 } 432 433 /** 434 * Wait for createAlwaysOnHotwordDetectorNoHotwordDetectionService be ready 435 */ waitCreateAlwaysOnHotwordDetectorNoHotwordDetectionServiceReady()436 public void waitCreateAlwaysOnHotwordDetectorNoHotwordDetectionServiceReady() 437 throws InterruptedException { 438 Log.d(mTag, "waitCreateAlwaysOnHotwordDetectorNoHotwordDetectionServiceReady(), latch=" 439 + mDetectorInitializedLatch); 440 if (mDetectorInitializedLatch == null 441 || !mDetectorInitializedLatch.await(WAIT_TIMEOUT_IN_MS, 442 TimeUnit.MILLISECONDS)) { 443 Log.w(mTag, "waitCreateAlwaysOnHotwordDetectorNoHotwordDetectionServiceReady()"); 444 mDetectorInitializedLatch = null; 445 throw new AssertionError( 446 "CreateAlwaysOnHotwordDetectorNoHotwordDetectionService is not ready"); 447 } 448 mDetectorInitializedLatch = null; 449 } 450 451 /** 452 * Wait for onSandboxedDetectionServiceInitialized() be called or exception throws when creating 453 * AlwaysOnHotwordDetector or VisualQueryDetector. 454 */ waitSandboxedDetectionServiceInitializedCalledOrException()455 public void waitSandboxedDetectionServiceInitializedCalledOrException() 456 throws InterruptedException { 457 Log.d(mTag, "waitSandboxedDetectionServiceInitializedCalledOrException(), latch=" 458 + mDetectorInitializedLatch); 459 if (mDetectorInitializedLatch == null 460 || !mDetectorInitializedLatch.await(WAIT_TIMEOUT_IN_MS, 461 TimeUnit.MILLISECONDS)) { 462 Log.w(mTag, "waitAndGetSandboxedServiceInitializedResult()"); 463 mDetectorInitializedLatch = null; 464 throw new AssertionError("Sandboxed detection service initialized fail."); 465 } 466 mDetectorInitializedLatch = null; 467 } 468 resetDetectorCreationExceptions()469 private void resetDetectorCreationExceptions() { 470 mIsCreateDetectorIllegalStateExceptionThrow = false; 471 mIsCreateDetectorSecurityExceptionThrow = false; 472 } 473 474 /** 475 * Return the args from onPrepareToShowSession. 476 */ 477 @NonNull getPrepareToShowSessionArgs()478 public Bundle getPrepareToShowSessionArgs() { 479 Log.d(mTag, "getPrepareToShowSessionArgs = " + mPrepareToShowSessionArgs); 480 return mPrepareToShowSessionArgs; 481 } 482 483 /** 484 * Return the flags from onPrepareToShowSession. 485 */ getPrepareToShowSessionFlags()486 public int getPrepareToShowSessionFlags() { 487 Log.d(mTag, "getPrepareToShowSessionFlags = " + mPrepareToShowSessionFlags); 488 return mPrepareToShowSessionFlags; 489 } 490 491 /** 492 * Return the args from onShowSessionFailed. 493 */ 494 @NonNull getShowSessionFailedArgs()495 public Bundle getShowSessionFailedArgs() { 496 Log.d(mTag, "getShowSessionFailedArgs = " + mShowSessionFailedArgs); 497 return mShowSessionFailedArgs; 498 } 499 500 /** 501 * Return the result for onHotwordDetectionServiceInitialized(). 502 */ getSandboxedDetectionServiceInitializedResult()503 public int getSandboxedDetectionServiceInitializedResult() { 504 Log.d(mTag, "getSandboxedDetectionServiceInitializedResult = " + mInitializedStatus); 505 return mInitializedStatus; 506 } 507 508 509 /** 510 * Enable override the model enrollment database one which has a specific mode registered. 511 * Need to have "android.permission.MANAGE_VOICE_KEYPHRASES" permission. 512 * 513 * @see #disableOverrideRegisterModel() 514 */ enableOverrideRegisterModel(KeyphraseSoundModel model)515 public void enableOverrideRegisterModel(KeyphraseSoundModel model) { 516 final KeyphraseModelManager manager = createKeyphraseModelManager(); 517 manager.setModelDatabaseForTestEnabled(/* enabled= */ true); 518 manager.updateKeyphraseSoundModel(model); 519 } 520 521 /** 522 * Disable model override started in 523 * {@link #enableOverrideRegisterModel(KeyphraseSoundModel)} 524 */ disableOverrideRegisterModel()525 public void disableOverrideRegisterModel() { 526 createKeyphraseModelManager().setModelDatabaseForTestEnabled(/* enabled= */ false); 527 } 528 529 /** 530 * Creates a file in the internal storage to test the file read method 531 * {@link android.service.voice.VisualQueryDetectionService#openFileInput(String)}. 532 * @throws Throwable throws exceptions when writing to the file via output stream. 533 */ createTestFile(String suffix)534 public void createTestFile(String suffix) throws Throwable { 535 File path = this.getFilesDir(); 536 File file = new File(path, Utils.TEST_RESOURCE_FILE_NAME + suffix); 537 try (FileOutputStream stream = new FileOutputStream(file)) { 538 stream.write(Utils.TEST_RESOURCE_FILE_CONTENT.getBytes()); 539 } 540 } 541 542 /** 543 * Remove all files in the internal storage that is created by 544 * {@link BaseVoiceInteractionService#createTestFile(String)}. 545 */ removeTestFiles()546 public void removeTestFiles() { 547 File path = this.getFilesDir(); 548 File[] files = path.listFiles(); 549 if (files != null) { 550 for (File file : files) { 551 // Check if the filename starts with the specified prefix 552 if (file.getName().startsWith(Utils.TEST_RESOURCE_FILE_NAME)) { 553 file.delete(); // Delete the file 554 } 555 } 556 } 557 } 558 callCreateAlwaysOnHotwordDetectorNoHotwordDetectionService( AlwaysOnHotwordDetector.Callback callback, boolean useExecutor)559 AlwaysOnHotwordDetector callCreateAlwaysOnHotwordDetectorNoHotwordDetectionService( 560 AlwaysOnHotwordDetector.Callback callback, boolean useExecutor) { 561 Log.i(mTag, 562 "callCreateAlwaysOnHotwordDetectorNoHotwordDetectionService() useExecutor = " 563 + useExecutor); 564 try { 565 setTestModuleForAlwaysOnHotwordDetectorEnabled(true); 566 resetDetectorCreationExceptions(); 567 if (useExecutor) { 568 return createAlwaysOnHotwordDetector(KEYPHRASE_TEXT, 569 KEYPHRASE_LOCALE, 570 getDetectorCallbackExecutor(), 571 callback); 572 } 573 return createAlwaysOnHotwordDetector(KEYPHRASE_TEXT, KEYPHRASE_LOCALE, callback); 574 } catch (IllegalStateException | SecurityException e) { 575 if (e instanceof IllegalStateException) { 576 mIsCreateDetectorIllegalStateExceptionThrow = true; 577 } else { 578 mIsCreateDetectorSecurityExceptionThrow = true; 579 } 580 Log.w(mTag, "callCreateAlwaysOnHotwordDetector() exception: ", e); 581 if (mDetectorInitializedLatch != null) { 582 mDetectorInitializedLatch.countDown(); 583 } 584 } finally { 585 setTestModuleForAlwaysOnHotwordDetectorEnabled(false); 586 } 587 return null; 588 } 589 callCreateAlwaysOnHotwordDetector( AlwaysOnHotwordDetector.Callback callback)590 AlwaysOnHotwordDetector callCreateAlwaysOnHotwordDetector( 591 AlwaysOnHotwordDetector.Callback callback) { 592 return callCreateAlwaysOnHotwordDetector(callback, /* useExecutor= */ false); 593 } 594 callCreateAlwaysOnHotwordDetector( AlwaysOnHotwordDetector.Callback callback, boolean useExecutor)595 AlwaysOnHotwordDetector callCreateAlwaysOnHotwordDetector( 596 AlwaysOnHotwordDetector.Callback callback, boolean useExecutor) { 597 return callCreateAlwaysOnHotwordDetector(callback, useExecutor, /* options= */ null); 598 } 599 callCreateAlwaysOnHotwordDetector( AlwaysOnHotwordDetector.Callback callback, boolean useExecutor, @Nullable PersistableBundle options)600 AlwaysOnHotwordDetector callCreateAlwaysOnHotwordDetector( 601 AlwaysOnHotwordDetector.Callback callback, boolean useExecutor, 602 @Nullable PersistableBundle options) { 603 Log.i(mTag, 604 "callCreateAlwaysOnHotwordDetector() useExecutor = " + useExecutor + ", options = " 605 + options); 606 try { 607 setTestModuleForAlwaysOnHotwordDetectorEnabled(true); 608 resetDetectorCreationExceptions(); 609 if (useExecutor) { 610 return createAlwaysOnHotwordDetector(KEYPHRASE_TEXT, 611 KEYPHRASE_LOCALE, 612 options != null ? options : Helper.createFakePersistableBundleData(), 613 Helper.createFakeSharedMemoryData(), 614 getDetectorCallbackExecutor(), 615 callback); 616 } 617 return createAlwaysOnHotwordDetector(KEYPHRASE_TEXT, 618 KEYPHRASE_LOCALE, 619 options != null ? options : Helper.createFakePersistableBundleData(), 620 Helper.createFakeSharedMemoryData(), 621 callback); 622 } catch (IllegalStateException | SecurityException e) { 623 if (e instanceof IllegalStateException) { 624 mIsCreateDetectorIllegalStateExceptionThrow = true; 625 } else { 626 mIsCreateDetectorSecurityExceptionThrow = true; 627 } 628 Log.w(mTag, "callCreateAlwaysOnHotwordDetector() exception: ", e); 629 if (mDetectorInitializedLatch != null) { 630 mDetectorInitializedLatch.countDown(); 631 } 632 } finally { 633 setTestModuleForAlwaysOnHotwordDetectorEnabled(false); 634 } 635 return null; 636 } 637 callCreateSoftwareHotwordDetector(HotwordDetector.Callback callback, boolean useExecutor)638 HotwordDetector callCreateSoftwareHotwordDetector(HotwordDetector.Callback callback, 639 boolean useExecutor) { 640 return callCreateSoftwareHotwordDetector(callback, useExecutor, /* options= */ null); 641 } 642 callCreateSoftwareHotwordDetector(HotwordDetector.Callback callback, boolean useExecutor, @Nullable PersistableBundle options)643 HotwordDetector callCreateSoftwareHotwordDetector(HotwordDetector.Callback callback, 644 boolean useExecutor, @Nullable PersistableBundle options) { 645 Log.i(mTag, 646 "callCreateSoftwareHotwordDetector() useExecutor = " + useExecutor + ", options = " 647 + options); 648 try { 649 resetDetectorCreationExceptions(); 650 if (useExecutor) { 651 return createHotwordDetector( 652 options != null ? options : Helper.createFakePersistableBundleData(), 653 Helper.createFakeSharedMemoryData(), getDetectorCallbackExecutor(), 654 callback); 655 } 656 return createHotwordDetector( 657 options != null ? options : Helper.createFakePersistableBundleData(), 658 Helper.createFakeSharedMemoryData(), callback); 659 } catch (IllegalStateException | SecurityException e) { 660 if (e instanceof IllegalStateException) { 661 mIsCreateDetectorIllegalStateExceptionThrow = true; 662 } else { 663 mIsCreateDetectorSecurityExceptionThrow = true; 664 } 665 Log.w(mTag, "callCreateSoftwareHotwordDetector() exception: " + e); 666 if (mDetectorInitializedLatch != null) { 667 mDetectorInitializedLatch.countDown(); 668 } 669 } 670 return null; 671 } 672 callCreateVisualQueryDetector(VisualQueryDetector.Callback callback)673 VisualQueryDetector callCreateVisualQueryDetector(VisualQueryDetector.Callback callback) { 674 Log.i(mTag, "callCreateVisualQueryDetector()"); 675 try { 676 resetDetectorCreationExceptions(); 677 return createVisualQueryDetector(Helper.createFakePersistableBundleData(), 678 Helper.createFakeSharedMemoryData(), Executors.newSingleThreadExecutor(), 679 callback); 680 } catch (IllegalStateException | SecurityException e) { 681 if (e instanceof IllegalStateException) { 682 mIsCreateDetectorIllegalStateExceptionThrow = true; 683 } else { 684 mIsCreateDetectorSecurityExceptionThrow = true; 685 } 686 Log.w(mTag, "callCreateVisualQueryDetector() exception: " + e); 687 if (mDetectorInitializedLatch != null) { 688 mDetectorInitializedLatch.countDown(); 689 } 690 } 691 return null; 692 } 693 } 694