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