1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package android.server.wm; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 25 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 26 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 27 import static android.server.wm.StateLogger.logE; 28 import static android.server.wm.WindowManagerState.STATE_RESUMED; 29 import static android.server.wm.WindowManagerState.dpToPx; 30 import static android.server.wm.app.Components.BROADCAST_RECEIVER_ACTIVITY; 31 import static android.server.wm.app.Components.DIALOG_WHEN_LARGE_ACTIVITY; 32 import static android.server.wm.app.Components.LANDSCAPE_ORIENTATION_ACTIVITY; 33 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY; 34 import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_APP_CONFIG_INFO; 35 import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_CONFIG_INFO_IN_ON_CREATE; 36 import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_DISPLAY_REAL_SIZE; 37 import static android.server.wm.app.Components.LandscapeOrientationActivity.EXTRA_SYSTEM_RESOURCES_CONFIG_INFO; 38 import static android.server.wm.app.Components.NIGHT_MODE_ACTIVITY; 39 import static android.server.wm.app.Components.PORTRAIT_ORIENTATION_ACTIVITY; 40 import static android.server.wm.app.Components.RESIZEABLE_ACTIVITY; 41 import static android.server.wm.app.Components.TEST_ACTIVITY; 42 import static android.server.wm.translucentapp26.Components.SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY; 43 import static android.view.Surface.ROTATION_0; 44 import static android.view.Surface.ROTATION_180; 45 import static android.view.Surface.ROTATION_270; 46 import static android.view.Surface.ROTATION_90; 47 48 import static org.hamcrest.MatcherAssert.assertThat; 49 import static org.hamcrest.Matchers.lessThan; 50 import static org.junit.Assert.assertEquals; 51 import static org.junit.Assert.assertTrue; 52 import static org.junit.Assert.assertFalse; 53 import static org.junit.Assert.assertNotEquals; 54 import static org.junit.Assert.fail; 55 import static org.junit.Assume.assumeFalse; 56 import static org.junit.Assume.assumeTrue; 57 58 import android.app.Activity; 59 import android.content.ComponentName; 60 import android.content.Context; 61 import android.content.res.Resources; 62 import android.graphics.Point; 63 import android.graphics.Rect; 64 import android.hardware.display.DisplayManager; 65 import android.os.Bundle; 66 import android.platform.test.annotations.Presubmit; 67 import android.server.wm.CommandSession.ActivitySession; 68 import android.server.wm.CommandSession.ActivitySessionClient; 69 import android.server.wm.CommandSession.ConfigInfo; 70 import android.server.wm.CommandSession.SizeInfo; 71 import android.server.wm.TestJournalProvider.TestJournalContainer; 72 import android.util.DisplayMetrics; 73 import android.view.Display; 74 75 import org.junit.Test; 76 77 import java.util.function.Function; 78 79 /** 80 * Build/Install/Run: 81 * atest CtsWindowManagerDeviceTestCases:AppConfigurationTests 82 */ 83 @Presubmit 84 public class AppConfigurationTests extends MultiDisplayTestBase { 85 86 private static final int SMALL_WIDTH_DP = 426; 87 private static final int SMALL_HEIGHT_DP = 320; 88 89 /** 90 * Tests that the WindowManager#getDefaultDisplay() and the Configuration of the Activity 91 * has an updated size when the Activity is resized from fullscreen to docked state. 92 * 93 * The Activity handles configuration changes, so it will not be restarted between resizes. 94 * On Configuration changes, the Activity logs the Display size and Configuration width 95 * and heights. The values reported in fullscreen should be larger than those reported in 96 * docked state. 97 */ 98 @Test testConfigurationUpdatesWhenResizedFromFullscreen()99 public void testConfigurationUpdatesWhenResizedFromFullscreen() { 100 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 101 102 separateTestJournal(); 103 launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 104 final SizeInfo fullscreenSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 105 106 separateTestJournal(); 107 putActivityInPrimarySplit(RESIZEABLE_ACTIVITY); 108 final SizeInfo dockedSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 109 110 assertSizesAreSane(fullscreenSizes, dockedSizes); 111 } 112 113 /** 114 * Same as {@link #testConfigurationUpdatesWhenResizedFromFullscreen()} but resizing 115 * from docked state to fullscreen (reverse). 116 */ 117 @Test testConfigurationUpdatesWhenResizedFromDockedStack()118 public void testConfigurationUpdatesWhenResizedFromDockedStack() { 119 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 120 121 separateTestJournal(); 122 launchActivitiesInSplitScreen( 123 getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY) 124 .setWindowingMode(WINDOWING_MODE_FULLSCREEN), 125 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY) 126 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)); 127 128 final SizeInfo dockedSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 129 130 separateTestJournal(); 131 dismissSplitScreen(true /* primaryOnTop */); 132 final SizeInfo fullscreenSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 133 134 assertSizesAreSane(fullscreenSizes, dockedSizes); 135 } 136 137 /** 138 * Tests whether the Display sizes change when rotating the device. 139 */ 140 @Test testConfigurationUpdatesWhenRotatingWhileFullscreen()141 public void testConfigurationUpdatesWhenRotatingWhileFullscreen() { 142 assumeTrue("Skipping test: no rotation support", supportsRotation()); 143 144 final RotationSession rotationSession = createManagedRotationSession(); 145 rotationSession.set(ROTATION_0); 146 147 separateTestJournal(); 148 final ActivitySessionClient resizeableActivityClient = createManagedActivityClientSession(); 149 resizeableActivityClient.startActivity(getLaunchActivityBuilder() 150 .setUseInstrumentation() 151 .setTargetActivity(RESIZEABLE_ACTIVITY) 152 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)); 153 final SizeInfo initialSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 154 155 rotateAndCheckSizes(rotationSession, resizeableActivityClient, initialSizes); 156 } 157 158 /** 159 * Same as {@link #testConfigurationUpdatesWhenRotatingWhileFullscreen()} but when the Activity 160 * is in the docked stack. 161 */ 162 @Test testConfigurationUpdatesWhenRotatingWhileDocked()163 public void testConfigurationUpdatesWhenRotatingWhileDocked() { 164 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 165 166 final ActivitySessionClient resizeableActivityClient = createManagedActivityClientSession(); 167 final RotationSession rotationSession = createManagedRotationSession(); 168 rotationSession.set(ROTATION_0); 169 170 separateTestJournal(); 171 // Launch our own activity to side in case Recents (or other activity to side) doesn't 172 // support rotation. 173 launchActivitiesInSplitScreen( 174 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY), 175 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 176 // Launch target activity in docked stack. 177 getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY) 178 .setActivitySessionClient(resizeableActivityClient).execute(); 179 final SizeInfo initialSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 180 181 rotateAndCheckSizes(rotationSession, resizeableActivityClient, initialSizes); 182 } 183 184 /** 185 * Same as {@link #testConfigurationUpdatesWhenRotatingWhileDocked()} but when the Activity 186 * is launched to side from docked stack. 187 */ 188 @Test testConfigurationUpdatesWhenRotatingToSideFromDocked()189 public void testConfigurationUpdatesWhenRotatingToSideFromDocked() { 190 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 191 192 final ActivitySessionClient resizeableActivityClient = createManagedActivityClientSession(); 193 final RotationSession rotationSession = createManagedRotationSession(); 194 rotationSession.set(ROTATION_0); 195 196 separateTestJournal(); 197 launchActivitiesInSplitScreen( 198 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY), 199 getLaunchActivityBuilder().setTargetActivity(RESIZEABLE_ACTIVITY) 200 .setActivitySessionClient(resizeableActivityClient)); 201 final SizeInfo initialSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 202 203 rotateAndCheckSizes(rotationSession, resizeableActivityClient, initialSizes); 204 } 205 rotateAndCheckSizes(RotationSession rotationSession, ActivitySessionClient noRelaunchActivityClient, SizeInfo prevSizes)206 private void rotateAndCheckSizes(RotationSession rotationSession, 207 ActivitySessionClient noRelaunchActivityClient, SizeInfo prevSizes) { 208 final ActivitySession activitySession = noRelaunchActivityClient.getLastStartedSession(); 209 final ComponentName activityName = activitySession.getName(); 210 final WindowManagerState.Task task = mWmState.getTaskByActivity(activityName); 211 final int displayId = mWmState.getRootTask(task.mRootTaskId).mDisplayId; 212 213 assumeTrue(supportsLockedUserRotation(rotationSession, displayId)); 214 215 final boolean isCloseToSquareDisplay = isCloseToSquareDisplay(); 216 final int[] rotations = { ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0 }; 217 for (final int rotation : rotations) { 218 separateTestJournal(); 219 rotationSession.set(rotation); 220 final int newDeviceRotation = getDeviceRotation(displayId); 221 if (newDeviceRotation == INVALID_DEVICE_ROTATION) { 222 logE("Got an invalid device rotation value. " 223 + "Continuing the test despite of that, but it is likely to fail."); 224 } 225 final boolean expectConfigChange = task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN 226 && !isCloseToSquareDisplay; 227 if (expectConfigChange) { 228 assertActivityLifecycle(activityName, false /* relaunch */); 229 } 230 final SizeInfo rotatedSizes = activitySession.getConfigInfo().sizeInfo; 231 assertSizesRotate(prevSizes, rotatedSizes, 232 // Skip orientation checks if we are not in fullscreen mode, or when the display 233 // is close to square because the app config orientation may always be landscape 234 // excluding the system insets. 235 !expectConfigChange /* skipOrientationCheck */); 236 prevSizes = rotatedSizes; 237 } 238 } 239 240 /** 241 * Tests when activity moved from fullscreen stack to docked and back. Activity will be 242 * relaunched twice and it should have same config as initial one. 243 */ 244 @Test testSameConfigurationFullSplitFullRelaunch()245 public void testSameConfigurationFullSplitFullRelaunch() { 246 moveActivityFullSplitFull(true /* relaunch */); 247 } 248 249 /** 250 * Same as {@link #testSameConfigurationFullSplitFullRelaunch} but without relaunch. 251 */ 252 @Test testSameConfigurationFullSplitFullNoRelaunch()253 public void testSameConfigurationFullSplitFullNoRelaunch() { 254 moveActivityFullSplitFull(false /* relaunch */); 255 } 256 257 /** 258 * Launches activity in fullscreen task, moves to docked task and back to fullscreen task. 259 * Asserts that initial and final reported sizes in fullscreen task are the same. 260 */ moveActivityFullSplitFull(boolean relaunch)261 private void moveActivityFullSplitFull(boolean relaunch) { 262 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 263 264 final ComponentName activityName = relaunch ? TEST_ACTIVITY : RESIZEABLE_ACTIVITY; 265 // Launch to fullscreen task and record size. 266 separateTestJournal(); 267 launchActivity(activityName, WINDOWING_MODE_FULLSCREEN); 268 final SizeInfo initialFullscreenSizes = getLastReportedSizesForActivity(activityName); 269 270 // Move the task to the primary split task. 271 separateTestJournal(); 272 putActivityInPrimarySplit(activityName); 273 // Currently launchActivityInPrimarySplit launches the target activity and then move it 274 // to split task, so it requires waiting of lifecycle to get the stable initial size. 275 if (relaunch) { 276 assertActivityLifecycle(activityName, true /* relaunch */); 277 } else { 278 // The lifecycle callbacks contain the initial launch event so only wait for 279 // multi-window mode changed. 280 waitForOnMultiWindowModeChanged(activityName); 281 } 282 final SizeInfo dockedSizes = getLastReportedSizesForActivity(activityName); 283 assertSizesAreSane(initialFullscreenSizes, dockedSizes); 284 285 // Restore to fullscreen. 286 separateTestJournal(); 287 mTaskOrganizer.dismissSplitScreen(); 288 // Home task could be on top since it was the top-most task while in split-screen mode 289 // (dock task was minimized), start the activity again to ensure the activity is at 290 // foreground. 291 launchActivity(activityName, WINDOWING_MODE_FULLSCREEN); 292 assertActivityLifecycle(activityName, relaunch); 293 final SizeInfo finalFullscreenSizes = getLastReportedSizesForActivity(activityName); 294 295 // After activity configuration was changed twice it must report same size as original one. 296 assertSizesAreSame(initialFullscreenSizes, finalFullscreenSizes); 297 } 298 299 /** 300 * Tests that an activity with the DialogWhenLarge theme can transform properly when in split 301 * screen. 302 */ 303 @Test testDialogWhenLargeSplitSmall()304 public void testDialogWhenLargeSplitSmall() { 305 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 306 307 launchActivitiesInSplitScreen( 308 getLaunchActivityBuilder().setTargetActivity(DIALOG_WHEN_LARGE_ACTIVITY), 309 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); 310 int displayId = mWmState.getDisplayByActivity(DIALOG_WHEN_LARGE_ACTIVITY); 311 final WindowManagerState.DisplayContent display = mWmState.getDisplay(displayId); 312 final int density = display.getDpi(); 313 final int smallWidthPx = dpToPx(SMALL_WIDTH_DP, density); 314 final int smallHeightPx = dpToPx(SMALL_HEIGHT_DP, density); 315 316 mTaskOrganizer.setRootPrimaryTaskBounds(new Rect(0, 0, smallWidthPx, smallHeightPx)); 317 mWmState.waitForValidState( 318 new WaitForValidActivityState.Builder(DIALOG_WHEN_LARGE_ACTIVITY) 319 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW) 320 .setActivityType(ACTIVITY_TYPE_STANDARD) 321 .build()); 322 } 323 324 /** 325 * Test that device handles consequent requested orientations and displays the activities. 326 */ 327 @Test testFullscreenAppOrientationRequests()328 public void testFullscreenAppOrientationRequests() { 329 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 330 331 separateTestJournal(); 332 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY); 333 mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */); 334 SizeInfo reportedSizes = getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY); 335 assertEquals("portrait activity should be in portrait", 336 ORIENTATION_PORTRAIT, reportedSizes.orientation); 337 assertTrue("portrait activity should have height >= width", 338 reportedSizes.heightDp >= reportedSizes.widthDp); 339 separateTestJournal(); 340 341 launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY); 342 mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */); 343 reportedSizes = getLastReportedSizesForActivity(LANDSCAPE_ORIENTATION_ACTIVITY); 344 assertEquals("landscape activity should be in landscape", 345 ORIENTATION_LANDSCAPE, reportedSizes.orientation); 346 assertTrue("landscape activity should have height < width", 347 reportedSizes.heightDp < reportedSizes.widthDp); 348 separateTestJournal(); 349 350 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY); 351 mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */); 352 reportedSizes = getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY); 353 assertEquals("portrait activity should be in portrait", 354 ORIENTATION_PORTRAIT, reportedSizes.orientation); 355 } 356 357 @Test testTranslucentAppOrientationRequests()358 public void testTranslucentAppOrientationRequests() { 359 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 360 361 separateTestJournal(); 362 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 363 final SizeInfo initialReportedSizes = 364 getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY); 365 assertEquals("portrait activity should be in portrait", 366 ORIENTATION_PORTRAIT, initialReportedSizes.orientation); 367 assertTrue("portrait activity should have height >= width", 368 initialReportedSizes.heightDp >= initialReportedSizes.widthDp); 369 separateTestJournal(); 370 371 launchActivity(SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 372 assertEquals("Legacy translucent activity requested landscape orientation", 373 SCREEN_ORIENTATION_LANDSCAPE, mWmState.getLastOrientation()); 374 375 // TODO(b/36897968): uncomment once we can suppress unsupported configurations 376 // final ReportedSizes updatedReportedSizes = 377 // getLastReportedSizesForActivity(PORTRAIT_ACTIVITY_NAME, logSeparator); 378 // assertEquals("portrait activity should not have moved from portrait", 379 // 1 /* portrait */, updatedReportedSizes.orientation); 380 } 381 382 /** 383 * Test that device handles consequent requested orientations and will not report a config 384 * change to an invisible activity. 385 */ 386 @Test testAppOrientationRequestConfigChanges()387 public void testAppOrientationRequestConfigChanges() { 388 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 389 390 separateTestJournal(); 391 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 392 mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */); 393 394 assertLifecycleCounts(PORTRAIT_ORIENTATION_ACTIVITY, 395 1 /* create */, 1 /* start */, 1 /* resume */, 396 0 /* pause */, 0 /* stop */, 0 /* destroy */, 0 /* config */); 397 398 launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 399 mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */); 400 401 assertLifecycleCounts(PORTRAIT_ORIENTATION_ACTIVITY, 402 1 /* create */, 1 /* start */, 1 /* resume */, 403 1 /* pause */, 1 /* stop */, 0 /* destroy */, 0 /* config */); 404 assertLifecycleCounts(LANDSCAPE_ORIENTATION_ACTIVITY, 405 1 /* create */, 1 /* start */, 1 /* resume */, 406 0 /* pause */, 0 /* stop */, 0 /* destroy */, 0 /* config */); 407 408 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 409 mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */); 410 411 assertLifecycleCounts(PORTRAIT_ORIENTATION_ACTIVITY, 412 2 /* create */, 2 /* start */, 2 /* resume */, 413 1 /* pause */, 1 /* stop */, 0 /* destroy */, 0 /* config */); 414 assertLifecycleCounts(LANDSCAPE_ORIENTATION_ACTIVITY, 415 1 /* create */, 1 /* start */, 1 /* resume */, 416 1 /* pause */, 1 /* stop */, 0 /* destroy */, 0 /* config */); 417 } 418 419 /** 420 * Test that device orientation is restored when an activity that requests it is no longer 421 * visible. 422 * 423 * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has 424 * rotation sensing optimization. So this is listed in cts-known-failures.xml. 425 */ 426 @Test testAppOrientationRequestConfigClears()427 public void testAppOrientationRequestConfigClears() { 428 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 429 430 separateTestJournal(); 431 launchActivity(TEST_ACTIVITY); 432 mWmState.assertVisibility(TEST_ACTIVITY, true /* visible */); 433 final SizeInfo initialReportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY); 434 final int initialOrientation = initialReportedSizes.orientation; 435 436 // Launch an activity that requests different orientation and check that it will be applied 437 final boolean launchingPortrait; 438 if (initialOrientation == ORIENTATION_LANDSCAPE) { 439 launchingPortrait = true; 440 } else if (initialOrientation == ORIENTATION_PORTRAIT) { 441 launchingPortrait = false; 442 } else { 443 fail("Unexpected orientation value: " + initialOrientation); 444 return; 445 } 446 final ComponentName differentOrientationActivity = launchingPortrait 447 ? PORTRAIT_ORIENTATION_ACTIVITY : LANDSCAPE_ORIENTATION_ACTIVITY; 448 separateTestJournal(); 449 launchActivity(differentOrientationActivity); 450 mWmState.assertVisibility(differentOrientationActivity, true /* visible */); 451 final SizeInfo rotatedReportedSizes = 452 getLastReportedSizesForActivity(differentOrientationActivity); 453 assertEquals("Applied orientation must correspond to activity request", 454 launchingPortrait ? 1 : 2, rotatedReportedSizes.orientation); 455 456 // Launch another activity on top and check that its orientation is not affected by previous 457 // activity. 458 separateTestJournal(); 459 launchActivity(RESIZEABLE_ACTIVITY); 460 mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */); 461 final SizeInfo finalReportedSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 462 assertEquals("Applied orientation must not be influenced by previously visible activity", 463 initialOrientation, finalReportedSizes.orientation); 464 } 465 466 @Test testRotatedInfoWithFixedRotationTransform()467 public void testRotatedInfoWithFixedRotationTransform() { 468 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 469 470 // Start a portrait activity first to ensure that the orientation will change. 471 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY); 472 mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT); 473 474 getLaunchActivityBuilder() 475 .setUseInstrumentation() 476 .setTargetActivity(LANDSCAPE_ORIENTATION_ACTIVITY) 477 // Request the info from onCreate because at that moment the real display hasn't 478 // rotated but the activity is rotated. 479 .setIntentExtra(bundle -> bundle.putBoolean(EXTRA_CONFIG_INFO_IN_ON_CREATE, true)) 480 .execute(); 481 mWmState.waitForLastOrientation(SCREEN_ORIENTATION_LANDSCAPE); 482 483 final SizeInfo reportedSizes = 484 getLastReportedSizesForActivity(LANDSCAPE_ORIENTATION_ACTIVITY); 485 final Bundle extras = TestJournalContainer.get(LANDSCAPE_ORIENTATION_ACTIVITY).extras; 486 final ConfigInfo appConfigInfo = extras.getParcelable(EXTRA_APP_CONFIG_INFO); 487 final Point onCreateRealDisplaySize = extras.getParcelable(EXTRA_DISPLAY_REAL_SIZE); 488 final ConfigInfo onCreateConfigInfo = extras.getParcelable(EXTRA_CONFIG_INFO_IN_ON_CREATE); 489 final SizeInfo onCreateSize = onCreateConfigInfo.sizeInfo; 490 final ConfigInfo globalConfigInfo = 491 extras.getParcelable(EXTRA_SYSTEM_RESOURCES_CONFIG_INFO); 492 final SizeInfo globalSizeInfo = globalConfigInfo.sizeInfo; 493 494 assertEquals("The last reported size should be the same as the one from onCreate", 495 reportedSizes, onCreateConfigInfo.sizeInfo); 496 497 final Display display = mDm.getDisplay(Display.DEFAULT_DISPLAY); 498 final Point expectedRealDisplaySize = new Point(); 499 display.getRealSize(expectedRealDisplaySize); 500 501 final int expectedRotation = display.getRotation(); 502 assertEquals("The activity should get the final display rotation in onCreate", 503 expectedRotation, onCreateConfigInfo.rotation); 504 assertEquals("The application should get the final display rotation in onCreate", 505 expectedRotation, appConfigInfo.rotation); 506 assertEquals("The orientation of application must be landscape", 507 ORIENTATION_LANDSCAPE, appConfigInfo.sizeInfo.orientation); 508 assertEquals("The orientation of system resources must be landscape", 509 ORIENTATION_LANDSCAPE, globalSizeInfo.orientation); 510 assertEquals("The activity should get the final display size in onCreate", 511 expectedRealDisplaySize, onCreateRealDisplaySize); 512 513 final boolean isLandscape = expectedRealDisplaySize.x > expectedRealDisplaySize.y; 514 assertEquals("The app size of activity should have the same orientation", isLandscape, 515 onCreateSize.displayWidth > onCreateSize.displayHeight); 516 assertEquals("The application should get the same orientation", isLandscape, 517 appConfigInfo.sizeInfo.displayWidth > appConfigInfo.sizeInfo.displayHeight); 518 assertEquals("The app display metrics must be landscape", isLandscape, 519 appConfigInfo.sizeInfo.metricsWidth > appConfigInfo.sizeInfo.metricsHeight); 520 521 final DisplayMetrics globalMetrics = Resources.getSystem().getDisplayMetrics(); 522 assertEquals("The display metrics of system resources must be landscape", 523 new Point(globalMetrics.widthPixels, globalMetrics.heightPixels), 524 new Point(globalSizeInfo.metricsWidth, globalSizeInfo.metricsHeight)); 525 } 526 527 @Test testTranslucentActivityPermitted()528 public void testTranslucentActivityPermitted() throws Exception { 529 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 530 531 final RotationSession rotationSession = createManagedRotationSession(); 532 rotationSession.set(ROTATION_0); 533 534 launchActivity(SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 535 mWmState.assertResumedActivity( 536 "target SDK <= 26 translucent activity should be allowed to launch", 537 SDK26_TRANSLUCENT_LANDSCAPE_ACTIVITY); 538 assertEquals("translucent activity requested landscape orientation", 539 SCREEN_ORIENTATION_LANDSCAPE, mWmState.getLastOrientation()); 540 } 541 542 /** 543 * Test that device handles moving between two tasks with different orientations. 544 */ 545 @Test testTaskCloseRestoreFixedOrientation()546 public void testTaskCloseRestoreFixedOrientation() { 547 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 548 549 // Start landscape activity. 550 launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 551 mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */); 552 mWmState.waitAndAssertLastOrientation("Fullscreen app requested landscape orientation", 553 SCREEN_ORIENTATION_LANDSCAPE); 554 555 // Start another activity in a different task. 556 launchActivityInNewTask(BROADCAST_RECEIVER_ACTIVITY); 557 558 // Request portrait 559 mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_PORTRAIT); 560 mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT); 561 waitForBroadcastActivityReady(ORIENTATION_PORTRAIT); 562 563 // Finish activity 564 mBroadcastActionTrigger.finishBroadcastReceiverActivity(); 565 566 // Verify that activity brought to front is in originally requested orientation. 567 mWmState.computeState(LANDSCAPE_ORIENTATION_ACTIVITY); 568 mWmState.waitAndAssertLastOrientation("Should return to app in landscape orientation", 569 SCREEN_ORIENTATION_LANDSCAPE); 570 } 571 572 /** 573 * Test that device handles moving between two tasks with different orientations. 574 * 575 * TODO(b/139936670, b/112688380): This test case fails on some vendor devices which has 576 * rotation sensing optimization. So this is listed in cts-known-failures.xml. 577 */ 578 @Test testTaskCloseRestoreFreeOrientation()579 public void testTaskCloseRestoreFreeOrientation() { 580 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 581 582 // Start landscape activity. 583 launchActivity(RESIZEABLE_ACTIVITY); 584 mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */); 585 final int initialServerOrientation = mWmState.getLastOrientation(); 586 587 // Verify fixed-landscape 588 separateTestJournal(); 589 launchActivityInNewTask(BROADCAST_RECEIVER_ACTIVITY); 590 mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_LANDSCAPE); 591 mWmState.waitForLastOrientation(SCREEN_ORIENTATION_LANDSCAPE); 592 waitForBroadcastActivityReady(ORIENTATION_LANDSCAPE); 593 mBroadcastActionTrigger.finishBroadcastReceiverActivity(); 594 595 // Verify that activity brought to front is in originally requested orientation. 596 mWmState.waitForActivityState(RESIZEABLE_ACTIVITY, STATE_RESUMED); 597 mWmState.waitAndAssertLastOrientation("Should come back in original server orientation", 598 initialServerOrientation); 599 assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY, 0 /* numRelaunch */, 600 0 /* numConfigChange */); 601 602 // Verify fixed-portrait 603 separateTestJournal(); 604 launchActivityInNewTask(BROADCAST_RECEIVER_ACTIVITY); 605 mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_PORTRAIT); 606 mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT); 607 waitForBroadcastActivityReady(ORIENTATION_PORTRAIT); 608 mBroadcastActionTrigger.finishBroadcastReceiverActivity(); 609 610 // Verify that activity brought to front is in originally requested orientation. 611 mWmState.waitForActivityState(RESIZEABLE_ACTIVITY, STATE_RESUMED); 612 mWmState.waitAndAssertLastOrientation("Should come back in original server orientation", 613 initialServerOrientation); 614 assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY, 0 /* numRelaunch */, 615 0 /* numConfigChange */); 616 } 617 618 /** 619 * Test that activity orientation will change when device is rotated. 620 * Also verify that occluded activity will not get config changes. 621 */ 622 @Test testAppOrientationWhenRotating()623 public void testAppOrientationWhenRotating() throws Exception { 624 assumeTrue("Skipping test: no rotation support", supportsRotation()); 625 626 // Start resizeable activity that handles configuration changes. 627 separateTestJournal(); 628 launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 629 launchActivity(RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 630 mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */); 631 632 final int displayId = mWmState.getDisplayByActivity(RESIZEABLE_ACTIVITY); 633 634 // Rotate the activity and check that it receives configuration changes with a different 635 // orientation each time. 636 final RotationSession rotationSession = createManagedRotationSession(); 637 assumeTrue("Skipping test: no locked user rotation mode support.", 638 supportsLockedUserRotation(rotationSession, displayId)); 639 640 rotationSession.set(ROTATION_0); 641 SizeInfo reportedSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 642 int prevOrientation = reportedSizes.orientation; 643 644 final int[] rotations = { ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0 }; 645 for (final int rotation : rotations) { 646 separateTestJournal(); 647 rotationSession.set(rotation); 648 649 // Verify lifecycle count and orientation changes. 650 assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY, 0 /* numRelaunch */, 651 1 /* numConfigChange */); 652 reportedSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 653 assertNotEquals(prevOrientation, reportedSizes.orientation); 654 assertRelaunchOrConfigChanged(TEST_ACTIVITY, 0 /* numRelaunch */, 655 0 /* numConfigChange */); 656 657 prevOrientation = reportedSizes.orientation; 658 } 659 } 660 661 /** 662 * Test that the orientation for a simulated display context derived from an application context 663 * will not change when the device rotates. 664 */ 665 @Test testAppContextDerivedDisplayContextOrientationWhenRotating()666 public void testAppContextDerivedDisplayContextOrientationWhenRotating() { 667 assumeTrue("Skipping test: no rotation support", supportsRotation()); 668 assumeTrue("Skipping test: no multi-display support", supportsMultiDisplay()); 669 670 assertDisplayContextDoesntChangeOrientationWhenRotating(Activity::getApplicationContext); 671 } 672 673 /** 674 * Test that the orientation for a simulated display context derived from an activity context 675 * will not change when the device rotates. 676 */ 677 @Test testActivityContextDerivedDisplayContextOrientationWhenRotating()678 public void testActivityContextDerivedDisplayContextOrientationWhenRotating() { 679 assumeTrue("Skipping test: no rotation support", supportsRotation()); 680 assumeTrue("Skipping test: no multi-display support", supportsMultiDisplay()); 681 682 assertDisplayContextDoesntChangeOrientationWhenRotating(activity -> activity); 683 } 684 685 /** 686 * Asserts that the orientation for a simulated display context derived from a base context will 687 * not change when the device rotates. 688 * 689 * @param baseContextSupplier function that returns a base context used to created the display 690 * context. 691 * 692 * @see #testAppContextDerivedDisplayContextOrientationWhenRotating 693 * @see #testActivityContextDerivedDisplayContextOrientationWhenRotating 694 */ assertDisplayContextDoesntChangeOrientationWhenRotating( Function<Activity, Context> baseContextSupplier)695 private void assertDisplayContextDoesntChangeOrientationWhenRotating( 696 Function<Activity, Context> baseContextSupplier) { 697 RotationSession rotationSession = createManagedRotationSession(); 698 rotationSession.set(ROTATION_0); 699 700 TestActivitySession<ConfigChangeHandlingActivity> activitySession 701 = createManagedTestActivitySession(); 702 activitySession.launchTestActivityOnDisplaySync( 703 ConfigChangeHandlingActivity.class, 704 Display.DEFAULT_DISPLAY, 705 WINDOWING_MODE_FULLSCREEN); 706 final ConfigChangeHandlingActivity activity = activitySession.getActivity(); 707 708 VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession(); 709 WindowManagerState.DisplayContent displayContent = virtualDisplaySession 710 .setSimulateDisplay(true) 711 .setSimulationDisplaySize(100 /* width */, 200 /* height */) 712 .createDisplay(); 713 714 DisplayManager dm = activity.getSystemService(DisplayManager.class); 715 Display simulatedDisplay = dm.getDisplay(displayContent.mId); 716 Context simulatedDisplayContext = baseContextSupplier.apply(activity) 717 .createDisplayContext(simulatedDisplay); 718 assertEquals(ORIENTATION_PORTRAIT, 719 simulatedDisplayContext.getResources().getConfiguration().orientation); 720 721 separateTestJournal(); 722 723 final int[] rotations = {ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0}; 724 for (final int rotation : rotations) { 725 rotationSession.set(rotation); 726 727 assertRelaunchOrConfigChanged(activity.getComponentName(), 0 /* numRelaunch */, 728 1 /* numConfigChange */); 729 separateTestJournal(); 730 731 assertEquals("Display context orientation must not be changed", ORIENTATION_PORTRAIT, 732 simulatedDisplayContext.getResources().getConfiguration().orientation); 733 } 734 } 735 736 /** 737 * Test that activity orientation will not change when trying to rotate fixed-orientation 738 * activity. 739 * Also verify that occluded activity will not get config changes. 740 */ 741 @Test testFixedOrientationWhenRotating()742 public void testFixedOrientationWhenRotating() { 743 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 744 // TODO(b/110533226): Fix test on devices with display cutout 745 assumeFalse("Skipping test: display cutout present, can't predict exact lifecycle", 746 hasDisplayCutout()); 747 748 // Start portrait-fixed activity 749 separateTestJournal(); 750 final ActivitySession activitySession = createManagedActivityClientSession() 751 .startActivity(getLaunchActivityBuilder() 752 .setUseInstrumentation() 753 .setWindowingMode(WINDOWING_MODE_FULLSCREEN) 754 .setTargetActivity(RESIZEABLE_ACTIVITY)); 755 mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */); 756 757 final int displayId = mWmState.getDisplayByActivity(RESIZEABLE_ACTIVITY); 758 759 final RotationSession rotationSession = createManagedRotationSession(); 760 assumeTrue("Skipping test: no user locked rotation support.", 761 supportsLockedUserRotation(rotationSession, displayId)); 762 763 launchActivity(PORTRAIT_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 764 mWmState.assertVisibility(PORTRAIT_ORIENTATION_ACTIVITY, true /* visible */); 765 final SizeInfo initialSize = getLastReportedSizesForActivity(PORTRAIT_ORIENTATION_ACTIVITY); 766 767 // Rotate the display and check that the orientation doesn't change 768 rotationSession.set(ROTATION_0); 769 final int[] rotations = { ROTATION_270, ROTATION_180, ROTATION_90, ROTATION_0 }; 770 for (final int rotation : rotations) { 771 separateTestJournal(); 772 rotationSession.set(rotation, false /* waitDeviceRotation */); 773 774 // Verify lifecycle count and orientation changes. 775 assertRelaunchOrConfigChanged(PORTRAIT_ORIENTATION_ACTIVITY, 0 /* numRelaunch */, 776 0 /* numConfigChange */); 777 final SizeInfo currentSize = activitySession.getConfigInfo().sizeInfo; 778 assertEquals("Sizes must not be changed", initialSize, currentSize); 779 assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY, 0 /* numRelaunch */, 780 0 /* numConfigChange */); 781 } 782 } 783 784 /** 785 * Test that device handles moving between two tasks with different orientations. 786 */ 787 @Test testTaskMoveToBackOrientation()788 public void testTaskMoveToBackOrientation() { 789 assumeTrue("Skipping test: no orientation request support", supportsOrientationRequest()); 790 791 // Start landscape activity. 792 launchActivity(LANDSCAPE_ORIENTATION_ACTIVITY, WINDOWING_MODE_FULLSCREEN); 793 mWmState.assertVisibility(LANDSCAPE_ORIENTATION_ACTIVITY, true /* visible */); 794 mWmState.waitAndAssertLastOrientation("Fullscreen app requested landscape orientation", 795 SCREEN_ORIENTATION_LANDSCAPE); 796 797 // Start another activity in a different task. 798 launchActivityInNewTask(BROADCAST_RECEIVER_ACTIVITY); 799 800 // Request portrait 801 mBroadcastActionTrigger.requestOrientation(SCREEN_ORIENTATION_PORTRAIT); 802 mWmState.waitForLastOrientation(SCREEN_ORIENTATION_PORTRAIT); 803 waitForBroadcastActivityReady(ORIENTATION_PORTRAIT); 804 805 // Finish activity 806 mBroadcastActionTrigger.moveTopTaskToBack(); 807 808 // Verify that activity brought to front is in originally requested orientation. 809 mWmState.waitForValidState(LANDSCAPE_ORIENTATION_ACTIVITY); 810 mWmState.waitAndAssertLastOrientation("Should return to app in landscape orientation", 811 SCREEN_ORIENTATION_LANDSCAPE); 812 } 813 814 /** 815 * Test that device doesn't change device orientation by app request while in multi-window. 816 */ 817 @Test testSplitscreenPortraitAppOrientationRequests()818 public void testSplitscreenPortraitAppOrientationRequests() throws Exception { 819 requestOrientationInSplitScreen(createManagedRotationSession(), 820 isDisplayPortrait() ? ROTATION_0 : ROTATION_90, LANDSCAPE_ORIENTATION_ACTIVITY); 821 } 822 823 /** 824 * Test that device doesn't change device orientation by app request while in multi-window. 825 */ 826 @Test testSplitscreenLandscapeAppOrientationRequests()827 public void testSplitscreenLandscapeAppOrientationRequests() throws Exception { 828 requestOrientationInSplitScreen(createManagedRotationSession(), 829 isDisplayPortrait() ? ROTATION_90 : ROTATION_0, PORTRAIT_ORIENTATION_ACTIVITY); 830 } 831 832 /** 833 * Launch specified activity in split-screen then rotate the divice, checking orientation 834 * should always change by the device rotation. 835 */ requestOrientationInSplitScreen(RotationSession rotationSession, int rotation, ComponentName activity)836 private void requestOrientationInSplitScreen(RotationSession rotationSession, int rotation, 837 ComponentName activity) throws Exception { 838 assumeTrue("Skipping test: no rotation support", supportsRotation()); 839 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 840 841 // Launch activities in split screen. 842 launchActivitiesInSplitScreen( 843 getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY), 844 getLaunchActivityBuilder().setTargetActivity(activity)); 845 mWmState.assertVisibility(activity, true /* visible */); 846 847 // Rotate the device and it should always rotate regardless orientation app requested. 848 rotationSession.set(rotation); 849 assertEquals("Split-screen apps shouldn't influence device orientation", 850 rotation, mWmState.getRotation()); 851 852 // Launch target activity during split-screen again and check orientation still not change. 853 mTaskOrganizer.setLaunchRoot(mTaskOrganizer.getSecondarySplitTaskId()); 854 getLaunchActivityBuilder().setMultipleTask(true).setTargetActivity(activity).execute(); 855 mWmState.computeState(activity); 856 mWmState.assertVisibility(activity, true /* visible */); 857 assertEquals("Split-screen apps shouldn't influence device orientation", 858 rotation, mWmState.getRotation()); 859 } 860 861 /** 862 * Asserts that after rotation, the aspect ratios of display size, metrics, and configuration 863 * have flipped. 864 */ assertSizesRotate(SizeInfo rotationA, SizeInfo rotationB, boolean skipOrientationCheck)865 private static void assertSizesRotate(SizeInfo rotationA, SizeInfo rotationB, 866 boolean skipOrientationCheck) { 867 assertEquals(rotationA.displayWidth, rotationA.metricsWidth); 868 assertEquals(rotationA.displayHeight, rotationA.metricsHeight); 869 assertEquals(rotationB.displayWidth, rotationB.metricsWidth); 870 assertEquals(rotationB.displayHeight, rotationB.metricsHeight); 871 872 if (skipOrientationCheck) { 873 // All done if we are not doing orientation check. 874 return; 875 } 876 final boolean beforePortrait = rotationA.displayWidth < rotationA.displayHeight; 877 final boolean afterPortrait = rotationB.displayWidth < rotationB.displayHeight; 878 assertFalse(beforePortrait == afterPortrait); 879 880 final boolean beforeConfigPortrait = rotationA.widthDp < rotationA.heightDp; 881 final boolean afterConfigPortrait = rotationB.widthDp < rotationB.heightDp; 882 assertEquals(beforePortrait, beforeConfigPortrait); 883 assertEquals(afterPortrait, afterConfigPortrait); 884 885 assertEquals(rotationA.smallestWidthDp, rotationB.smallestWidthDp); 886 } 887 888 /** 889 * Throws an AssertionError if fullscreenSizes has widths/heights (depending on aspect ratio) 890 * that are smaller than the dockedSizes. 891 */ 892 private static void assertSizesAreSane(SizeInfo fullscreenSizes, SizeInfo dockedSizes) { 893 final boolean isHorizontalDivision = 894 fullscreenSizes.displayHeight - dockedSizes.displayHeight > 895 fullscreenSizes.displayWidth - dockedSizes.displayWidth; 896 if (isHorizontalDivision) { 897 assertThat(dockedSizes.displayHeight, lessThan(fullscreenSizes.displayHeight)); 898 assertThat(dockedSizes.heightDp, lessThan(fullscreenSizes.heightDp)); 899 assertThat(dockedSizes.metricsHeight, lessThan(fullscreenSizes.metricsHeight)); 900 } else { 901 assertThat(dockedSizes.displayWidth, lessThan(fullscreenSizes.displayWidth)); 902 assertThat(dockedSizes.widthDp, lessThan(fullscreenSizes.widthDp)); 903 assertThat(dockedSizes.metricsWidth, lessThan(fullscreenSizes.metricsWidth)); 904 } 905 } 906 907 /** 908 * Throws an AssertionError if sizes are different. 909 */ 910 private static void assertSizesAreSame(SizeInfo firstSize, SizeInfo secondSize) { 911 assertEquals(firstSize.widthDp, secondSize.widthDp); 912 assertEquals(firstSize.heightDp, secondSize.heightDp); 913 assertEquals(firstSize.displayWidth, secondSize.displayWidth); 914 assertEquals(firstSize.displayHeight, secondSize.displayHeight); 915 assertEquals(firstSize.metricsWidth, secondSize.metricsWidth); 916 assertEquals(firstSize.metricsHeight, secondSize.metricsHeight); 917 assertEquals(firstSize.smallestWidthDp, secondSize.smallestWidthDp); 918 } 919 920 private void waitForBroadcastActivityReady(int orientation) { 921 mWmState.waitForActivityOrientation(BROADCAST_RECEIVER_ACTIVITY, orientation); 922 mWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED); 923 } 924 925 /** 926 * Test launching an activity which requests specific UI mode during creation. 927 */ 928 @Test 929 public void testLaunchWithUiModeChange() { 930 // Launch activity that changes UI mode and handles this configuration change. 931 launchActivity(NIGHT_MODE_ACTIVITY); 932 mWmState.waitForActivityState(NIGHT_MODE_ACTIVITY, STATE_RESUMED); 933 934 // Check if activity is launched successfully. 935 mWmState.assertVisibility(NIGHT_MODE_ACTIVITY, true /* visible */); 936 mWmState.assertFocusedActivity("Launched activity should be focused", 937 NIGHT_MODE_ACTIVITY); 938 mWmState.assertResumedActivity("Launched activity must be resumed", NIGHT_MODE_ACTIVITY); 939 } 940 941 @Test 942 public void testAppConfigurationMatchesActivityInMultiWindow() throws Exception { 943 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 944 945 final ActivitySession activitySession = createManagedActivityClientSession() 946 .startActivity(getLaunchActivityBuilder() 947 .setUseInstrumentation() 948 .setTargetActivity(RESIZEABLE_ACTIVITY) 949 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)); 950 putActivityInPrimarySplit(RESIZEABLE_ACTIVITY); 951 SizeInfo dockedActivitySizes = getActivitySizeInfo(activitySession); 952 SizeInfo applicationSizes = getAppSizeInfo(activitySession); 953 assertSizesAreSame(dockedActivitySizes, applicationSizes); 954 955 // Move the activity to fullscreen and check that the size was updated 956 separateTestJournal(); 957 mTaskOrganizer.dismissSplitScreen(true /* primaryOnTop */); 958 waitForOrFail("Activity and application configuration must match", 959 () -> activityAndAppSizesMatch(activitySession)); 960 final SizeInfo fullscreenSizes = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY); 961 applicationSizes = getAppSizeInfo(activitySession); 962 assertSizesAreSane(fullscreenSizes, dockedActivitySizes); 963 assertSizesAreSame(fullscreenSizes, applicationSizes); 964 965 // Move the activity to docked size again, check if the sizes were updated 966 separateTestJournal(); 967 putActivityInPrimarySplit(RESIZEABLE_ACTIVITY); 968 waitForOrFail("Activity and application configuration must match", 969 () -> activityAndAppSizesMatch(activitySession)); 970 dockedActivitySizes = getActivitySizeInfo(activitySession); 971 applicationSizes = getAppSizeInfo(activitySession); 972 assertSizesAreSane(fullscreenSizes, dockedActivitySizes); 973 assertSizesAreSame(dockedActivitySizes, applicationSizes); 974 } 975 976 @Test 977 public void testAppConfigurationMatchesTopActivityInMultiWindow() throws Exception { 978 assumeTrue("Skipping test: no multi-window support", supportsSplitScreenMultiWindow()); 979 980 // Launch initial activity in fullscreen and assert sizes 981 final ActivitySession fullscreenActivitySession = createManagedActivityClientSession() 982 .startActivity(getLaunchActivityBuilder() 983 .setUseInstrumentation() 984 .setTargetActivity(TEST_ACTIVITY) 985 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)); 986 SizeInfo fullscreenActivitySizes = getActivitySizeInfo(fullscreenActivitySession); 987 SizeInfo applicationSizes = getAppSizeInfo(fullscreenActivitySession); 988 assertSizesAreSame(fullscreenActivitySizes, applicationSizes); 989 990 // Launch second activity in split-screen and assert that sizes were updated 991 separateTestJournal(); 992 final ActivitySession secondActivitySession = createManagedActivityClientSession() 993 .startActivity(getLaunchActivityBuilder() 994 .setUseInstrumentation() 995 .setTargetActivity(RESIZEABLE_ACTIVITY) 996 .setNewTask(true) 997 .setMultipleTask(true)); 998 putActivityInPrimarySplit(RESIZEABLE_ACTIVITY); 999 waitForOrFail("Activity and application configuration must match", 1000 () -> activityAndAppSizesMatch(secondActivitySession)); 1001 SizeInfo dockedActivitySizes = getActivitySizeInfo(secondActivitySession); 1002 applicationSizes = getAppSizeInfo(secondActivitySession); 1003 assertSizesAreSame(dockedActivitySizes, applicationSizes); 1004 assertSizesAreSane(fullscreenActivitySizes, dockedActivitySizes); 1005 1006 // Launch third activity in secondary split-screen and assert that sizes were updated 1007 separateTestJournal(); 1008 final ActivitySession thirdActivitySession = createManagedActivityClientSession() 1009 .startActivity(getLaunchActivityBuilder() 1010 .setUseInstrumentation() 1011 .setTargetActivity(RESIZEABLE_ACTIVITY) 1012 .setNewTask(true) 1013 .setMultipleTask(true)); 1014 putActivityInPrimarySplit(RESIZEABLE_ACTIVITY); 1015 waitForOrFail("Activity and application configuration must match", 1016 () -> activityAndAppSizesMatch(thirdActivitySession)); 1017 SizeInfo secondarySplitActivitySizes = getActivitySizeInfo(thirdActivitySession); 1018 applicationSizes = getAppSizeInfo(thirdActivitySession); 1019 assertSizesAreSame(secondarySplitActivitySizes, applicationSizes); 1020 assertSizesAreSane(fullscreenActivitySizes, secondarySplitActivitySizes); 1021 } 1022 1023 @Test testAppConfigurationMatchesActivityInFreeform()1024 public void testAppConfigurationMatchesActivityInFreeform() throws Exception { 1025 assumeTrue("Skipping test: no freeform support", supportsFreeform()); 1026 1027 // Launch activity in freeform and assert sizes 1028 final ActivitySession freeformActivitySession = createManagedActivityClientSession() 1029 .startActivity(getLaunchActivityBuilder() 1030 .setUseInstrumentation() 1031 .setTargetActivity(TEST_ACTIVITY) 1032 .setWindowingMode(WINDOWING_MODE_FREEFORM)); 1033 SizeInfo freeformActivitySizes = getActivitySizeInfo(freeformActivitySession); 1034 SizeInfo applicationSizes = getAppSizeInfo(freeformActivitySession); 1035 assertSizesAreSame(freeformActivitySizes, applicationSizes); 1036 } 1037 activityAndAppSizesMatch(ActivitySession activitySession)1038 private boolean activityAndAppSizesMatch(ActivitySession activitySession) { 1039 final SizeInfo activitySize = activitySession.getConfigInfo().sizeInfo; 1040 final SizeInfo appSize = activitySession.getAppConfigInfo().sizeInfo; 1041 return activitySize.equals(appSize); 1042 } 1043 getActivitySizeInfo(ActivitySession activitySession)1044 private SizeInfo getActivitySizeInfo(ActivitySession activitySession) { 1045 return activitySession.getConfigInfo().sizeInfo; 1046 } 1047 getAppSizeInfo(ActivitySession activitySession)1048 private SizeInfo getAppSizeInfo(ActivitySession activitySession) { 1049 return activitySession.getAppConfigInfo().sizeInfo; 1050 } 1051 } 1052