1 /* 2 * Copyright (C) 2015 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.ActivityManager.LOCK_TASK_MODE_NONE; 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_MULTI_WINDOW; 23 import static android.server.wm.TestTaskOrganizer.INVALID_TASK_ID; 24 import static android.server.wm.WindowManagerState.STATE_RESUMED; 25 import static android.server.wm.WindowManagerState.STATE_STOPPED; 26 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY; 27 import static android.server.wm.app.Components.NON_RESIZEABLE_ACTIVITY; 28 import static android.server.wm.app.Components.NO_RELAUNCH_ACTIVITY; 29 import static android.server.wm.app.Components.SINGLE_INSTANCE_ACTIVITY; 30 import static android.server.wm.app.Components.SINGLE_TASK_ACTIVITY; 31 import static android.server.wm.app.Components.TEST_ACTIVITY; 32 import static android.server.wm.app.Components.TEST_ACTIVITY_WITH_SAME_AFFINITY; 33 import static android.server.wm.app.Components.TRANSLUCENT_TEST_ACTIVITY; 34 import static android.server.wm.app.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF; 35 import static android.server.wm.app27.Components.SDK_27_LAUNCHING_ACTIVITY; 36 import static android.server.wm.app27.Components.SDK_27_SEPARATE_PROCESS_ACTIVITY; 37 import static android.server.wm.app27.Components.SDK_27_TEST_ACTIVITY; 38 39 import static org.junit.Assert.assertEquals; 40 import static org.junit.Assert.assertNotEquals; 41 import static org.junit.Assert.assertTrue; 42 import static org.junit.Assert.fail; 43 import static org.junit.Assume.assumeTrue; 44 45 import android.content.ComponentName; 46 import android.content.res.Resources; 47 import android.platform.test.annotations.Presubmit; 48 import android.server.wm.CommandSession.ActivityCallback; 49 import android.view.WindowManager; 50 import android.window.WindowContainerToken; 51 import android.window.WindowContainerTransaction; 52 53 import org.junit.Before; 54 import org.junit.Test; 55 56 /** 57 * Build/Install/Run: 58 * atest CtsWindowManagerDeviceTestCases:MultiWindowTests 59 */ 60 @Presubmit 61 @android.server.wm.annotation.Group2 62 public class MultiWindowTests extends ActivityManagerTestBase { 63 64 private boolean mIsHomeRecentsComponent; 65 66 @Before 67 @Override setUp()68 public void setUp() throws Exception { 69 super.setUp(); 70 71 mIsHomeRecentsComponent = mWmState.isHomeRecentsComponent(); 72 73 assumeTrue("Skipping test: no split multi-window support", 74 supportsSplitScreenMultiWindow()); 75 } 76 77 @Test testMinimumDeviceSize()78 public void testMinimumDeviceSize() { 79 mWmState.assertDeviceDefaultDisplaySizeForMultiWindow( 80 "Devices supporting multi-window must be larger than the default minimum" 81 + " task size"); 82 mWmState.assertDeviceDefaultDisplaySizeForSplitScreen( 83 "Devices supporting split-screen multi-window must be larger than the" 84 + " default minimum display size."); 85 } 86 87 /** Resizeable activity should be able to enter multi-window mode.*/ 88 @Test testResizeableActivity()89 public void testResizeableActivity() { 90 assertActivitySupportedInSplitScreen(TEST_ACTIVITY); 91 } 92 93 /** 94 * Depending on the value of 95 * {@link com.android.internal.R.integer.config_supportsNonResizableMultiWindow}, 96 * non-resizeable activity may or may not be able to enter multi-window mode. 97 * 98 * Based on the flag value: 99 * -1: not support non-resizable in multi window. 100 * 0: check the screen smallest width, if it is a large screen, support non-resizable in multi 101 * window. Otherwise, not support. 102 * 1: always support non-resizable in multi window. 103 */ 104 @Test testNonResizeableActivity()105 public void testNonResizeableActivity() { 106 createManagedDevEnableNonResizableMultiWindowSession().set(0); 107 final Resources resources = mContext.getResources(); 108 final int configSupportsNonResizableMultiWindow; 109 try { 110 configSupportsNonResizableMultiWindow = resources.getInteger(resources.getIdentifier( 111 "config_supportsNonResizableMultiWindow", "integer", "android")); 112 } catch (Resources.NotFoundException e) { 113 fail("Device must define config_supportsNonResizableMultiWindow"); 114 return; 115 } 116 switch (configSupportsNonResizableMultiWindow) { 117 case -1: 118 assertActivityNotSupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY); 119 break; 120 case 1: 121 assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY); 122 break; 123 case 0: 124 final int smallestScreenWidthDp = mWmState.getHomeTask() 125 .mFullConfiguration.smallestScreenWidthDp; 126 if (smallestScreenWidthDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP) { 127 assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY); 128 } else { 129 assertActivityNotSupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY); 130 } 131 break; 132 default: 133 fail("config_supportsNonResizableMultiWindow must be -1, 0, or 1."); 134 } 135 } 136 137 /** 138 * Non-resizeable activity can enter split-screen if 139 * {@link android.provider.Settings.Global#DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW} is 140 * set. 141 */ 142 @Test testDevEnableNonResizeableMultiWindow_splitScreenPrimary()143 public void testDevEnableNonResizeableMultiWindow_splitScreenPrimary() { 144 createManagedDevEnableNonResizableMultiWindowSession().set(1); 145 146 assertActivitySupportedInSplitScreen(NON_RESIZEABLE_ACTIVITY); 147 } 148 149 /** 150 * Non-resizeable activity can enter split-screen if 151 * {@link android.provider.Settings.Global#DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW} is 152 * set. 153 */ 154 @Test testDevEnableNonResizeableMultiWindow_splitScreenSecondary()155 public void testDevEnableNonResizeableMultiWindow_splitScreenSecondary() { 156 createManagedDevEnableNonResizableMultiWindowSession().set(1); 157 158 launchActivitiesInSplitScreen( 159 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY), 160 getLaunchActivityBuilder().setTargetActivity(NON_RESIZEABLE_ACTIVITY)); 161 162 mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED); 163 mWmState.assertVisibility(NON_RESIZEABLE_ACTIVITY, true); 164 assertTrue(mWmState.containsActivityInWindowingMode( 165 NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW)); 166 } 167 168 /** Asserts that the give activity can be shown in split screen. */ assertActivitySupportedInSplitScreen(ComponentName activity)169 private void assertActivitySupportedInSplitScreen(ComponentName activity) { 170 launchActivityInPrimarySplit(activity); 171 mWmState.waitForActivityState(activity, STATE_RESUMED); 172 mWmState.assertVisibility(activity, true); 173 assertTrue(mWmState.containsActivityInWindowingMode(activity, WINDOWING_MODE_MULTI_WINDOW)); 174 } 175 176 /** Asserts that the give activity can NOT be shown in split screen. */ assertActivityNotSupportedInSplitScreen(ComponentName activity)177 private void assertActivityNotSupportedInSplitScreen(ComponentName activity) { 178 boolean gotAssertionError = false; 179 try { 180 launchActivityInPrimarySplit(activity); 181 } catch (AssertionError e) { 182 gotAssertionError = true; 183 } 184 assertTrue("Trying to put non-resizeable activity in split should throw error.", 185 gotAssertionError); 186 mWmState.waitForActivityState(activity, STATE_RESUMED); 187 mWmState.assertVisibility(activity, true); 188 assertTrue(mWmState.containsActivityInWindowingMode(activity, WINDOWING_MODE_FULLSCREEN)); 189 } 190 191 @Test testLaunchToSideMultiWindowCallbacks()192 public void testLaunchToSideMultiWindowCallbacks() { 193 // Launch two activities in split-screen mode. 194 launchActivitiesInSplitScreen( 195 getLaunchActivityBuilder().setTargetActivity(NO_RELAUNCH_ACTIVITY), 196 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 197 198 int displayWindowingMode = mWmState.getDisplay( 199 mWmState.getDisplayByActivity(TEST_ACTIVITY)).getWindowingMode(); 200 separateTestJournal(); 201 mTaskOrganizer.dismissSplitScreen(true /* primaryOnTop */); 202 if (displayWindowingMode == WINDOWING_MODE_FULLSCREEN) { 203 // Exit split-screen mode and ensure we only get 1 multi-window mode changed callback. 204 final ActivityLifecycleCounts lifecycleCounts = waitForOnMultiWindowModeChanged( 205 NO_RELAUNCH_ACTIVITY); 206 assertEquals(1, 207 lifecycleCounts.getCount(ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED)); 208 } else { 209 // Display is not a fullscreen display, so there won't be a multi-window callback. 210 // Instead just verify that windows are not in split-screen anymore. 211 waitForIdle(); 212 mWmState.computeState(); 213 mWmState.assertDoesNotContainStack("Must have exited split-screen", 214 WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD); 215 } 216 } 217 218 @Test testNoUserLeaveHintOnMultiWindowModeChanged()219 public void testNoUserLeaveHintOnMultiWindowModeChanged() { 220 launchActivity(NO_RELAUNCH_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 221 222 // Move to primary split. 223 separateTestJournal(); 224 putActivityInPrimarySplit(NO_RELAUNCH_ACTIVITY); 225 226 ActivityLifecycleCounts lifecycleCounts = 227 waitForOnMultiWindowModeChanged(NO_RELAUNCH_ACTIVITY); 228 assertEquals("mMultiWindowModeChangedCount", 229 1, lifecycleCounts.getCount(ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED)); 230 assertEquals("mUserLeaveHintCount", 231 0, lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT)); 232 233 // Make sure primary split is focused. This way when we dismiss it later fullscreen stack 234 // will come up. 235 launchActivity(LAUNCHING_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 236 putActivityInSecondarySplit(LAUNCHING_ACTIVITY); 237 238 launchActivity(NO_RELAUNCH_ACTIVITY); 239 240 separateTestJournal(); 241 242 // Move activities back to fullscreen screen. 243 // TestTaskOrganizer sets windowing modes of tasks to unspecific when putting them to split 244 // screens so we need to explicitly set their windowing modes back to fullscreen to avoid 245 // inheriting freeform windowing mode from the display on freeform first devices. 246 int noRelaunchTaskId = mWmState.getTaskByActivity(NO_RELAUNCH_ACTIVITY).mTaskId; 247 WindowContainerToken noRelaunchTaskToken = 248 mTaskOrganizer.getTaskInfo(noRelaunchTaskId).getToken(); 249 WindowContainerTransaction t = new WindowContainerTransaction() 250 .setWindowingMode(noRelaunchTaskToken, WINDOWING_MODE_FULLSCREEN); 251 mTaskOrganizer.dismissSplitScreen(t, true /* primaryOnTop */); 252 253 lifecycleCounts = waitForOnMultiWindowModeChanged(NO_RELAUNCH_ACTIVITY); 254 assertEquals("mMultiWindowModeChangedCount", 255 1, lifecycleCounts.getCount(ActivityCallback.ON_MULTI_WINDOW_MODE_CHANGED)); 256 assertEquals("mUserLeaveHintCount", 257 0, lifecycleCounts.getCount(ActivityCallback.ON_USER_LEAVE_HINT)); 258 } 259 260 @Test testLaunchToSideAndBringToFront()261 public void testLaunchToSideAndBringToFront() { 262 launchActivitiesInSplitScreen( 263 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY), 264 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 265 266 mWmState.assertFocusedActivity("Launched to side activity must be in front.", 267 TEST_ACTIVITY); 268 269 // Set secondary split as launch root 270 mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId()); 271 272 // Launch another activity to side to cover first one. 273 launchActivityInSecondarySplit(NO_RELAUNCH_ACTIVITY); 274 mWmState.assertFocusedActivity("Launched to side covering activity must be in front.", 275 NO_RELAUNCH_ACTIVITY); 276 277 // Launch activity that was first launched to side. It should be brought to front. 278 launchActivity(TEST_ACTIVITY); 279 mWmState.assertFocusedActivity("Launched to side covering activity must be in front.", 280 TEST_ACTIVITY); 281 } 282 283 @Test testLaunchToSideMultiple()284 public void testLaunchToSideMultiple() { 285 launchActivitiesInSplitScreen( 286 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY), 287 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 288 289 final int taskNumberInitial = mTaskOrganizer.getSecondarySplitTaskCount(); 290 291 // Try to launch to side same activity again. 292 launchActivity(TEST_ACTIVITY); 293 mWmState.computeState(TEST_ACTIVITY, LAUNCHING_ACTIVITY); 294 final int taskNumberFinal = mTaskOrganizer.getSecondarySplitTaskCount(); 295 assertEquals("Task number mustn't change.", taskNumberInitial, taskNumberFinal); 296 mWmState.assertFocusedActivity("Launched to side activity must remain in front.", 297 TEST_ACTIVITY); 298 } 299 300 @Test testLaunchToSideSingleInstance()301 public void testLaunchToSideSingleInstance() { 302 launchTargetToSide(SINGLE_INSTANCE_ACTIVITY, false); 303 } 304 305 @Test testLaunchToSideSingleTask()306 public void testLaunchToSideSingleTask() { 307 launchTargetToSide(SINGLE_TASK_ACTIVITY, false); 308 } 309 310 @Test testLaunchToSideMultipleWithDifferentIntent()311 public void testLaunchToSideMultipleWithDifferentIntent() { 312 launchTargetToSide(TEST_ACTIVITY, true); 313 } 314 launchTargetToSide(ComponentName targetActivityName, boolean taskCountMustIncrement)315 private void launchTargetToSide(ComponentName targetActivityName, 316 boolean taskCountMustIncrement) { 317 launchActivityInPrimarySplit(LAUNCHING_ACTIVITY); 318 319 // Launch target to side 320 final LaunchActivityBuilder targetActivityLauncher = getLaunchActivityBuilder() 321 .setTargetActivity(targetActivityName) 322 .setToSide(true) 323 .setRandomData(true) 324 .setMultipleTask(false); 325 targetActivityLauncher.execute(); 326 final int secondaryTaskId = mWmState.getTaskByActivity(targetActivityName).mTaskId; 327 mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId); 328 329 mWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY); 330 final int taskNumberInitial = mTaskOrganizer.getSecondarySplitTaskCount(); 331 332 // Try to launch to side same activity again with different data. 333 targetActivityLauncher.execute(); 334 mWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY); 335 336 final int[] excludeTaskIds = new int[] { secondaryTaskId, INVALID_TASK_ID }; 337 if (taskCountMustIncrement) { 338 mWmState.waitFor("Waiting for new activity to come up.", 339 state -> state.getTaskByActivity(targetActivityName, excludeTaskIds) != null); 340 } 341 WindowManagerState.Task task = mWmState.getTaskByActivity(targetActivityName, 342 excludeTaskIds); 343 final int secondaryTaskId2; 344 if (task != null) { 345 secondaryTaskId2 = task.mTaskId; 346 mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId2); 347 } else { 348 secondaryTaskId2 = INVALID_TASK_ID; 349 } 350 final int taskNumberSecondLaunch = mTaskOrganizer.getSecondarySplitTaskCount(); 351 352 if (taskCountMustIncrement) { 353 assertEquals("Task number must be incremented.", taskNumberInitial + 1, 354 taskNumberSecondLaunch); 355 } else { 356 assertEquals("Task number must not change.", taskNumberInitial, 357 taskNumberSecondLaunch); 358 } 359 mWmState.waitForFocusedActivity("Wait for launched to side activity to be in front.", 360 targetActivityName); 361 mWmState.assertFocusedActivity("Launched to side activity must be in front.", 362 targetActivityName); 363 364 // Try to launch to side same activity again with different random data. Note that null 365 // cannot be used here, since the first instance of TestActivity is launched with no data 366 // in order to launch into split screen. 367 targetActivityLauncher.execute(); 368 mWmState.computeState(targetActivityName, LAUNCHING_ACTIVITY); 369 370 excludeTaskIds[1] = secondaryTaskId2; 371 if (taskCountMustIncrement) { 372 mWmState.waitFor("Waiting for the second new activity to come up.", 373 state -> state.getTaskByActivity(targetActivityName, excludeTaskIds) != null); 374 } 375 WindowManagerState.Task taskFinal = 376 mWmState.getTaskByActivity(targetActivityName, excludeTaskIds); 377 if (taskFinal != null) { 378 int secondaryTaskId3 = taskFinal.mTaskId; 379 mTaskOrganizer.putTaskInSplitSecondary(secondaryTaskId3); 380 } 381 final int taskNumberFinal = mTaskOrganizer.getSecondarySplitTaskCount(); 382 383 if (taskCountMustIncrement) { 384 assertEquals("Task number must be incremented.", taskNumberSecondLaunch + 1, 385 taskNumberFinal); 386 } else { 387 assertEquals("Task number must not change.", taskNumberSecondLaunch, 388 taskNumberFinal); 389 } 390 mWmState.waitForFocusedActivity("Wait for launched to side activity to be in front.", 391 targetActivityName); 392 mWmState.assertFocusedActivity("Launched to side activity must be in front.", 393 targetActivityName); 394 } 395 396 @Test testLaunchToSideMultipleWithFlag()397 public void testLaunchToSideMultipleWithFlag() { 398 launchActivitiesInSplitScreen( 399 getLaunchActivityBuilder() 400 .setTargetActivity(TEST_ACTIVITY), 401 getLaunchActivityBuilder() 402 // Try to launch to side same activity again, 403 // but with Intent#FLAG_ACTIVITY_MULTIPLE_TASK. 404 .setMultipleTask(true) 405 .setTargetActivity(TEST_ACTIVITY)); 406 assertTrue("Primary split must contain TEST_ACTIVITY", 407 mWmState.getRootTask(mTaskOrganizer.getPrimarySplitTaskId()) 408 .containsActivity(TEST_ACTIVITY) 409 ); 410 411 assertTrue("Secondary split must contain TEST_ACTIVITY", 412 mWmState.getRootTask(mTaskOrganizer.getSecondarySplitTaskId()) 413 .containsActivity(TEST_ACTIVITY) 414 ); 415 mWmState.assertFocusedActivity("Launched to side activity must be in front.", 416 TEST_ACTIVITY); 417 } 418 419 @Test testSameProcessActivityResumedPreQ()420 public void testSameProcessActivityResumedPreQ() { 421 launchActivitiesInSplitScreen( 422 getLaunchActivityBuilder().setTargetActivity(SDK_27_TEST_ACTIVITY), 423 getLaunchActivityBuilder().setTargetActivity(SDK_27_LAUNCHING_ACTIVITY)); 424 425 assertEquals("There must be only one resumed activity in the package.", 1, 426 mWmState.getResumedActivitiesCountInPackage( 427 SDK_27_TEST_ACTIVITY.getPackageName())); 428 } 429 430 @Test testDifferentProcessActivityResumedPreQ()431 public void testDifferentProcessActivityResumedPreQ() { 432 launchActivitiesInSplitScreen( 433 getLaunchActivityBuilder().setTargetActivity(SDK_27_TEST_ACTIVITY), 434 getLaunchActivityBuilder().setTargetActivity(SDK_27_SEPARATE_PROCESS_ACTIVITY)); 435 436 assertEquals("There must be only two resumed activities in the package.", 2, 437 mWmState.getResumedActivitiesCountInPackage( 438 SDK_27_TEST_ACTIVITY.getPackageName())); 439 } 440 441 @Test testDisallowUpdateWindowingModeWhenInLockedTask()442 public void testDisallowUpdateWindowingModeWhenInLockedTask() { 443 launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 444 final WindowManagerState.Task task = 445 mWmState.getStandardRootTaskByWindowingMode( 446 WINDOWING_MODE_FULLSCREEN).getTopTask(); 447 448 try { 449 // Lock the task 450 runWithShellPermission(() -> mAtm.startSystemLockTaskMode(task.mTaskId)); 451 waitForOrFail("Fail to enter locked task mode", () -> 452 mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE); 453 454 // Verify specifying non-fullscreen windowing mode will fail. 455 runWithShellPermission(() -> { 456 final WindowContainerTransaction wct = new WindowContainerTransaction() 457 .setWindowingMode( 458 mTaskOrganizer.getTaskInfo(task.mTaskId).getToken(), 459 WINDOWING_MODE_MULTI_WINDOW); 460 mTaskOrganizer.applyTransaction(wct); 461 }); 462 mWmState.computeState(TEST_ACTIVITY); 463 assertEquals(WINDOWING_MODE_FULLSCREEN, 464 mWmState.getWindowState(TEST_ACTIVITY).getWindowingMode()); 465 } finally { 466 runWithShellPermission(() -> { 467 mAtm.stopSystemLockTaskMode(); 468 }); 469 } 470 } 471 472 @Test testDisallowReparentOperationWhenInLockedTask()473 public void testDisallowReparentOperationWhenInLockedTask() { 474 launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 475 launchActivity(LAUNCHING_ACTIVITY, WINDOWING_MODE_MULTI_WINDOW); 476 final WindowManagerState.Task task = mWmState 477 .getStandardRootTaskByWindowingMode(WINDOWING_MODE_FULLSCREEN).getTopTask(); 478 final WindowManagerState.Task root = mWmState 479 .getStandardRootTaskByWindowingMode(WINDOWING_MODE_MULTI_WINDOW).getTopTask(); 480 481 try { 482 // Lock the task 483 runWithShellPermission(() -> { 484 mAtm.startSystemLockTaskMode(task.mTaskId); 485 }); 486 waitForOrFail("Fail to enter locked task mode", () -> 487 mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE); 488 489 boolean gotAssertionError = false; 490 try { 491 runWithShellPermission(() -> { 492 // Fetch tokens of testing task and multi-window root. 493 final WindowContainerToken multiWindowRoot = 494 mTaskOrganizer.getTaskInfo(root.mTaskId).getToken(); 495 final WindowContainerToken testChild = 496 mTaskOrganizer.getTaskInfo(task.mTaskId).getToken(); 497 498 // Verify performing reparent operation is no operation. 499 final WindowContainerTransaction wct = new WindowContainerTransaction() 500 .reparent(testChild, multiWindowRoot, true /* onTop */); 501 mTaskOrganizer.applyTransaction(wct); 502 waitForOrFail("Fail to reparent", () -> 503 mTaskOrganizer.getTaskInfo(task.mTaskId).getParentTaskId() 504 == root.mTaskId); 505 }); 506 } catch (AssertionError e) { 507 gotAssertionError = true; 508 } 509 assertTrue("Not allowed to perform hierarchy operation while in locked task mode.", 510 gotAssertionError); 511 } finally { 512 runWithShellPermission(() -> { 513 mAtm.stopSystemLockTaskMode(); 514 }); 515 } 516 } 517 518 /** 519 * Asserts that the activity is visible when the top opaque activity finishes and with another 520 * translucent activity on top while in split-screen-secondary task. 521 */ 522 @Test testVisibilityWithTranslucentAndTopFinishingActivity()523 public void testVisibilityWithTranslucentAndTopFinishingActivity() { 524 // Launch two activities in split-screen mode. 525 launchActivitiesInSplitScreen( 526 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY), 527 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY_WITH_SAME_AFFINITY)); 528 529 mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId()); 530 531 // Launch two more activities on a different task on top of split-screen-secondary and 532 // only the top opaque activity should be visible. 533 // Explicitly launch them into fullscreen mode because the control windowing mode of the 534 // launch root doesn't include freeform mode. Freeform first devices launch apps in freeform 535 // mode by default, which won't trigger the launch root. 536 getLaunchActivityBuilder().setTargetActivity(TRANSLUCENT_TEST_ACTIVITY) 537 .setUseInstrumentation() 538 .setWaitForLaunched(true) 539 .setWindowingMode(WINDOWING_MODE_FULLSCREEN) 540 .execute(); 541 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY) 542 .setUseInstrumentation() 543 .setWaitForLaunched(true) 544 .setWindowingMode(WINDOWING_MODE_FULLSCREEN) 545 .execute(); 546 mWmState.assertVisibility(TEST_ACTIVITY, true); 547 mWmState.waitForActivityState(TRANSLUCENT_TEST_ACTIVITY, STATE_STOPPED); 548 mWmState.assertVisibility(TRANSLUCENT_TEST_ACTIVITY, false); 549 mWmState.assertVisibility(TEST_ACTIVITY_WITH_SAME_AFFINITY, false); 550 551 // Finish the top opaque activity and both the two activities should be visible. 552 mBroadcastActionTrigger.doAction(TEST_ACTIVITY_ACTION_FINISH_SELF); 553 mWmState.computeState(new WaitForValidActivityState(TRANSLUCENT_TEST_ACTIVITY)); 554 mWmState.assertVisibility(TRANSLUCENT_TEST_ACTIVITY, true); 555 mWmState.assertVisibility(TEST_ACTIVITY_WITH_SAME_AFFINITY, true); 556 } 557 558 /** 559 * Ensure that the hierarchy operation : reorder is not allowed if the target task is violated 560 * the lock-task policy. 561 */ 562 @Test testDisallowReOrderOperationWhenInLockedTask()563 public void testDisallowReOrderOperationWhenInLockedTask() { 564 // Start LaunchingActivity and testActivity in two separate tasks. 565 launchActivity(LAUNCHING_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 566 launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 567 waitAndAssertResumedActivity(TEST_ACTIVITY, "Activity must be resumed"); 568 569 final int taskId = mWmState.getTaskByActivity(TEST_ACTIVITY).mTaskId; 570 final int taskId2 = mWmState.getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId; 571 // Make sure the launching activity and the test activity are not in the same task. 572 assertNotEquals("Activity must be in different task.", taskId, taskId2); 573 574 try { 575 runWithShellPermission(() -> { 576 mAtm.startSystemLockTaskMode(taskId); 577 }); 578 waitForOrFail("Fail to enter locked task mode", () -> 579 mAm.getLockTaskModeState() != LOCK_TASK_MODE_NONE); 580 581 boolean gotAssertionError = false; 582 try { 583 runWithShellPermission(() -> { 584 final WindowContainerToken token = 585 mTaskOrganizer.getTaskInfo(taskId2).getToken(); 586 587 // Verify performing reorder operation is no operation. 588 final WindowContainerTransaction wct = new WindowContainerTransaction() 589 .reorder(token, true /* onTop */); 590 mTaskOrganizer.applyTransaction(wct); 591 592 final WindowManagerState.Task topTask = mWmState 593 .getStandardRootTaskByWindowingMode(WINDOWING_MODE_FULLSCREEN) 594 .getTopTask(); 595 waitForOrFail("Fail to reorder", () -> (topTask.mTaskId == taskId2)); 596 }); 597 } catch (AssertionError e) { 598 gotAssertionError = true; 599 } 600 assertTrue("Not allowed to perform reorder operation while in locked task mode.", 601 gotAssertionError); 602 } finally { 603 runWithShellPermission(() -> { 604 mAtm.stopSystemLockTaskMode(); 605 }); 606 } 607 } 608 } 609