1 /* 2 * Copyright (C) 2017 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.server.wm; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 24 import static android.server.wm.CliIntentExtra.extraString; 25 import static android.server.wm.ComponentNameUtils.getActivityName; 26 import static android.server.wm.UiDeviceUtils.pressHomeButton; 27 import static android.server.wm.WindowManagerState.STATE_RESUMED; 28 import static android.server.wm.app.Components.ANIMATION_TEST_ACTIVITY; 29 import static android.server.wm.app.Components.ASSISTANT_ACTIVITY; 30 import static android.server.wm.app.Components.ASSISTANT_VOICE_INTERACTION_SERVICE; 31 import static android.server.wm.app.Components.AssistantActivity.EXTRA_ASSISTANT_DISPLAY_ID; 32 import static android.server.wm.app.Components.AssistantActivity.EXTRA_ASSISTANT_ENTER_PIP; 33 import static android.server.wm.app.Components.AssistantActivity.EXTRA_ASSISTANT_FINISH_SELF; 34 import static android.server.wm.app.Components.AssistantActivity.EXTRA_ASSISTANT_LAUNCH_NEW_TASK; 35 import static android.server.wm.app.Components.DOCKED_ACTIVITY; 36 import static android.server.wm.app.Components.LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION; 37 import static android.server.wm.app.Components.LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK; 38 import static android.server.wm.app.Components.LaunchAssistantActivityIntoAssistantStack.EXTRA_ASSISTANT_IS_TRANSLUCENT; 39 import static android.server.wm.app.Components.PIP_ACTIVITY; 40 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP; 41 import static android.server.wm.app.Components.TEST_ACTIVITY; 42 import static android.server.wm.app.Components.TRANSLUCENT_ASSISTANT_ACTIVITY; 43 import static android.server.wm.app.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF; 44 import static android.view.Display.DEFAULT_DISPLAY; 45 46 import static org.hamcrest.Matchers.hasSize; 47 import static org.junit.Assert.assertEquals; 48 import static org.junit.Assert.assertThat; 49 import static org.junit.Assert.assertTrue; 50 import static org.junit.Assume.assumeTrue; 51 52 import android.content.ComponentName; 53 import android.platform.test.annotations.Presubmit; 54 import android.provider.Settings; 55 import android.server.wm.settings.SettingsSession; 56 57 import org.junit.Ignore; 58 import org.junit.Test; 59 60 /** 61 * Build/Install/Run: 62 * atest CtsWindowManagerDeviceTestCases:AssistantStackTests 63 */ 64 @Presubmit 65 public class AssistantStackTests extends ActivityManagerTestBase { 66 67 private int mAssistantDisplayId = DEFAULT_DISPLAY; 68 setUp()69 public void setUp() throws Exception { 70 super.setUp(); 71 try (final AssistantSession assistantSession = new AssistantSession()) { 72 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 73 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK); 74 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 75 WindowManagerState.Task assistantStack = 76 mWmState.getRootTaskByActivityType(ACTIVITY_TYPE_ASSISTANT); 77 mAssistantDisplayId = assistantStack.mDisplayId; 78 } 79 } 80 81 @Test testLaunchingAssistantActivityIntoAssistantStack()82 public void testLaunchingAssistantActivityIntoAssistantStack() throws Exception { 83 // Enable the assistant and launch an assistant activity 84 try (final AssistantSession assistantSession = new AssistantSession()) { 85 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 86 87 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION); 88 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 89 90 // Ensure that the activity launched in the fullscreen assistant stack 91 assertAssistantStackExists(); 92 // In a multi-window environment the assistant might not be fullscreen 93 assumeTrue(getDefaultDisplayWindowingMode() == WINDOWING_MODE_FULLSCREEN); 94 assertTrue("Expected assistant stack to be fullscreen", 95 mWmState.getRootTaskByActivityType( 96 ACTIVITY_TYPE_ASSISTANT).isFullscreen()); 97 } 98 } 99 100 @Test testAssistantStackZOrder()101 public void testAssistantStackZOrder() throws Exception { 102 assumeTrue(assistantRunsOnPrimaryDisplay()); 103 assumeTrue(supportsPip()); 104 assumeTrue(supportsSplitScreenMultiWindow()); 105 106 // Launch a pinned stack task 107 launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true")); 108 waitForValidStateWithActivityTypeAndWindowingMode( 109 PIP_ACTIVITY, ACTIVITY_TYPE_STANDARD, WINDOWING_MODE_PINNED); 110 mWmState.assertContainsStack("Must contain pinned stack.", 111 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); 112 113 // Dock a task 114 launchActivitiesInSplitScreen( 115 getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), 116 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 117 118 // Enable the assistant and launch an assistant activity, ensure it is on top 119 try (final AssistantSession assistantSession = new AssistantSession()) { 120 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 121 122 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION); 123 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 124 assertAssistantStackExists(); 125 126 mWmState.assertFrontStack("Pinned stack should be on top.", 127 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); 128 mWmState.assertFocusedRootTask("Assistant stack should be focused.", 129 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 130 } 131 } 132 133 @Test testAssistantStackLaunchNewTask()134 public void testAssistantStackLaunchNewTask() throws Exception { 135 assertAssistantStackCanLaunchAndReturnFromNewTask(); 136 } 137 138 @Test 139 @Ignore("b/77272253#comment10") testAssistantStackLaunchNewTaskWithDockedStack()140 public void testAssistantStackLaunchNewTaskWithDockedStack() throws Exception { 141 assumeTrue(assistantRunsOnPrimaryDisplay()); 142 assumeTrue(supportsSplitScreenMultiWindow()); 143 144 // Dock a task 145 launchActivitiesInSplitScreen( 146 getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), 147 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 148 149 //assertAssistantStackCanLaunchAndReturnFromNewTask(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); 150 } 151 assertAssistantStackCanLaunchAndReturnFromNewTask()152 private void assertAssistantStackCanLaunchAndReturnFromNewTask() 153 throws Exception { 154 // Enable the assistant and launch an assistant activity which will launch a new task 155 try (final AssistantSession assistantSession = new AssistantSession()) { 156 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 157 158 launchActivityOnDisplayNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, mAssistantDisplayId, 159 extraString(EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY)), 160 extraString(EXTRA_ASSISTANT_DISPLAY_ID, Integer.toString(mAssistantDisplayId))); 161 // Ensure that the fullscreen stack is on top and the test activity is now visible 162 waitForValidStateWithActivityType(TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD); 163 } 164 165 if (isAssistantOnTopOfDream()) { 166 // If the assistant is configured to be always-on-top, then the new task should have 167 // been started behind it and the assistant stack should still be on top. 168 mWmState.assertFocusedActivity( 169 "AssistantActivity should be focused", ASSISTANT_ACTIVITY); 170 mWmState.assertFrontStackActivityType( 171 "Assistant stack should be on top.", ACTIVITY_TYPE_ASSISTANT); 172 mWmState.assertFocusedRootTask("Assistant stack should be focused.", 173 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 174 } else { 175 final int testActivityWindowingMode = 176 mWmState.getTaskDisplayArea(TEST_ACTIVITY).getWindowingMode(); 177 mWmState.assertFocusedActivity("TestActivity should be resumed", TEST_ACTIVITY); 178 mWmState.assertFrontStack("TestActivity stack should be on top.", 179 testActivityWindowingMode, ACTIVITY_TYPE_STANDARD); 180 mWmState.assertFocusedRootTask("TestActivity stack should be focused.", 181 testActivityWindowingMode, ACTIVITY_TYPE_STANDARD); 182 } 183 184 // Now, tell it to finish itself and ensure that the assistant stack is brought back forward 185 mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF); 186 mWmState.waitForFocusedStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 187 mWmState.assertFrontStackActivityType( 188 "Assistant stack should be on top.", ACTIVITY_TYPE_ASSISTANT); 189 mWmState.assertFocusedRootTask("Assistant stack should be focused.", 190 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 191 } 192 193 @Test testAssistantStackFinishToPreviousApp()194 public void testAssistantStackFinishToPreviousApp() throws Exception { 195 // If the Assistant is configured to be always-on-top, then the assistant activity 196 // started in setUp() will not allow any other activities to start. Therefore we should 197 // remove it before launching a fullscreen activity. 198 if (isAssistantOnTopOfDream()) { 199 removeRootTasksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 200 } 201 202 // Launch an assistant activity on top of an existing activity, and ensure that the activity 203 // is still visible and on top after the assistant activity finishes 204 launchActivityOnDisplay(TEST_ACTIVITY, mAssistantDisplayId); 205 try (final AssistantSession assistantSession = new AssistantSession()) { 206 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 207 208 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 209 extraString(EXTRA_ASSISTANT_FINISH_SELF, "true")); 210 mWmState.waitFor((amState) -> !amState.containsActivity(ASSISTANT_ACTIVITY), 211 getActivityName(ASSISTANT_ACTIVITY) + " finished"); 212 } 213 waitForValidStateWithActivityType(TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD); 214 waitAndAssertTopResumedActivity(TEST_ACTIVITY, mAssistantDisplayId, 215 "TestActivity should be resumed"); 216 mWmState.assertFocusedActivity("TestActivity should be focused", TEST_ACTIVITY); 217 218 final int testActivityWindowingMode = 219 mWmState.getTaskDisplayArea(TEST_ACTIVITY).getWindowingMode(); 220 mWmState.assertFrontStack("TestActivity stack should be on top.", 221 testActivityWindowingMode, ACTIVITY_TYPE_STANDARD); 222 mWmState.assertFocusedRootTask("TestActivity stack should be focused.", 223 testActivityWindowingMode, ACTIVITY_TYPE_STANDARD); 224 } 225 226 @Test testDisallowEnterPiPFromAssistantStack()227 public void testDisallowEnterPiPFromAssistantStack() throws Exception { 228 try (final AssistantSession assistantSession = new AssistantSession()) { 229 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 230 231 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 232 extraString(EXTRA_ASSISTANT_ENTER_PIP, "true")); 233 } 234 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 235 mWmState.assertDoesNotContainStack("Must not contain pinned stack.", 236 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); 237 } 238 239 @Test testTranslucentAssistantActivityStackVisibility()240 public void testTranslucentAssistantActivityStackVisibility() throws Exception { 241 try (final AssistantSession assistantSession = new AssistantSession()) { 242 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 243 244 // Go home, launch the assistant and check to see that home is visible 245 removeRootTasksInWindowingModes(WINDOWING_MODE_FULLSCREEN); 246 pressHomeButton(); 247 resumeAppSwitches(); 248 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 249 extraString(EXTRA_ASSISTANT_IS_TRANSLUCENT, "true")); 250 waitForValidStateWithActivityType( 251 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 252 assertAssistantStackExists(); 253 mWmState.waitForHomeActivityVisible(); 254 if (hasHomeScreen()) { 255 mWmState.assertHomeActivityVisible(true); 256 } 257 258 // Launch a fullscreen app and then launch the assistant and check to see that it is 259 // also visible 260 removeRootTasksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 261 launchActivityOnDisplay(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN, mAssistantDisplayId); 262 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 263 extraString(EXTRA_ASSISTANT_IS_TRANSLUCENT, "true")); 264 waitForValidStateWithActivityType( 265 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 266 assertAssistantStackExists(); 267 mWmState.assertVisibility(TEST_ACTIVITY, true); 268 269 // Go home, launch assistant, launch app into fullscreen with activity present, and go 270 // back.Ensure home is visible. 271 removeRootTasksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 272 pressHomeButton(); 273 resumeAppSwitches(); 274 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 275 extraString(EXTRA_ASSISTANT_IS_TRANSLUCENT, "true"), 276 extraString(EXTRA_ASSISTANT_LAUNCH_NEW_TASK, getActivityName(TEST_ACTIVITY))); 277 waitForValidStateWithActivityType(TEST_ACTIVITY, ACTIVITY_TYPE_STANDARD); 278 279 final ComponentName homeActivity = mWmState.getHomeActivityName(); 280 int windowingMode = mWmState.getFocusedRootTaskWindowingMode(); 281 // In a multi-window environment the home activity might not be fully covered 282 assumeTrue(windowingMode == WINDOWING_MODE_FULLSCREEN); 283 284 // A WM Shell can implement a policy where there are more than one default 285 // Task Display Areas. 286 // If there are two task display areas, for example, left and right. 287 // When an activity is organized in left task display area it is still running in 288 // WINDOWING_MODE_FULLSCREEN. Having said that, home activity in default task display 289 // area is not fully covered. Thus, home activity is still resumed and visible. 290 // More than that, in the current AOSP 11 implementation, visibility and activity 291 // lifecycle work differently if activities are in the same task display area or in 292 // different task display areas. 293 // For example, if two task display areas have the exact same bounds, 294 // for the user, an activity running in the top task display area covers the activity 295 // running in the bottom task display area. However, because they are in separate 296 // display areas they will be both resumed. 297 // There can be cases where the bounds match but because tasks are in different 298 // task display area they are both resumed. 299 // So we check the activity bounds for two activities to confirm if task display 300 // areas are the same. If not the same, we will skip the visibility asserting test. 301 if (compareActivityBounds(homeActivity, 302 ComponentName.unflattenFromString(mWmState.getFocusedActivity()))) { 303 mWmState.waitAndAssertVisibilityGone(homeActivity); 304 } 305 306 mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF); 307 mWmState.waitForFocusedStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 308 assertAssistantStackExists(); 309 mWmState.waitForHomeActivityVisible(); 310 if (hasHomeScreen()) { 311 mWmState.assertHomeActivityVisible(true); 312 } 313 314 // Launch a fullscreen and docked app and then launch the assistant and check to see 315 // that it 316 // is also visible 317 if (supportsSplitScreenMultiWindow() && assistantRunsOnPrimaryDisplay()) { 318 removeRootTasksWithActivityTypes(ACTIVITY_TYPE_ASSISTANT); 319 launchActivitiesInSplitScreen( 320 getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), 321 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 322 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 323 extraString(EXTRA_ASSISTANT_IS_TRANSLUCENT, "true")); 324 waitForValidStateWithActivityType( 325 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 326 assertAssistantStackExists(); 327 mWmState.assertVisibility(DOCKED_ACTIVITY, true); 328 mWmState.assertVisibility(TEST_ACTIVITY, true); 329 } 330 } 331 } 332 333 @Test testLaunchIntoSameTask()334 public void testLaunchIntoSameTask() throws Exception { 335 try (final AssistantSession assistantSession = new AssistantSession()) { 336 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 337 338 // Launch the assistant 339 launchActivityOnDisplayNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION, 340 mAssistantDisplayId); 341 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 342 assertAssistantStackExists(); 343 mWmState.assertVisibility(ASSISTANT_ACTIVITY, true); 344 mWmState.assertFocusedRootTask("Expected assistant stack focused", 345 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 346 final WindowManagerState amState = mWmState; 347 assertThat(amState.getRootTaskByActivityType(ACTIVITY_TYPE_ASSISTANT).getTasks(), 348 hasSize(1)); 349 final int taskId = mWmState.getTaskByActivity(ASSISTANT_ACTIVITY) 350 .mTaskId; 351 352 // Launch a new fullscreen activity 353 // Using Animation Test Activity because it is opaque on all devices. 354 launchActivityOnDisplay(ANIMATION_TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN, mAssistantDisplayId); 355 // If the activity is not launched in same TDA, ASSISTANT_ACTIVITY will be visible. 356 assumeTrue("Should launch in same TDA", 357 mWmState.getTaskDisplayArea(ASSISTANT_ACTIVITY) 358 == mWmState.getTaskDisplayArea(ANIMATION_TEST_ACTIVITY) 359 ); 360 // Wait for animation finished. 361 mWmState.waitForActivityState(ANIMATION_TEST_ACTIVITY, STATE_RESUMED); 362 363 if (isAssistantOnTopOfDream()) { 364 mWmState.assertVisibility(ASSISTANT_ACTIVITY, true); 365 } else { 366 mWmState.waitAndAssertVisibilityGone(ASSISTANT_ACTIVITY); 367 } 368 369 // Launch the assistant again and ensure that it goes into the same task 370 launchActivityOnDisplayNoWait(LAUNCH_ASSISTANT_ACTIVITY_FROM_SESSION, 371 mAssistantDisplayId); 372 waitForValidStateWithActivityType(ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 373 assertAssistantStackExists(); 374 mWmState.assertVisibility(ASSISTANT_ACTIVITY, true); 375 mWmState.assertFocusedRootTask("Expected assistant stack focused", 376 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 377 assertThat(amState.getRootTaskByActivityType(ACTIVITY_TYPE_ASSISTANT).getTasks(), 378 hasSize(1)); 379 assertEquals(taskId, 380 mWmState.getTaskByActivity(ASSISTANT_ACTIVITY).mTaskId); 381 382 } 383 } 384 385 @Test testPinnedStackWithAssistant()386 public void testPinnedStackWithAssistant() throws Exception { 387 assumeTrue(supportsPip()); 388 assumeTrue(supportsSplitScreenMultiWindow()); 389 390 try (final AssistantSession assistantSession = new AssistantSession()) { 391 assistantSession.setVoiceInteractionService(ASSISTANT_VOICE_INTERACTION_SERVICE); 392 393 // Launch a fullscreen activity and a PIP activity, then launch the assistant, and 394 // ensure that the test activity is still visible 395 launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 396 launchActivity(PIP_ACTIVITY, extraString(EXTRA_ENTER_PIP, "true")); 397 launchActivityNoWait(LAUNCH_ASSISTANT_ACTIVITY_INTO_STACK, 398 extraString(EXTRA_ASSISTANT_IS_TRANSLUCENT, String.valueOf(true))); 399 waitForValidStateWithActivityType( 400 TRANSLUCENT_ASSISTANT_ACTIVITY, ACTIVITY_TYPE_ASSISTANT); 401 assertAssistantStackExists(); 402 mWmState.assertVisibility(TRANSLUCENT_ASSISTANT_ACTIVITY, true); 403 mWmState.assertVisibility(PIP_ACTIVITY, true); 404 mWmState.assertVisibility(TEST_ACTIVITY, true); 405 406 } 407 } 408 waitForValidStateWithActivityType(ComponentName activityName, int activityType)409 private void waitForValidStateWithActivityType(ComponentName activityName, int activityType) 410 throws Exception { 411 mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName) 412 .setActivityType(activityType) 413 .build()); 414 } 415 waitForValidStateWithActivityTypeAndWindowingMode(ComponentName activityName, int activityType, int windowingMode)416 private void waitForValidStateWithActivityTypeAndWindowingMode(ComponentName activityName, 417 int activityType, int windowingMode) throws Exception { 418 mWmState.waitForValidState(new WaitForValidActivityState.Builder(activityName) 419 .setActivityType(activityType) 420 .setWindowingMode(windowingMode) 421 .build()); 422 } 423 424 /** 425 * Asserts that the assistant stack exists. 426 */ assertAssistantStackExists()427 private void assertAssistantStackExists() throws Exception { 428 mWmState.assertContainsStack("Must contain assistant stack.", 429 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_ASSISTANT); 430 } 431 432 // Any 2D Activity in VR mode is run on a special VR virtual display, so check if the Assistant 433 // is going to run on the same display as other tasks. assistantRunsOnPrimaryDisplay()434 protected boolean assistantRunsOnPrimaryDisplay() { 435 return mAssistantDisplayId == DEFAULT_DISPLAY; 436 } 437 438 /** 439 * @return Windowing Mode from the default display 440 */ getDefaultDisplayWindowingMode()441 private int getDefaultDisplayWindowingMode() { 442 mWmState.computeState(); 443 return mWmState.getDisplay(DEFAULT_DISPLAY).getWindowingMode(); 444 } 445 446 /** Helper class to save, set, and restore 447 * {@link Settings.Secure#VOICE_INTERACTION_SERVICE} system preference. 448 */ 449 private static class AssistantSession extends SettingsSession<String> { AssistantSession()450 AssistantSession() { 451 super(Settings.Secure.getUriFor(Settings.Secure.VOICE_INTERACTION_SERVICE), 452 Settings.Secure::getString, Settings.Secure::putString); 453 } 454 setVoiceInteractionService(ComponentName assistantName)455 void setVoiceInteractionService(ComponentName assistantName) throws Exception { 456 super.set(getActivityName(assistantName)); 457 } 458 } 459 460 /** 461 * Compare if bounds were the same between activities 462 */ compareActivityBounds(ComponentName activityName1, ComponentName activityName2)463 private boolean compareActivityBounds(ComponentName activityName1, 464 ComponentName activityName2) { 465 if (mWmState.getTaskByActivity(activityName1).getBounds() 466 .equals(mWmState.getTaskByActivity(activityName2).getBounds())) { 467 return true; 468 } 469 return false; 470 } 471 } 472