Adding tests for assistant stack.
Bug: 30999386
Test: android.server.cts.ActivityManagerAssistantStackTests
Change-Id: Ife68f9029ef7cfc8565f1b4ed9e205236f3caded
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index a37be98..49384e2 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -21,8 +21,8 @@
<!-- virtual display test permissions -->
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
-
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
<application>
<activity android:name=".TestActivity"
@@ -283,6 +283,29 @@
<action android:name="android.server.cts.LAUNCH_BROADCAST_ACTION"/>
</intent-filter>
</receiver>
+
+ <activity android:name=".AssistantActivity"
+ android:exported="true" />
+ <activity android:name=".LaunchAssistantActivityFromSession"
+ android:taskAffinity="nobody.but.LaunchAssistantActivityFromSession"
+ android:exported="true" />
+ <activity android:name=".LaunchAssistantActivityIntoAssistantStack"
+ android:taskAffinity="nobody.but.LaunchAssistantActivityIntoAssistantStack"
+ android:exported="true" />
+
+ <service android:name=".AssistantVoiceInteractionService"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:exported="true">
+ <meta-data android:name="android.voice_interaction"
+ android:resource="@xml/interaction_service" />
+ <intent-filter>
+ <action android:name="android.service.voice.VoiceInteractionService" />
+ </intent-filter>
+ </service>
+
+ <service android:name=".AssistantVoiceInteractionSessionService"
+ android:permission="android.permission.BIND_VOICE_INTERACTION"
+ android:exported="true" />
</application>
</manifest>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/xml/interaction_service.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/xml/interaction_service.xml
new file mode 100644
index 0000000..7cf92a0
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/xml/interaction_service.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.server.cts.AssistantVoiceInteractionSessionService"
+ android:recognitionService="android.server.cts.AssistantVoiceInteractionSessionService"
+ android:supportsAssist="true" />
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantActivity.java
new file mode 100644
index 0000000..e15f6d0
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantActivity.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.server.cts;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class AssistantActivity extends Activity {
+
+ // Launches the given activity in onResume
+ public static final String EXTRA_LAUNCH_NEW_TASK = "launch_new_task";
+ // Finishes this activity in onResume, this happens after EXTRA_LAUNCH_NEW_TASK
+ public static final String EXTRA_FINISH_SELF = "finish_self";
+ // Attempts to enter picture-in-picture in onResume
+ public static final String EXTRA_ENTER_PIP = "enter_pip";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Launch the new activity if requested
+ if (getIntent().hasExtra(EXTRA_LAUNCH_NEW_TASK)) {
+ Intent i = new Intent();
+ i.setComponent(new ComponentName(this, getPackageName() + "."
+ + getIntent().getStringExtra(EXTRA_LAUNCH_NEW_TASK)));
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(i);
+ }
+
+ // Enter pip if requested
+ if (getIntent().hasExtra(EXTRA_ENTER_PIP)) {
+ try {
+ enterPictureInPictureMode();
+ } catch (IllegalStateException e) {
+ finish();
+ return;
+ }
+ }
+
+ // Finish this activity if requested
+ if (getIntent().hasExtra(EXTRA_FINISH_SELF)) {
+ finish();
+ }
+ }
+
+ /**
+ * Launches a new instance of the AssistantActivity directly into the assistant stack.
+ */
+ static void launchActivityIntoAssistantStack(Activity caller, Bundle extras) {
+ final Intent intent = new Intent(caller, AssistantActivity.class);
+ intent.setFlags(FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK);
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchStackId(6 /* ActivityManager.StackId.ASSISTANT_STACK_ID */);
+ caller.startActivity(intent, options.toBundle());
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantVoiceInteractionService.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantVoiceInteractionService.java
new file mode 100644
index 0000000..51c2348
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantVoiceInteractionService.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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.server.cts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionService;
+import android.util.Log;
+
+public class AssistantVoiceInteractionService extends VoiceInteractionService {
+
+ private static final String TAG = AssistantVoiceInteractionService.class.getSimpleName();
+
+ private boolean mReady;
+
+ @Override
+ public void onReady() {
+ super.onReady();
+ mReady = true;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (!isActiveService(this, new ComponentName(this, getClass()))) {
+ Log.wtf(TAG, "**** Not starting AssistantVoiceInteractionService because" +
+ " it is not set as the current voice interaction service");
+ stopSelf();
+ return START_NOT_STICKY;
+ }
+ if (mReady) {
+ Bundle extras = intent.getExtras() != null ? intent.getExtras() : new Bundle();
+ showSession(extras, 0);
+ }
+ return START_NOT_STICKY;
+ }
+
+ /**
+ * Starts the assistant voice interaction service, which initiates a new session that starts
+ * the assistant activity.
+ */
+ public static void launchAssistantActivity(Context context, Bundle extras) {
+ Intent i = new Intent(context, AssistantVoiceInteractionService.class);
+ if (extras != null) {
+ i.putExtras(extras);
+ }
+ context.startService(i);
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantVoiceInteractionSessionService.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantVoiceInteractionSessionService.java
new file mode 100644
index 0000000..e711ac4
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AssistantVoiceInteractionSessionService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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.server.cts;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.service.voice.VoiceInteractionSessionService;
+
+public class AssistantVoiceInteractionSessionService extends VoiceInteractionSessionService {
+
+ @Override
+ public VoiceInteractionSession onNewSession(Bundle args) {
+ return new VoiceInteractionSession(this) {
+ @Override
+ public void onPrepareShow(Bundle args, int showFlags) {
+ setUiEnabled(false);
+ }
+
+ @Override
+ public void onShow(Bundle args, int showFlags) {
+ Intent i = new Intent(AssistantVoiceInteractionSessionService.this,
+ AssistantActivity.class);
+ if (args != null) {
+ i.putExtras(args);
+ }
+ startAssistantActivity(i);
+ }
+ };
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchAssistantActivityFromSession.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchAssistantActivityFromSession.java
new file mode 100644
index 0000000..2d562ff
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchAssistantActivityFromSession.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.server.cts;
+
+import android.app.Activity;
+
+public class LaunchAssistantActivityFromSession extends Activity {
+ @Override
+ protected void onResume() {
+ super.onResume();
+ AssistantVoiceInteractionService.launchAssistantActivity(this, getIntent().getExtras());
+ finishAndRemoveTask();
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchAssistantActivityIntoAssistantStack.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchAssistantActivityIntoAssistantStack.java
new file mode 100644
index 0000000..af610be
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchAssistantActivityIntoAssistantStack.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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.server.cts;
+
+import android.app.Activity;
+
+public class LaunchAssistantActivityIntoAssistantStack extends Activity {
+ @Override
+ protected void onResume() {
+ super.onResume();
+ AssistantActivity.launchActivityIntoAssistantStack(this, getIntent().getExtras());
+ finishAndRemoveTask();
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
index e9b57ff..defcf4e 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -57,7 +57,7 @@
private static final String EXTRA_ENTER_PIP_ON_PAUSE = "enter_pip_on_pause";
// Starts the activity (component name) provided by the value at the end of onCreate
private static final String EXTRA_START_ACTIVITY = "start_activity";
- // Finishes the activity at the end of onCreate (after EXTRA_START_ACTIVITY is handled)
+ // Finishes the activity at the end of onResume (after EXTRA_START_ACTIVITY is handled)
private static final String EXTRA_FINISH_SELF_ON_RESUME = "finish_self_on_resume";
// Calls enterPictureInPicture() again after onPictureInPictureModeChanged(false) is called
private static final String EXTRA_REENTER_PIP_ON_EXIT = "reenter_pip_on_exit";
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
index dc633f2..eb08861 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
@@ -16,6 +16,10 @@
package android.server.cts;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -26,6 +30,18 @@
// Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
+ // Finishes the activity
+ private static final String ACTION_FINISH_SELF = "android.server.cts.TestActivity.finish_self";
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && intent.getAction().equals(ACTION_FINISH_SELF)) {
+ finish();
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -40,10 +56,17 @@
@Override
protected void onResume() {
super.onResume();
+ registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
dumpDisplaySize(getResources().getConfiguration());
}
@Override
+ protected void onPause() {
+ super.onPause();
+ unregisterReceiver(mReceiver);
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
dumpDisplaySize(newConfig);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java
new file mode 100644
index 0000000..ae94603
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAssistantStackTests.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2017 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.server.cts;
+
+import static android.server.cts.ActivityManagerState.STATE_RESUMED;
+import static android.server.cts.ActivityManagerState.STATE_STOPPED;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerAssistantStackTests
+ */
+public class ActivityManagerAssistantStackTests extends ActivityManagerTestBase {
+
+ private static final String VOICE_INTERACTION_SERVICE = "AssistantVoiceInteractionService";
+
+ private static final String TEST_ACTIVITY = "TestActivity";
+ private static final String DOCKED_ACTIVITY = "DockedActivity";
+ private static final String ASSISTANT_ACTIVITY = "AssistantActivity";
+ private static final String LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION =
+ "LaunchAssistantActivityFromSession";
+ private static final String LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK =
+ "LaunchAssistantActivityIntoAssistantStack";
+ private static final String PIP_ACTIVITY = "PipActivity";
+
+ private static final String EXTRA_ENTER_PIP = "enter_pip";
+ private static final String EXTRA_LAUNCH_NEW_TASK = "launch_new_task";
+ private static final String EXTRA_FINISH_SELF = "finish_self";
+
+ private static final String TEST_ACTIVITY_ACTION_FINISH_SELF =
+ "android.server.cts.TestActivity.finish_self";
+
+ public void testLaunchingAssistantActivityIntoAssistantStack() throws Exception {
+ // Enable the assistant and launch an assistant activity
+ enableAssistant();
+ launchActivity(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION);
+ mAmWmState.waitForValidState(mDevice, ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+
+ // Ensure that the activity launched in the fullscreen assistant stack
+ assertAssistantStackExists();
+ assertTrue("Expected assistant stack to be fullscreen",
+ mAmWmState.getAmState().getStackById(ASSISTANT_STACK_ID).isFullscreen());
+
+ disableAssistant();
+ }
+
+ public void testAssistantStackZOrder() throws Exception {
+ // Launch a pinned stack task
+ launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+ mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, PINNED_STACK_ID);
+ mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
+
+ // Dock a task
+ launchActivity(TEST_ACTIVITY);
+ launchActivityInDockStack(DOCKED_ACTIVITY);
+ mAmWmState.assertContainsStack("Must contain fullscreen stack.",
+ FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+
+ // Enable the assistant and launch an assistant activity, ensure it is on top
+ enableAssistant();
+ launchActivity(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION);
+ mAmWmState.waitForValidState(mDevice, ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+ assertAssistantStackExists();
+
+ mAmWmState.assertFrontStack("Pinned stack should be on top.", PINNED_STACK_ID);
+ mAmWmState.assertFocusedStack("Assistant stack should be focused.", ASSISTANT_STACK_ID);
+
+ disableAssistant();
+ }
+
+ public void testAssistantStackLaunchNewTask() throws Exception {
+ enableAssistant();
+ assertAssistantStackCanLaunchAndReturnFromNewTask();
+ disableAssistant();
+ }
+
+ public void testAssistantStackLaunchNewTaskWithDockedStack() throws Exception {
+ // Dock a task
+ launchActivity(TEST_ACTIVITY);
+ launchActivityInDockStack(DOCKED_ACTIVITY);
+ mAmWmState.assertContainsStack("Must contain fullscreen stack.",
+ FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+
+ enableAssistant();
+ assertAssistantStackCanLaunchAndReturnFromNewTask();
+ disableAssistant();
+ }
+
+ private void assertAssistantStackCanLaunchAndReturnFromNewTask() throws Exception {
+ // Enable the assistant and launch an assistant activity which will launch a new task
+ enableAssistant();
+ launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
+ EXTRA_LAUNCH_NEW_TASK, TEST_ACTIVITY);
+ disableAssistant();
+
+ // Ensure that the fullscreen stack is on top and the test activity is now visible
+ mAmWmState.waitForValidState(mDevice, TEST_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY);
+ mAmWmState.assertFrontStack("Fullscreen stack should be on top.",
+ FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertFocusedStack("Fullscreen stack should be focused.",
+ FULLSCREEN_WORKSPACE_STACK_ID);
+
+ // Now, tell it to finish itself and ensure that the assistant stack is brought back forward
+ executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH_SELF);
+ mAmWmState.waitForFocusedStack(mDevice, ASSISTANT_STACK_ID);
+ mAmWmState.assertFrontStack("Assistant stack should be on top.", ASSISTANT_STACK_ID);
+ mAmWmState.assertFocusedStack("Assistant stack should be focused.", ASSISTANT_STACK_ID);
+ }
+
+ public void testAssistantStackFinishToPreviousApp() throws Exception {
+ // Launch an assistant activity on top of an existing fullscreen activity, and ensure that
+ // the fullscreen activity is still visible and on top after the assistant activity finishes
+ launchActivity(TEST_ACTIVITY);
+ enableAssistant();
+ launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
+ EXTRA_FINISH_SELF, "true");
+ disableAssistant();
+ mAmWmState.waitForValidState(mDevice, TEST_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY, STATE_RESUMED);
+ mAmWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY);
+ mAmWmState.assertFrontStack("Fullscreen stack should be on top.",
+ FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.assertFocusedStack("Fullscreen stack should be focused.",
+ FULLSCREEN_WORKSPACE_STACK_ID);
+ }
+
+ public void testDisallowEnterPiPFromAssistantStack() throws Exception {
+ enableAssistant();
+ launchActivity(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK,
+ EXTRA_ENTER_PIP, "true");
+ disableAssistant();
+ mAmWmState.waitForValidState(mDevice, ASSISTANT_ACTIVITY, ASSISTANT_STACK_ID);
+ mAmWmState.assertDoesNotContainStack("Must not contain pinned stack.", PINNED_STACK_ID);
+ }
+
+ /**
+ * Asserts that the assistant stack exists.
+ */
+ private void assertAssistantStackExists() throws Exception {
+ mAmWmState.assertContainsStack("Must contain assistant stack.", ASSISTANT_STACK_ID);
+ }
+
+ /**
+ * Asserts that the assistant stack does not exist.
+ */
+ private void assertAssistantStackDoesNotExist() throws Exception {
+ mAmWmState.assertDoesNotContainStack("Must not contain assistant stack.",
+ ASSISTANT_STACK_ID);
+ }
+
+ /**
+ * Sets the system voice interaction service.
+ */
+ private void enableAssistant() throws Exception {
+ executeShellCommand("settings put secure voice_interaction_service " +
+ getActivityComponentName(VOICE_INTERACTION_SERVICE));
+ }
+
+ /**
+ * Resets the system voice interaction service.
+ */
+ private void disableAssistant() throws Exception {
+ executeShellCommand("settings delete secure voice_interaction_service " +
+ getActivityComponentName(VOICE_INTERACTION_SERVICE));
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 298b030..d2ee551 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -63,13 +63,19 @@
/** ID of stack that always on top (always visible) when it exist. */
public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
+ /** Recents activity stack ID. */
+ public static final int RECENTS_STACK_ID = PINNED_STACK_ID + 1;
+
+ /** Assistant activity stack ID. This stack is fullscreen and non-resizeable. */
+ public static final int ASSISTANT_STACK_ID = RECENTS_STACK_ID + 1;
+
protected static final int[] ALL_STACK_IDS_BUT_HOME = {
FULLSCREEN_WORKSPACE_STACK_ID, FREEFORM_WORKSPACE_STACK_ID, DOCKED_STACK_ID,
- PINNED_STACK_ID
+ PINNED_STACK_ID, ASSISTANT_STACK_ID
};
protected static final int[] ALL_STACK_IDS_BUT_HOME_AND_FULLSCREEN = {
- FREEFORM_WORKSPACE_STACK_ID, DOCKED_STACK_ID, PINNED_STACK_ID
+ FREEFORM_WORKSPACE_STACK_ID, DOCKED_STACK_ID, PINNED_STACK_ID, ASSISTANT_STACK_ID
};
private static final String TASK_ID_PREFIX = "taskId";