Add tests for VoiceInteractionService role change
Bug: 170742278
Test: atest VoiceInteractionRoleTest
Change-Id: Ica5f3c533c662017ed39703ff37f8ae65c749084
diff --git a/tests/tests/voiceinteraction/AndroidTest.xml b/tests/tests/voiceinteraction/AndroidTest.xml
index 68501e2..69ae2a9 100644
--- a/tests/tests/voiceinteraction/AndroidTest.xml
+++ b/tests/tests/voiceinteraction/AndroidTest.xml
@@ -27,6 +27,7 @@
<option name="force-install-mode" value="FULL"/>
<option name="cleanup-apks" value="true"/>
<option name="test-file-name" value="CtsVoiceInteractionService.apk"/>
+ <option name="test-file-name" value="CtsNoRecognitionVoiceInteractionService.apk"/>
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/voiceinteraction/service/Android.bp b/tests/tests/voiceinteraction/service/Android.bp
index 4aee259..f90a5b4 100644
--- a/tests/tests/voiceinteraction/service/Android.bp
+++ b/tests/tests/voiceinteraction/service/Android.bp
@@ -32,3 +32,18 @@
],
sdk_version: "test_current",
}
+
+// A test service that doesn't define RecognitionService
+android_test_helper_app {
+ name: "CtsNoRecognitionVoiceInteractionService",
+ defaults: ["cts_support_defaults"],
+ srcs: ["noRecognitionVoiceInteractionService/**/*.java"],
+ resource_dirs: ["noRecognitionVoiceInteractionService/res"],
+ manifest: "noRecognitionVoiceInteractionService/AndroidManifest.xml",
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+ sdk_version: "test_current",
+}
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/service/AndroidManifest.xml b/tests/tests/voiceinteraction/service/AndroidManifest.xml
index e47d30b..087a833 100644
--- a/tests/tests/voiceinteraction/service/AndroidManifest.xml
+++ b/tests/tests/voiceinteraction/service/AndroidManifest.xml
@@ -18,8 +18,18 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.voiceinteraction.service">
- <application>
+ <application android:label="Voice service">
<uses-library android:name="android.test.runner" />
+ <service android:name="android.voiceinteraction.service.NoOpVoiceInteractionService"
+ android:label="NoOpVoiceInteractionService has recognition"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:exported="true">
+ <meta-data android:name="android.voice_interaction"
+ android:resource="@xml/has_recognition_interaction_service" />
+ <intent-filter>
+ <action android:name="android.service.voice.VoiceInteractionService" />
+ </intent-filter>
+ </service>
<service android:name=".MainInteractionService"
android:label="CTS test voice interaction service"
android:permission="android.permission.BIND_VOICE_INTERACTION"
diff --git a/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/AndroidManifest.xml b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/AndroidManifest.xml
new file mode 100644
index 0000000..44cd725
--- /dev/null
+++ b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2021 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.voiceinteraction.norecognition">
+
+ <application android:label="no recognition service">
+ <uses-library android:name="android.test.runner"/>
+ <service android:name="android.voiceinteraction.norecognition.NoOpVoiceInteractionService"
+ android:label="NoOpVoiceInteractionService no recognition"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:process=":interactor"
+ android:exported="true">
+ <meta-data android:name="android.voice_interaction"
+ android:resource="@xml/interaction_no_recognition_service"/>
+ <intent-filter>
+ <action android:name="android.service.voice.VoiceInteractionService"/>
+ </intent-filter>
+ </service>
+ <activity android:name="android.voiceinteraction.norecognition.NoOpActivity"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.ASSIST"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/res/xml/interaction_no_recognition_service.xml b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/res/xml/interaction_no_recognition_service.xml
new file mode 100644
index 0000000..260062a
--- /dev/null
+++ b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/res/xml/interaction_no_recognition_service.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:sessionService="android.voiceinteraction.service.MainInteractionSessionService"
+ android:supportsAssist="true"
+ android:supportsLocalInteraction="true"/>
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/src/android/voiceinteraction/norecognition/NoOpActivity.java b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/src/android/voiceinteraction/norecognition/NoOpActivity.java
new file mode 100644
index 0000000..0790c16
--- /dev/null
+++ b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/src/android/voiceinteraction/norecognition/NoOpActivity.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 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.norecognition;
+
+import android.app.Activity;
+
+/**
+ * A Activity that received android.intent.action.ASSIST but do nothing for testing.
+ */
+public final class NoOpActivity extends Activity {
+}
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/src/android/voiceinteraction/norecognition/NoOpVoiceInteractionService.java b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/src/android/voiceinteraction/norecognition/NoOpVoiceInteractionService.java
new file mode 100644
index 0000000..93ac526
--- /dev/null
+++ b/tests/tests/voiceinteraction/service/noRecognitionVoiceInteractionService/src/android/voiceinteraction/norecognition/NoOpVoiceInteractionService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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.norecognition;
+
+import android.service.voice.VoiceInteractionService;
+
+/**
+ * A {@link VoiceInteractionService} without implementation that is used for role changing testing.
+ */
+public class NoOpVoiceInteractionService extends VoiceInteractionService {
+ // do nothing
+}
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/service/res/xml/has_recognition_interaction_service.xml b/tests/tests/voiceinteraction/service/res/xml/has_recognition_interaction_service.xml
new file mode 100644
index 0000000..5957aeb
--- /dev/null
+++ b/tests/tests/voiceinteraction/service/res/xml/has_recognition_interaction_service.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:sessionService="android.voiceinteraction.service.MainInteractionSessionService"
+ android:recognitionService="android.voiceinteraction.service.MainRecognitionService"
+ android:settingsActivity="android.voiceinteraction.service.SettingsActivity"
+ android:supportsAssist="true"/>
diff --git a/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/NoOpVoiceInteractionService.java b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/NoOpVoiceInteractionService.java
new file mode 100644
index 0000000..8e23102
--- /dev/null
+++ b/tests/tests/voiceinteraction/service/src/android/voiceinteraction/service/NoOpVoiceInteractionService.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 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.common;
+
+import android.service.voice.VoiceInteractionService;
+
+/**
+ * A {@link VoiceInteractionService} without implementation that is used for role changing testing.
+ */
+public class NoOpVoiceInteractionService extends VoiceInteractionService {
+ // do nothing
+}
\ No newline at end of file
diff --git a/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionRoleTest.java b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionRoleTest.java
new file mode 100644
index 0000000..192e97f
--- /dev/null
+++ b/tests/tests/voiceinteraction/src/android/voiceinteraction/cts/VoiceInteractionRoleTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 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.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Tests for successfully changing ROLE_ASSISTANT. The test focuses on changing ROLE_ASSISTANT role,
+ * the target voice interaction services do nothing during the test.
+ */
+@AppModeFull(reason = "No need for testing role for instant app")
+@RunWith(AndroidJUnit4.class)
+public class VoiceInteractionRoleTest {
+
+ private static final String TAG = "VoiceInteractionRoleTest";
+
+ private static final long TIMEOUT_MILLIS = 15 * 1000;
+ private static final String VOICE_INTERACTION_HAS_RECOGNITION_SERVICE =
+ "android.voiceinteraction.service";
+ private static final String VOICE_INTERACTION_NO_RECOGNITION_SERVICE =
+ "android.voiceinteraction.norecognition";
+
+ private static Context sContext;
+ private static RoleManager sRoleManager;
+
+ List<String> mOriginalRoleHolders;
+
+ @BeforeClass
+ public static void oneTimeSetup() {
+ sContext = ApplicationProvider.getApplicationContext();
+ sRoleManager = sContext.getSystemService(RoleManager.class);
+ }
+
+ @Before
+ public void setup() throws Exception {
+ mOriginalRoleHolders = getAssistRoleHolders();
+ }
+
+ @After
+ public void cleanup() throws Exception {
+ if (mOriginalRoleHolders != null && mOriginalRoleHolders.size() > 0) {
+ // Restore to original, assistant is singleton role
+ addAssistRoleHolder(mOriginalRoleHolders.get(0));
+ }
+ }
+
+ @Test
+ public void testAssistRole_hasRecognitionService() throws Exception {
+ roleTestingForPackage(VOICE_INTERACTION_HAS_RECOGNITION_SERVICE, /* hasRecognition= */
+ true);
+ }
+
+ @Test
+ public void testAssistRole_noRecognitionService() throws Exception {
+ roleTestingForPackage(VOICE_INTERACTION_NO_RECOGNITION_SERVICE, /* hasRecognition= */
+ false);
+ }
+
+ // TODO: Use helpers and move the assertion in Test instead of move together
+ private void roleTestingForPackage(String packageName, boolean hasRecognition)
+ throws Exception {
+ assertThat(getAssistRoleHolders()).doesNotContain(packageName);
+
+ addAssistRoleHolder(packageName);
+ if (mOriginalRoleHolders != null && mOriginalRoleHolders.size() > 0) {
+ String originalHolder = mOriginalRoleHolders.get(0);
+ removeAssistRoleHolder(originalHolder);
+ assertThat(getAssistRoleHolders()).doesNotContain(originalHolder);
+ }
+ assertThat(getAssistRoleHolders()).containsExactly(packageName);
+
+ final String curVoiceInteractionComponentName = Settings.Secure.getString(
+ sContext.getContentResolver(),
+ Settings.Secure.VOICE_INTERACTION_SERVICE);
+ String curVoiceInteractionPackageName = "";
+ if (!TextUtils.isEmpty(curVoiceInteractionComponentName)) {
+ curVoiceInteractionPackageName =
+ ComponentName.unflattenFromString(
+ curVoiceInteractionComponentName).getPackageName();
+ }
+ assertThat(curVoiceInteractionPackageName).isEqualTo(hasRecognition ? packageName : "");
+
+ removeAssistRoleHolder(packageName);
+ assertThat(getAssistRoleHolders()).doesNotContain(packageName);
+ }
+
+ private List<String> getAssistRoleHolders() throws Exception {
+ return callWithShellPermissionIdentity(
+ () -> sRoleManager.getRoleHolders(RoleManager.ROLE_ASSISTANT));
+ }
+
+ private void addAssistRoleHolder(String packageName)
+ throws Exception {
+ Log.i(TAG, "addAssistRoleHolder for " + packageName);
+ final CallbackFuture future = new CallbackFuture("addAssistRoleHolder");
+ runWithShellPermissionIdentity(() -> {
+ sRoleManager.addRoleHolderAsUser(RoleManager.ROLE_ASSISTANT, packageName,
+ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, Process.myUserHandle(),
+ sContext.getMainExecutor(), future);
+ });
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ }
+
+ private void removeAssistRoleHolder(String packageName)
+ throws Exception {
+ Log.i(TAG, "removeAssistRoleHolder for " + packageName);
+ final CallbackFuture future = new CallbackFuture("removeAssistRoleHolder");
+ runWithShellPermissionIdentity(
+ () -> sRoleManager.removeRoleHolderAsUser(RoleManager.ROLE_ASSISTANT, packageName,
+ 0, Process.myUserHandle(), sContext.getMainExecutor(), future));
+ assertThat(future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ }
+
+ private static class CallbackFuture extends CompletableFuture<Boolean>
+ implements Consumer<Boolean> {
+ String mMethodName;
+
+ CallbackFuture(String methodName) {
+ mMethodName = methodName;
+ }
+
+ @Override
+ public void accept(Boolean successful) {
+ Log.i(TAG, mMethodName + " result " + successful);
+ complete(successful);
+ }
+ }
+}