blob: 8e171353334012a76de75d098bf396c894e76547 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.voiceinteraction.cts;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import android.content.ComponentName;
import android.content.Intent;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.media.AudioFormat;
import android.os.ConditionVariable;
import android.platform.test.annotations.AppModeFull;
import android.provider.Settings;
import android.util.Log;
import android.voiceinteraction.common.Utils;
import android.voiceinteraction.service.IProxyAlwaysOnHotwordDetector;
import android.voiceinteraction.service.IProxyDetectorCallback;
import android.voiceinteraction.service.ITestVoiceInteractionService;
import android.voiceinteraction.service.ITestVoiceInteractionServiceListener;
import android.voiceinteraction.service.IVoiceInteractionServiceBindingHelper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ServiceTestRule;
import com.android.compatibility.common.util.SettingsStateChangerRule;
import com.android.compatibility.common.util.UserSettings;
import com.google.common.collect.ImmutableList;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import java.util.Locale;
@RunWith(AndroidJUnit4.class)
@AppModeFull(reason = "No real use case for instant mode hotword detector")
public class VoiceInteractionMultiDetectorTest {
private static final String TAG = VoiceInteractionMultiDetectorTest.class.getSimpleName();
private static final Duration TEST_SERVICE_TIMEOUT = Duration.ofSeconds(3);
@Rule
public final SettingsStateChangerRule mServiceSetterRule = new SettingsStateChangerRule(
InstrumentationRegistry.getInstrumentation().getTargetContext(),
Settings.Secure.VOICE_INTERACTION_SERVICE,
Utils.PROXY_VOICEINTERACTION_SERVICE_COMPONENT);
private final ConditionVariable mIsTestServiceReady = new ConditionVariable();
private final ConditionVariable mIsTestServiceShutdown = new ConditionVariable();
@Rule
public ServiceTestRule mServiceTestRule = new ServiceTestRule();
private ITestVoiceInteractionService mTestServiceInterface = null;
private final UserSettings mUserSettings = new UserSettings();
@Before
public void setUp() throws Exception {
Intent serviceIntent = new Intent();
serviceIntent.setAction(Utils.ACTION_BIND_TEST_VOICE_INTERACTION);
serviceIntent.setComponent(
new ComponentName(Utils.TEST_VOICE_INTERACTION_SERVICE_PACKAGE_NAME,
Utils.VOICE_INTERACTION_SERVICE_BINDING_HELPER_CLASS_NAME));
IVoiceInteractionServiceBindingHelper voiceInteractionServiceBindingHelper =
IVoiceInteractionServiceBindingHelper.Stub.asInterface(
mServiceTestRule.bindService(serviceIntent)
);
mTestServiceInterface = voiceInteractionServiceBindingHelper.getVoiceInteractionService();
mTestServiceInterface.registerListener(new ITestVoiceInteractionServiceListener.Stub() {
@Override
public void onReady() {
Log.i(TAG, "ITestVoiceInteractionServiceListener: onReady");
mIsTestServiceReady.open();
mIsTestServiceShutdown.close();
}
@Override
public void onShutdown() {
Log.i(TAG, "ITestVoiceInteractionServiceListener: onShutdown");
mIsTestServiceReady.close();
mIsTestServiceShutdown.open();
}
});
assertThat(mIsTestServiceReady.block(TEST_SERVICE_TIMEOUT.toMillis())).isTrue();
}
@After
public void tearDown() throws Exception {
Log.i(TAG, "tearDown: clearing settings value");
mUserSettings.syncSet(Settings.Secure.VOICE_INTERACTION_SERVICE, "dummy_service");
Log.i(TAG, "tearDown: waiting for shutdown");
assertThat(mIsTestServiceShutdown.block(TEST_SERVICE_TIMEOUT.toMillis())).isTrue();
mServiceTestRule.unbindService();
mIsTestServiceReady.close();
mIsTestServiceShutdown.close();
}
@Test
@Ignore("b/274789133 - ProxyVIService instrumentation issue")
public void testAlwaysOnHotwordDetectorDestroy_throwsExceptionAfterDestroy() throws Exception {
final ConditionVariable availabilityChanged = new ConditionVariable();
IProxyAlwaysOnHotwordDetector alwaysOnHotwordDetector =
mTestServiceInterface.createAlwaysOnHotwordDetector("test keyphrase",
Locale.ENGLISH.toLanguageTag(),
new IProxyDetectorCallback.Stub() {
@Override
public void onAvailabilityChanged(int status) {
availabilityChanged.open();
}
});
assertThat(availabilityChanged.block(TEST_SERVICE_TIMEOUT.toMillis())).isTrue();
alwaysOnHotwordDetector.startRecognitionOnFakeAudioStream();
alwaysOnHotwordDetector.destroy();
assertThrows(IllegalStateException.class,
() -> alwaysOnHotwordDetector.startRecognitionOnFakeAudioStream());
assertThrows(IllegalStateException.class, () -> alwaysOnHotwordDetector.stopRecognition());
assertThrows(IllegalStateException.class,
() -> alwaysOnHotwordDetector.updateState(null, null));
assertThrows(IllegalStateException.class, () ->
alwaysOnHotwordDetector.triggerHardwareRecognitionEventForTest(/* status */ 0,
/* soundModelHandle */ 100, /* halEventReceivedMillis */ 12345,
/* captureAvailable */ true, /* captureSession */ 101,
/* captureDelayMs */ 1000, /* capturePreambleMs */ 1001,
/* triggerInData */ true,
new AudioFormat.Builder()
.setSampleRate(32000)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_IN_MONO).build(),
new byte[1024],
ImmutableList.of(
new KeyphraseRecognitionExtra(10,
SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER,
100))));
}
@Test
@Ignore("b/274789133 - ProxyVIService instrumentation issue")
public void testAlwaysOnHotwordDetectorCreate_rejectMultipleDetectorsOfTheSameType()
throws Exception {
final ConditionVariable availabilityChanged = new ConditionVariable();
IProxyAlwaysOnHotwordDetector alwaysOnHotwordDetectorEnglish =
mTestServiceInterface.createAlwaysOnHotwordDetector("test keyphrase",
Locale.ENGLISH.toLanguageTag(),
new IProxyDetectorCallback.Stub() {
@Override
public void onAvailabilityChanged(int status) {
availabilityChanged.open();
}
});
assertThat(alwaysOnHotwordDetectorEnglish).isNotNull();
assertThat(availabilityChanged.block(TEST_SERVICE_TIMEOUT.toMillis())).isTrue();
availabilityChanged.close();
assertThrows(IllegalStateException.class,
() -> mTestServiceInterface.createAlwaysOnHotwordDetector("test keyphrase",
Locale.ENGLISH.toLanguageTag(),
new IProxyDetectorCallback.Stub() {
@Override
public void onAvailabilityChanged(int status) {
availabilityChanged.open();
}
}));
alwaysOnHotwordDetectorEnglish.destroy();
}
}