From 9407076fb95551732421e7bc79cc4967402aef8c Mon Sep 17 00:00:00 2001 From: Atneya Nair Date: Fri, 31 Mar 2023 12:23:57 -0700 Subject: [PATCH] Add TestAPI for VIService to create AOHD for test Add test API which configures subsequent AlwaysOnHotwordDetector creation methods in VoiceInteractionService to use the underlying test ST module. Fixes: 276478654 Test: atest CtsVoiceInteractionTestCases Change-Id: I234199d5c874ff3145ef468cd40be3a07999f09e --- core/api/test-current.txt | 1 + .../voice/VoiceInteractionService.java | 54 +++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 2dfda517b4958..87835974b5d6d 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2944,6 +2944,7 @@ package android.service.voice { method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorForTest(@NonNull String, @NonNull java.util.Locale, @NonNull android.hardware.soundtrigger.SoundTrigger.ModuleProperties, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetectorForTest(@NonNull String, @NonNull java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.hardware.soundtrigger.SoundTrigger.ModuleProperties, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.AlwaysOnHotwordDetector.Callback); method @NonNull public final java.util.List listModuleProperties(); + method public final void setTestModuleForAlwaysOnHotwordDetectorEnabled(boolean); } public static class VoiceInteractionSession.ActivityId { diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index fcc64b088def1..68cce4ae274a4 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -50,6 +50,7 @@ import android.provider.Settings; import android.util.ArraySet; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceActionCheckCallback; import com.android.internal.app.IVoiceInteractionManagerService; @@ -200,6 +201,9 @@ public class VoiceInteractionService extends Service { private final Set mActiveDetectors = new ArraySet<>(); + // True if any of the createAOHD methods should use the test ST module. + @GuardedBy("mLock") + private boolean mTestModuleForAlwaysOnHotwordDetectorEnabled = false; private void onDetectorRemoteException(@NonNull IBinder token, int detectorType) { Log.d(TAG, "onDetectorRemoteException for " + HotwordDetector.detectorTypeToString( @@ -512,14 +516,14 @@ public class VoiceInteractionService extends Service { Objects.requireNonNull(callback); return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, /* supportHotwordDetectionService= */ false, /* options= */ null, - /* sharedMemory= */ null, /* moduleProperties */ null, executor, callback); + /* sharedMemory= */ null, /* moduleProperties= */ null, executor, callback); } /** * Same as {@link createAlwaysOnHotwordDetector(String, Locale, Executor, * AlwaysOnHotwordDetector.Callback)}, but allow explicit selection of the underlying ST * module to attach to. - * Use {@link listModuleProperties} to get available modules to attach to. + * Use {@link #listModuleProperties()} to get available modules to attach to. * @hide */ @TestApi @@ -645,14 +649,14 @@ public class VoiceInteractionService extends Service { Objects.requireNonNull(callback); return createAlwaysOnHotwordDetectorInternal(keyphrase, locale, /* supportHotwordDetectionService= */ true, options, sharedMemory, - /* moduleProperties */ null, executor, callback); + /* moduleProperties= */ null, executor, callback); } /** * Same as {@link createAlwaysOnHotwordDetector(String, Locale, * PersistableBundle, SharedMemory, Executor, AlwaysOnHotwordDetector.Callback)}, * but allow explicit selection of the underlying ST module to attach to. - * Use {@link listModuleProperties} to get available modules to attach to. + * Use {@link #listModuleProperties()} to get available modules to attach to. * @hide */ @TestApi @@ -717,6 +721,10 @@ public class VoiceInteractionService extends Service { try { dspDetector.registerOnDestroyListener(this::onHotwordDetectorDestroyed); + // Check if we are currently overridden, and should use the test module. + if (mTestModuleForAlwaysOnHotwordDetectorEnabled) { + moduleProperties = getTestModuleProperties(); + } // If moduleProperties is null, the default STModule is used. dspDetector.initialize(options, sharedMemory, moduleProperties); } catch (Exception e) { @@ -990,6 +998,44 @@ public class VoiceInteractionService extends Service { return mKeyphraseEnrollmentInfo; } + + /** + * Configure {@link createAlwaysOnHotwordDetector(String, Locale, + * SoundTrigger.ModuleProperties, Executor, AlwaysOnHotwordDetector.Callback)} + * and similar overloads to utilize the test SoundTrigger module instead of the + * actual DSP module. + * @param isEnabled - {@code true} if subsequently created {@link AlwaysOnHotwordDetector} + * objects should attach to a test module. {@code false} if subsequently created + * {@link AlwaysOnHotwordDetector} should attach to the actual DSP module. + * @hide + */ + @TestApi + public final void setTestModuleForAlwaysOnHotwordDetectorEnabled(boolean isEnabled) { + synchronized (mLock) { + mTestModuleForAlwaysOnHotwordDetectorEnabled = isEnabled; + } + } + + /** + * Get the {@link SoundTrigger.ModuleProperties} representing the fake + * STHAL to attach to via {@link createAlwaysOnHotwordDetector(String, Locale, + * SoundTrigger.ModuleProperties, Executor, AlwaysOnHotwordDetector.Callback)} and + * similar overloads for test purposes. + * @return ModuleProperties to use for test purposes. + */ + private final @NonNull SoundTrigger.ModuleProperties getTestModuleProperties() { + var moduleProps = listModuleProperties() + .stream() + .filter((SoundTrigger.ModuleProperties prop) + -> prop.getSupportedModelArch().equals(SoundTrigger.FAKE_HAL_ARCH)) + .findFirst() + .orElse(null); + if (moduleProps == null) { + throw new IllegalStateException("Fake ST HAL should always be available"); + } + return moduleProps; + } + /** * Checks if a given keyphrase and locale are supported to create an * {@link AlwaysOnHotwordDetector}.