1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.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.app.WindowConfiguration.WINDOWING_MODE_PINNED; 24 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 25 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 26 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 27 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 28 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 29 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 30 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 31 import static android.provider.DeviceConfig.NAMESPACE_CONSTRAIN_DISPLAY_APIS; 32 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; 33 import static android.view.InsetsState.ITYPE_STATUS_BAR; 34 import static android.view.Surface.ROTATION_0; 35 import static android.view.Surface.ROTATION_180; 36 import static android.view.Surface.ROTATION_270; 37 import static android.view.Surface.ROTATION_90; 38 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 39 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 40 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 41 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 42 43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 46 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 47 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; 48 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 49 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 50 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO; 51 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION; 52 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE; 53 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED; 54 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE; 55 import static com.android.server.wm.ActivityRecord.State.DESTROYED; 56 import static com.android.server.wm.ActivityRecord.State.PAUSED; 57 import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS; 58 import static com.android.server.wm.ActivityRecord.State.RESUMED; 59 import static com.android.server.wm.ActivityRecord.State.STOPPED; 60 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; 61 import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_POSITION_MULTIPLIER_CENTER; 62 import static com.android.server.wm.WindowContainer.POSITION_TOP; 63 64 import static com.google.common.truth.Truth.assertThat; 65 66 import static org.junit.Assert.assertEquals; 67 import static org.junit.Assert.assertFalse; 68 import static org.junit.Assert.assertNotEquals; 69 import static org.junit.Assert.assertNotNull; 70 import static org.junit.Assert.assertNull; 71 import static org.junit.Assert.assertTrue; 72 import static org.mockito.ArgumentMatchers.any; 73 import static org.mockito.ArgumentMatchers.anyBoolean; 74 import static org.mockito.ArgumentMatchers.anyInt; 75 import static org.mockito.ArgumentMatchers.anyString; 76 import static org.mockito.ArgumentMatchers.argThat; 77 import static org.mockito.ArgumentMatchers.isNull; 78 import static org.mockito.ArgumentMatchers.same; 79 import static org.mockito.Mockito.atLeastOnce; 80 import static org.mockito.Mockito.clearInvocations; 81 import static org.mockito.Mockito.doCallRealMethod; 82 import static org.mockito.Mockito.times; 83 84 import android.annotation.Nullable; 85 import android.app.ActivityManager; 86 import android.app.ActivityManagerInternal; 87 import android.app.WindowConfiguration; 88 import android.compat.testing.PlatformCompatChangeRule; 89 import android.content.ComponentName; 90 import android.content.pm.ActivityInfo; 91 import android.content.pm.ActivityInfo.ScreenOrientation; 92 import android.content.res.Configuration; 93 import android.graphics.Rect; 94 import android.os.UserHandle; 95 import android.platform.test.annotations.Presubmit; 96 import android.provider.DeviceConfig; 97 import android.provider.DeviceConfig.Properties; 98 import android.view.InsetsSource; 99 import android.view.InsetsVisibilities; 100 import android.view.WindowManager; 101 102 import androidx.test.filters.MediumTest; 103 104 import com.android.internal.policy.SystemBarUtils; 105 import com.android.internal.statusbar.LetterboxDetails; 106 import com.android.server.statusbar.StatusBarManagerInternal; 107 import com.android.server.wm.DeviceStateController.DeviceState; 108 109 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; 110 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 111 112 import org.junit.After; 113 import org.junit.Before; 114 import org.junit.Rule; 115 import org.junit.Test; 116 import org.junit.rules.TestRule; 117 import org.junit.runner.RunWith; 118 import org.mockito.ArgumentCaptor; 119 120 import java.util.List; 121 import java.util.function.Consumer; 122 import java.util.function.Function; 123 124 /** 125 * Tests for Size Compatibility mode. 126 * 127 * Build/Install/Run: 128 * atest WmTests:SizeCompatTests 129 */ 130 @MediumTest 131 @Presubmit 132 @RunWith(WindowTestRunner.class) 133 public class SizeCompatTests extends WindowTestsBase { 134 private static final String CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS = 135 "never_constrain_display_apis"; 136 private static final String CONFIG_ALWAYS_CONSTRAIN_DISPLAY_APIS = 137 "always_constrain_display_apis"; 138 private static final String CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES = 139 "never_constrain_display_apis_all_packages"; 140 141 @Rule 142 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 143 144 private Task mTask; 145 private ActivityRecord mActivity; 146 private ActivityMetricsLogger mActivityMetricsLogger; 147 private Properties mInitialConstrainDisplayApisFlags; 148 149 @Before setUp()150 public void setUp() throws Exception { 151 mActivityMetricsLogger = mock(ActivityMetricsLogger.class); 152 clearInvocations(mActivityMetricsLogger); 153 doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger(); 154 mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties( 155 NAMESPACE_CONSTRAIN_DISPLAY_APIS); 156 // Provide empty default values for the configs. 157 setNeverConstrainDisplayApisFlag("", true); 158 setNeverConstrainDisplayApisAllPackagesFlag(false, true); 159 setAlwaysConstrainDisplayApisFlag("", true); 160 } 161 162 @After tearDown()163 public void tearDown() throws Exception { 164 DeviceConfig.setProperties(mInitialConstrainDisplayApisFlags); 165 } 166 setUpApp(DisplayContent display)167 private void setUpApp(DisplayContent display) { 168 mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build(); 169 mActivity = mTask.getTopNonFinishingActivity(); 170 } 171 setUpDisplaySizeWithApp(int dw, int dh)172 private void setUpDisplaySizeWithApp(int dw, int dh) { 173 final TestDisplayContent.Builder builder = new TestDisplayContent.Builder(mAtm, dw, dh); 174 setUpApp(builder.build()); 175 } 176 177 @Test testActivityInHistoryAndNotVisibleIsNotUsedAsOpaqueForTranslucentActivities()178 public void testActivityInHistoryAndNotVisibleIsNotUsedAsOpaqueForTranslucentActivities() { 179 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 180 setUpDisplaySizeWithApp(2000, 1000); 181 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 182 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 183 mActivity.nowVisible = false; 184 // Translucent Activity 185 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 186 .setLaunchedFromUid(mActivity.getUid()) 187 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 188 .build(); 189 doReturn(false).when(translucentActivity).fillsParent(); 190 191 mTask.addChild(translucentActivity); 192 193 assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); 194 } 195 196 @Test testActivityInHistoryAndVisibleIsUsedAsOpaqueForTranslucentActivities()197 public void testActivityInHistoryAndVisibleIsUsedAsOpaqueForTranslucentActivities() { 198 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 199 setUpDisplaySizeWithApp(2000, 1000); 200 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 201 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 202 mActivity.nowVisible = true; 203 // Translucent Activity 204 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 205 .setLaunchedFromUid(mActivity.getUid()) 206 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 207 .build(); 208 doReturn(false).when(translucentActivity).fillsParent(); 209 210 mTask.addChild(translucentActivity); 211 212 assertTrue(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); 213 } 214 215 @Test testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed()216 public void testCleanLetterboxConfigListenerWhenTranslucentIsDestroyed() { 217 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 218 setUpDisplaySizeWithApp(2000, 1000); 219 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 220 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 221 // Translucent Activity 222 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 223 .setLaunchedFromUid(mActivity.getUid()) 224 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 225 .build(); 226 doReturn(false).when(translucentActivity).fillsParent(); 227 mTask.addChild(translucentActivity); 228 229 translucentActivity.setState(DESTROYED, "testing"); 230 translucentActivity.removeImmediately(); 231 232 assertFalse(translucentActivity.mLetterboxUiController.hasInheritedLetterboxBehavior()); 233 } 234 235 @Test testHorizontalReachabilityEnabledForTranslucentActivities()236 public void testHorizontalReachabilityEnabledForTranslucentActivities() { 237 setUpDisplaySizeWithApp(2500, 1000); 238 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 239 mActivity.nowVisible = true; 240 final LetterboxConfiguration config = mWm.mLetterboxConfiguration; 241 config.setTranslucentLetterboxingOverrideEnabled(true); 242 config.setLetterboxHorizontalPositionMultiplier(0.5f); 243 config.setIsHorizontalReachabilityEnabled(true); 244 245 // Opaque activity 246 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 247 addWindowToActivity(mActivity); 248 mActivity.mRootWindowContainer.performSurfacePlacement(); 249 250 // Translucent Activity 251 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 252 .setLaunchedFromUid(mActivity.getUid()) 253 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 254 .build(); 255 doReturn(false).when(translucentActivity).fillsParent(); 256 mTask.addChild(translucentActivity); 257 258 spyOn(translucentActivity.mLetterboxUiController); 259 doReturn(true).when(translucentActivity.mLetterboxUiController) 260 .shouldShowLetterboxUi(any()); 261 262 addWindowToActivity(translucentActivity); 263 translucentActivity.mRootWindowContainer.performSurfacePlacement(); 264 265 final Function<ActivityRecord, Rect> innerBoundsOf = 266 (ActivityRecord a) -> { 267 final Rect bounds = new Rect(); 268 a.mLetterboxUiController.getLetterboxInnerBounds(bounds); 269 return bounds; 270 }; 271 final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity), 272 innerBoundsOf.apply(translucentActivity)); 273 final Runnable checkIsLeft = () -> assertThat( 274 innerBoundsOf.apply(translucentActivity).left).isEqualTo(0); 275 final Runnable checkIsRight = () -> assertThat( 276 innerBoundsOf.apply(translucentActivity).right).isEqualTo(2500); 277 final Runnable checkIsCentered = () -> assertThat( 278 innerBoundsOf.apply(translucentActivity).left > 0 279 && innerBoundsOf.apply(translucentActivity).right < 2500).isTrue(); 280 281 final Consumer<Integer> doubleClick = 282 (Integer x) -> { 283 mActivity.mLetterboxUiController.handleHorizontalDoubleTap(x); 284 mActivity.mRootWindowContainer.performSurfacePlacement(); 285 }; 286 287 // Initial state 288 checkIsCentered.run(); 289 290 // Double-click left 291 doubleClick.accept(/* x */ 10); 292 checkLetterboxPositions.run(); 293 checkIsLeft.run(); 294 295 // Double-click right 296 doubleClick.accept(/* x */ 1990); 297 checkLetterboxPositions.run(); 298 checkIsCentered.run(); 299 300 // Double-click right 301 doubleClick.accept(/* x */ 1990); 302 checkLetterboxPositions.run(); 303 checkIsRight.run(); 304 305 // Double-click left 306 doubleClick.accept(/* x */ 10); 307 checkLetterboxPositions.run(); 308 checkIsCentered.run(); 309 } 310 311 @Test testVerticalReachabilityEnabledForTranslucentActivities()312 public void testVerticalReachabilityEnabledForTranslucentActivities() { 313 setUpDisplaySizeWithApp(1000, 2500); 314 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 315 mActivity.nowVisible = true; 316 final LetterboxConfiguration config = mWm.mLetterboxConfiguration; 317 config.setTranslucentLetterboxingOverrideEnabled(true); 318 config.setLetterboxVerticalPositionMultiplier(0.5f); 319 config.setIsVerticalReachabilityEnabled(true); 320 321 // Opaque activity 322 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 323 addWindowToActivity(mActivity); 324 mActivity.mRootWindowContainer.performSurfacePlacement(); 325 326 // Translucent Activity 327 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 328 .setLaunchedFromUid(mActivity.getUid()) 329 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 330 .build(); 331 doReturn(false).when(translucentActivity).fillsParent(); 332 mTask.addChild(translucentActivity); 333 334 spyOn(translucentActivity.mLetterboxUiController); 335 doReturn(true).when(translucentActivity.mLetterboxUiController) 336 .shouldShowLetterboxUi(any()); 337 338 addWindowToActivity(translucentActivity); 339 translucentActivity.mRootWindowContainer.performSurfacePlacement(); 340 341 final Function<ActivityRecord, Rect> innerBoundsOf = 342 (ActivityRecord a) -> { 343 final Rect bounds = new Rect(); 344 a.mLetterboxUiController.getLetterboxInnerBounds(bounds); 345 return bounds; 346 }; 347 final Runnable checkLetterboxPositions = () -> assertEquals(innerBoundsOf.apply(mActivity), 348 innerBoundsOf.apply(translucentActivity)); 349 final Runnable checkIsTop = () -> assertThat( 350 innerBoundsOf.apply(translucentActivity).top).isEqualTo(0); 351 final Runnable checkIsBottom = () -> assertThat( 352 innerBoundsOf.apply(translucentActivity).bottom).isEqualTo(2500); 353 final Runnable checkIsCentered = () -> assertThat( 354 innerBoundsOf.apply(translucentActivity).top > 0 355 && innerBoundsOf.apply(translucentActivity).bottom < 2500).isTrue(); 356 357 final Consumer<Integer> doubleClick = 358 (Integer y) -> { 359 mActivity.mLetterboxUiController.handleVerticalDoubleTap(y); 360 mActivity.mRootWindowContainer.performSurfacePlacement(); 361 }; 362 363 // Initial state 364 checkIsCentered.run(); 365 366 // Double-click top 367 doubleClick.accept(/* y */ 10); 368 checkLetterboxPositions.run(); 369 checkIsTop.run(); 370 371 // Double-click bottom 372 doubleClick.accept(/* y */ 1990); 373 checkLetterboxPositions.run(); 374 checkIsCentered.run(); 375 376 // Double-click bottom 377 doubleClick.accept(/* y */ 1990); 378 checkLetterboxPositions.run(); 379 checkIsBottom.run(); 380 381 // Double-click top 382 doubleClick.accept(/* y */ 10); 383 checkLetterboxPositions.run(); 384 checkIsCentered.run(); 385 } 386 387 @Test testApplyStrategyToTranslucentActivities()388 public void testApplyStrategyToTranslucentActivities() { 389 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 390 setUpDisplaySizeWithApp(2000, 1000); 391 prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 392 mActivity.info.setMinAspectRatio(1.2f); 393 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 394 mActivity.nowVisible = true; 395 // Translucent Activity 396 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 397 .setLaunchedFromUid(mActivity.getUid()) 398 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 399 .setMinAspectRatio(1.1f) 400 .setMaxAspectRatio(3f) 401 .build(); 402 doReturn(false).when(translucentActivity).fillsParent(); 403 mTask.addChild(translucentActivity); 404 // We check bounds 405 final Rect opaqueBounds = mActivity.getConfiguration().windowConfiguration.getBounds(); 406 final Rect translucentRequestedBounds = translucentActivity.getRequestedOverrideBounds(); 407 assertEquals(opaqueBounds, translucentRequestedBounds); 408 // We check orientation 409 final int translucentOrientation = 410 translucentActivity.getRequestedConfigurationOrientation(); 411 assertEquals(ORIENTATION_PORTRAIT, translucentOrientation); 412 // We check aspect ratios 413 assertEquals(1.2f, translucentActivity.getMinAspectRatio(), 0.00001f); 414 assertEquals(1.5f, translucentActivity.getMaxAspectRatio(), 0.00001f); 415 } 416 417 @Test testApplyStrategyToTranslucentActivitiesRetainsWindowConfigurationProperties()418 public void testApplyStrategyToTranslucentActivitiesRetainsWindowConfigurationProperties() { 419 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 420 setUpDisplaySizeWithApp(2000, 1000); 421 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 422 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 423 // Translucent Activity 424 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 425 .setLaunchedFromUid(mActivity.getUid()) 426 .build(); 427 doReturn(false).when(translucentActivity).fillsParent(); 428 WindowConfiguration translucentWinConf = translucentActivity.getWindowConfiguration(); 429 translucentActivity.setActivityType(ACTIVITY_TYPE_STANDARD); 430 translucentActivity.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 431 translucentActivity.setDisplayWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 432 translucentActivity.setAlwaysOnTop(true); 433 434 mTask.addChild(translucentActivity); 435 436 // We check the WIndowConfiguration properties 437 translucentWinConf = translucentActivity.getWindowConfiguration(); 438 assertEquals(ACTIVITY_TYPE_STANDARD, translucentActivity.getActivityType()); 439 assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getWindowingMode()); 440 assertEquals(WINDOWING_MODE_MULTI_WINDOW, translucentWinConf.getDisplayWindowingMode()); 441 assertTrue(translucentWinConf.isAlwaysOnTop()); 442 } 443 444 @Test testApplyStrategyToMultipleTranslucentActivities()445 public void testApplyStrategyToMultipleTranslucentActivities() { 446 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 447 setUpDisplaySizeWithApp(2000, 1000); 448 prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 449 mActivity.info.setMinAspectRatio(1.2f); 450 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 451 mActivity.nowVisible = true; 452 // Translucent Activity 453 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 454 .setLaunchedFromUid(mActivity.getUid()) 455 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 456 .setMinAspectRatio(1.1f) 457 .setMaxAspectRatio(3f) 458 .build(); 459 doReturn(false).when(translucentActivity).fillsParent(); 460 mTask.addChild(translucentActivity); 461 // We check bounds 462 final Rect opaqueBounds = mActivity.getConfiguration().windowConfiguration.getBounds(); 463 final Rect translucentRequestedBounds = translucentActivity.getRequestedOverrideBounds(); 464 assertEquals(opaqueBounds, translucentRequestedBounds); 465 // Launch another translucent activity 466 final ActivityRecord translucentActivity2 = new ActivityBuilder(mAtm) 467 .setLaunchedFromUid(mActivity.getUid()) 468 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 469 .build(); 470 doReturn(false).when(translucentActivity2).fillsParent(); 471 mTask.addChild(translucentActivity2); 472 // We check bounds 473 final Rect translucent2RequestedBounds = translucentActivity2.getRequestedOverrideBounds(); 474 assertEquals(opaqueBounds, translucent2RequestedBounds); 475 } 476 477 @Test testTranslucentActivitiesDontGoInSizeCompatMode()478 public void testTranslucentActivitiesDontGoInSizeCompatMode() { 479 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 480 setUpDisplaySizeWithApp(2800, 1400); 481 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 482 prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 483 // Rotate to put activity in size compat mode. 484 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 485 assertTrue(mActivity.inSizeCompatMode()); 486 // Rotate back 487 rotateDisplay(mActivity.mDisplayContent, ROTATION_0); 488 assertFalse(mActivity.inSizeCompatMode()); 489 // We launch a transparent activity 490 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 491 .setLaunchedFromUid(mActivity.getUid()) 492 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 493 .build(); 494 doReturn(false).when(translucentActivity).fillsParent(); 495 mTask.addChild(translucentActivity); 496 // It should not be in SCM 497 assertFalse(translucentActivity.inSizeCompatMode()); 498 // We rotate again 499 rotateDisplay(translucentActivity.mDisplayContent, ROTATION_90); 500 assertFalse(translucentActivity.inSizeCompatMode()); 501 } 502 503 @Test testCheckOpaqueIsLetterboxedWhenStrategyIsApplied()504 public void testCheckOpaqueIsLetterboxedWhenStrategyIsApplied() { 505 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 506 setUpDisplaySizeWithApp(2000, 1000); 507 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 508 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 509 // Translucent Activity 510 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 511 .setLaunchedFromUid(mActivity.getUid()) 512 .build(); 513 doReturn(false).when(translucentActivity).fillsParent(); 514 spyOn(mActivity); 515 mTask.addChild(translucentActivity); 516 verify(mActivity).isFinishing(); 517 } 518 519 @Test testTranslucentActivitiesWhenUnfolding()520 public void testTranslucentActivitiesWhenUnfolding() { 521 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 522 setUpDisplaySizeWithApp(2800, 1400); 523 mActivity.mDisplayContent.setIgnoreOrientationRequest( 524 true /* ignoreOrientationRequest */); 525 mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 526 1.0f /*letterboxVerticalPositionMultiplier*/); 527 mActivity.nowVisible = true; 528 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 529 // We launch a transparent activity 530 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 531 .setLaunchedFromUid(mActivity.getUid()) 532 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 533 .build(); 534 doReturn(false).when(translucentActivity).fillsParent(); 535 mTask.addChild(translucentActivity); 536 assertEquals(translucentActivity.getBounds(), mActivity.getBounds()); 537 538 mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 539 spyOn(mActivity); 540 541 // Halffold 542 setFoldablePosture(translucentActivity, true /* isHalfFolded */, 543 false /* isTabletop */); 544 verify(mActivity).recomputeConfiguration(); 545 assertEquals(translucentActivity.getBounds(), mActivity.getBounds()); 546 clearInvocations(mActivity); 547 548 // Unfold 549 setFoldablePosture(translucentActivity, false /* isHalfFolded */, 550 false /* isTabletop */); 551 verify(mActivity).recomputeConfiguration(); 552 assertEquals(translucentActivity.getBounds(), mActivity.getBounds()); 553 } 554 555 @Test testTranslucentActivity_clearSizeCompatMode_inheritedCompatDisplayInsetsCleared()556 public void testTranslucentActivity_clearSizeCompatMode_inheritedCompatDisplayInsetsCleared() { 557 mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); 558 setUpDisplaySizeWithApp(2800, 1400); 559 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 560 mActivity.nowVisible = true; 561 prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 562 // Rotate to put activity in size compat mode. 563 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 564 assertTrue(mActivity.inSizeCompatMode()); 565 566 // We launch a transparent activity 567 final ActivityRecord translucentActivity = new ActivityBuilder(mAtm) 568 .setLaunchedFromUid(mActivity.getUid()) 569 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 570 .build(); 571 doReturn(false).when(translucentActivity).fillsParent(); 572 mTask.addChild(translucentActivity); 573 574 // The transparent activity inherits the compat display insets of the opaque activity 575 // beneath it 576 assertNotNull(translucentActivity.getCompatDisplayInsets()); 577 578 // Clearing SCM should also clear the inherited compat display insets 579 translucentActivity.clearSizeCompatMode(); 580 assertNull(translucentActivity.getCompatDisplayInsets()); 581 } 582 583 @Test testRestartProcessIfVisible()584 public void testRestartProcessIfVisible() { 585 setUpDisplaySizeWithApp(1000, 2500); 586 doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity); 587 mActivity.setVisibleRequested(true); 588 mActivity.setSavedState(null /* savedState */); 589 mActivity.setState(RESUMED, "testRestart"); 590 prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 591 592 final Rect originalOverrideBounds = new Rect(mActivity.getBounds()); 593 resizeDisplay(mTask.mDisplayContent, 600, 1200); 594 // The visible activity should recompute configuration according to the last parent bounds. 595 mAtm.mActivityClientController.restartActivityProcessIfVisible(mActivity.token); 596 597 assertEquals(RESTARTING_PROCESS, mActivity.getState()); 598 assertNotEquals(originalOverrideBounds, mActivity.getBounds()); 599 } 600 601 @Test testFixedAspectRatioBoundsWithDecorInSquareDisplay()602 public void testFixedAspectRatioBoundsWithDecorInSquareDisplay() { 603 final int notchHeight = 100; 604 setUpApp(new TestDisplayContent.Builder(mAtm, 600, 800).setNotch(notchHeight).build()); 605 606 final Rect displayBounds = mActivity.mDisplayContent.getWindowConfiguration().getBounds(); 607 final float aspectRatio = 1.2f; 608 mActivity.info.setMaxAspectRatio(aspectRatio); 609 mActivity.info.setMinAspectRatio(aspectRatio); 610 prepareUnresizable(mActivity, -1f, SCREEN_ORIENTATION_UNSPECIFIED); 611 final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); 612 613 // The parent configuration doesn't change since the first resolved configuration, so the 614 // activity should fit in the parent naturally (size=583x700, appBounds=[9, 100 - 592, 800], 615 // horizontal offset = round((600 - 583) / 2) = 9)). 616 assertFitted(); 617 final int offsetX = (int) ((1f + displayBounds.width() - appBounds.width()) / 2); 618 // The bounds must be horizontal centered. 619 assertEquals(offsetX, appBounds.left); 620 assertEquals(appBounds.height(), displayBounds.height() - notchHeight); 621 // Ensure the app bounds keep the declared aspect ratio. 622 assertEquals(appBounds.height(), appBounds.width() * aspectRatio, 0.5f /* delta */); 623 // The decor height should be a part of the effective bounds. 624 assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight); 625 // Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio. 626 assertActivityMaxBoundsSandboxed(); 627 // Activity max bounds ignore notch, since an app can be shown past the notch (although app 628 // is currently limited by the notch). 629 assertThat(mActivity.getWindowConfiguration().getMaxBounds().height()) 630 .isEqualTo(displayBounds.height()); 631 632 mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 633 assertFitted(); 634 635 // After the orientation of activity is changed, the display is rotated, the aspect 636 // ratio should be the same (bounds=[0, 0 - 800, 583], appBounds=[100, 0 - 800, 583]). 637 assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */); 638 // Activity max bounds are sandboxed. 639 assertActivityMaxBoundsSandboxed(); 640 641 mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); 642 assertFitted(); 643 // Activity max bounds should be sandboxed; activity is letterboxed due to aspect ratio. 644 assertActivityMaxBoundsSandboxed(); 645 // Activity max bounds ignore notch, since an app can be shown past the notch (although app 646 // is currently limited by the notch). 647 assertThat(mActivity.getWindowConfiguration().getMaxBounds().height()) 648 .isEqualTo(displayBounds.height()); 649 } 650 651 @Test testFixedScreenConfigurationWhenMovingToDisplay()652 public void testFixedScreenConfigurationWhenMovingToDisplay() { 653 setUpDisplaySizeWithApp(1000, 2500); 654 655 // Make a new less-tall display with lower density 656 final DisplayContent newDisplay = 657 new TestDisplayContent.Builder(mAtm, 1000, 2000) 658 .setDensityDpi(200).build(); 659 660 prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 661 662 final Rect originalBounds = new Rect(mActivity.getBounds()); 663 final int originalDpi = mActivity.getConfiguration().densityDpi; 664 665 // Move the non-resizable activity to the new display. 666 mTask.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */); 667 668 assertEquals(originalBounds.width(), mActivity.getBounds().width()); 669 assertEquals(originalBounds.height(), mActivity.getBounds().height()); 670 assertEquals(originalDpi, mActivity.getConfiguration().densityDpi); 671 // Activity is sandboxed; it is in size compat mode since it is not resizable and has a 672 // max aspect ratio. 673 assertActivityMaxBoundsSandboxed(); 674 assertScaled(); 675 } 676 677 @Test testFixedScreenBoundsWhenDisplaySizeChanged()678 public void testFixedScreenBoundsWhenDisplaySizeChanged() { 679 setUpDisplaySizeWithApp(1000, 2500); 680 prepareUnresizable(mActivity, -1f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 681 final DisplayContent display = mActivity.mDisplayContent; 682 assertFitted(); 683 // Activity inherits bounds from TaskDisplayArea, since not sandboxed. 684 assertMaxBoundsInheritDisplayAreaBounds(); 685 686 final Rect origBounds = new Rect(mActivity.getBounds()); 687 final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); 688 689 // Change the size of current display. 690 resizeDisplay(display, 1000, 2000); 691 // The bounds should be [100, 0 - 1100, 2500]. 692 assertEquals(origBounds.width(), currentBounds.width()); 693 assertEquals(origBounds.height(), currentBounds.height()); 694 assertScaled(); 695 696 // The scale is 2000/2500=0.8. The horizontal centered offset is (1000-(1000*0.8))/2=100. 697 final float scale = (float) display.mBaseDisplayHeight / currentBounds.height(); 698 final int offsetX = (int) (display.mBaseDisplayWidth - (origBounds.width() * scale)) / 2; 699 final int screenX = mActivity.getBounds().left; 700 assertEquals(offsetX, screenX); 701 702 // The position of configuration bounds should be in app space. 703 assertEquals(screenX, (int) (currentBounds.left * scale + 0.5f)); 704 // Activity is sandboxed to the offset size compat bounds. 705 assertActivityMaxBoundsSandboxed(); 706 707 // Change display size to a different orientation 708 resizeDisplay(display, 2000, 1000); 709 // The bounds should be [800, 0 - 1800, 2500]. 710 assertEquals(origBounds.width(), currentBounds.width()); 711 assertEquals(origBounds.height(), currentBounds.height()); 712 assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation); 713 assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation); 714 // Activity is sandboxed to the offset size compat bounds. 715 assertActivityMaxBoundsSandboxed(); 716 717 // The previous resize operation doesn't consider the rotation change after size changed. 718 // These setups apply the requested orientation to rotation as real case that the top fixed 719 // portrait activity will determine the display rotation. 720 final DisplayRotation displayRotation = display.getDisplayRotation(); 721 doCallRealMethod().when(displayRotation).updateRotationUnchecked(anyBoolean()); 722 // Skip unrelated layout procedures. 723 mAtm.deferWindowLayout(); 724 display.reconfigureDisplayLocked(); 725 displayRotation.updateOrientation(display.getOrientation(), true /* forceUpdate */); 726 display.sendNewConfiguration(); 727 728 assertEquals(Configuration.ORIENTATION_PORTRAIT, display.getConfiguration().orientation); 729 assertEquals(Configuration.ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation); 730 // The size should still be in portrait [100, 0 - 1100, 2500] = 1000x2500. 731 assertEquals(origBounds.width(), currentBounds.width()); 732 assertEquals(origBounds.height(), currentBounds.height()); 733 assertEquals(offsetX, mActivity.getBounds().left); 734 assertScaled(); 735 // Activity is sandboxed due to size compat mode. 736 assertActivityMaxBoundsSandboxed(); 737 738 final WindowState appWindow = addWindowToActivity(mActivity); 739 assertTrue(mActivity.hasSizeCompatBounds()); 740 assertEquals("App window must use size compat bounds for layout in screen space", 741 mActivity.getBounds(), appWindow.getBounds()); 742 } 743 744 @Test testLetterboxFullscreenBoundsAndNotImeAttachable()745 public void testLetterboxFullscreenBoundsAndNotImeAttachable() { 746 final int displayWidth = 2500; 747 setUpDisplaySizeWithApp(displayWidth, 1000); 748 749 final float maxAspect = 1.5f; 750 prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE); 751 assertFitted(); 752 753 final Rect bounds = mActivity.getBounds(); 754 assertEquals(bounds.width(), bounds.height() * maxAspect, 0.0001f /* delta */); 755 // The position should be horizontal centered. 756 assertEquals((displayWidth - bounds.width()) / 2, bounds.left); 757 // Activity max bounds should be sandboxed since it is letterboxed. 758 assertActivityMaxBoundsSandboxed(); 759 760 mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity)); 761 // Make sure IME cannot attach to the app, otherwise IME window will also be shifted. 762 assertFalse(mActivity.mDisplayContent.shouldImeAttachedToApp()); 763 764 // Recompute the natural configuration without resolving size compat configuration. 765 mActivity.clearSizeCompatMode(); 766 mActivity.onConfigurationChanged(mTask.getConfiguration()); 767 // It should keep non-attachable because the resolved bounds will be computed according to 768 // the aspect ratio that won't match its parent bounds. 769 assertFalse(mActivity.mDisplayContent.shouldImeAttachedToApp()); 770 // Activity max bounds should be sandboxed since it is letterboxed. 771 assertActivityMaxBoundsSandboxed(); 772 } 773 774 @Test testIsLetterboxed_activityShowsWallpaper_returnsFalse()775 public void testIsLetterboxed_activityShowsWallpaper_returnsFalse() { 776 setUpDisplaySizeWithApp(1000, 2500); 777 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 778 779 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 780 final WindowState window = createWindow(null, TYPE_BASE_APPLICATION, mActivity, "window"); 781 782 assertEquals(window, mActivity.findMainWindow()); 783 784 spyOn(mActivity.mLetterboxUiController); 785 doReturn(true).when(mActivity.mLetterboxUiController) 786 .isSurfaceReadyToShow(any()); 787 doReturn(true).when(mActivity.mLetterboxUiController) 788 .isSurfaceVisible(any()); 789 790 assertTrue(mActivity.mLetterboxUiController.shouldShowLetterboxUi( 791 mActivity.findMainWindow())); 792 793 window.mAttrs.flags |= FLAG_SHOW_WALLPAPER; 794 795 assertFalse(mActivity.mLetterboxUiController.shouldShowLetterboxUi( 796 mActivity.findMainWindow())); 797 } 798 799 @Test testAspectRatioMatchParentBoundsAndImeAttachable()800 public void testAspectRatioMatchParentBoundsAndImeAttachable() { 801 setUpApp(new TestDisplayContent.Builder(mAtm, 1000, 2000).build()); 802 prepareUnresizable(mActivity, 2f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 803 assertFitted(); 804 805 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 806 mActivity.mDisplayContent.setImeLayeringTarget(addWindowToActivity(mActivity)); 807 mActivity.mDisplayContent.setImeInputTarget( 808 mActivity.mDisplayContent.getImeTarget(IME_TARGET_LAYERING).getWindow()); 809 // Because the aspect ratio of display doesn't exceed the max aspect ratio of activity. 810 // The activity should still fill its parent container and IME can attach to the activity. 811 assertTrue(mActivity.matchParentBounds()); 812 assertTrue(mActivity.mDisplayContent.shouldImeAttachedToApp()); 813 814 final Rect letterboxInnerBounds = new Rect(); 815 mActivity.getLetterboxInnerBounds(letterboxInnerBounds); 816 // The activity should not have letterbox. 817 assertTrue(letterboxInnerBounds.isEmpty()); 818 } 819 820 @Test testMoveToDifferentOrientationDisplay()821 public void testMoveToDifferentOrientationDisplay() { 822 setUpDisplaySizeWithApp(1000, 2500); 823 prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 824 assertFitted(); 825 826 final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); 827 final Rect currentAppBounds = mActivity.getWindowConfiguration().getAppBounds(); 828 final Rect originalBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 829 830 final int notchHeight = 100; 831 final DisplayContent newDisplay = new TestDisplayContent.Builder(mAtm, 2000, 1000) 832 .setCanRotate(false).setNotch(notchHeight).build(); 833 834 // Move the non-resizable activity to the new display. 835 mTask.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */); 836 // The configuration bounds [820, 0 - 1820, 2500] should keep the same. 837 assertEquals(originalBounds.width(), currentBounds.width()); 838 assertEquals(originalBounds.height(), currentBounds.height()); 839 assertScaled(); 840 // Activity max bounds are sandboxed due to size compat mode on the new display. 841 assertActivityMaxBoundsSandboxed(); 842 843 final Rect newDisplayBounds = newDisplay.getWindowConfiguration().getBounds(); 844 // The scaled bounds should exclude notch area (1000 - 100 == 360 * 2500 / 1000 = 900). 845 assertEquals(newDisplayBounds.height() - notchHeight, 846 (int) ((float) mActivity.getBounds().width() * originalBounds.height() 847 / originalBounds.width())); 848 849 // Recompute the natural configuration in the new display. 850 mActivity.clearSizeCompatMode(); 851 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 852 // Because the display cannot rotate, the portrait activity will fit the short side of 853 // display with keeping portrait bounds [200, 0 - 700, 1000] in center. 854 assertEquals(newDisplayBounds.height(), currentBounds.height()); 855 assertEquals(currentAppBounds.height() * newDisplayBounds.height() 856 / newDisplayBounds.width(), currentAppBounds.width()); 857 assertFitted(); 858 // The appBounds should be [200, 100 - 700, 1000]. 859 final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); 860 assertEquals(currentBounds.width(), appBounds.width()); 861 assertEquals(currentBounds.height() - notchHeight, appBounds.height()); 862 // Activity max bounds are sandboxed due to letterboxing from orientation mismatch with 863 // display. 864 assertActivityMaxBoundsSandboxed(); 865 } 866 867 @Test testFixedOrientationRotateCutoutDisplay()868 public void testFixedOrientationRotateCutoutDisplay() { 869 // Create a display with a notch/cutout 870 final int notchHeight = 60; 871 final int width = 1000; 872 setUpApp(new TestDisplayContent.Builder(mAtm, width, 2500) 873 .setNotch(notchHeight).build()); 874 // Bounds=[0, 0 - 1000, 1400], AppBounds=[0, 60 - 1000, 1460]. 875 final float maxAspect = 1.4f; 876 prepareUnresizable(mActivity, 1.4f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 877 878 final Rect currentBounds = mActivity.getWindowConfiguration().getBounds(); 879 final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds(); 880 final Rect origBounds = new Rect(currentBounds); 881 final Rect origAppBounds = new Rect(appBounds); 882 883 // Activity is sandboxed, and bounds include the area consumed by the notch. 884 assertActivityMaxBoundsSandboxed(); 885 assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds().height()) 886 .isEqualTo(Math.round(width * maxAspect) + notchHeight); 887 888 // Although the activity is fixed orientation, force rotate the display. 889 rotateDisplay(mActivity.mDisplayContent, ROTATION_270); 890 assertEquals(ROTATION_270, mTask.getWindowConfiguration().getRotation()); 891 892 assertEquals(origBounds.width(), currentBounds.width()); 893 // Make sure the app size is the same 894 assertEquals(origAppBounds.width(), appBounds.width()); 895 assertEquals(origAppBounds.height(), appBounds.height()); 896 // The activity is 1000x1400 and the display is 2500x1000. 897 assertScaled(); 898 final float scale = mActivity.getCompatScale(); 899 // The position in configuration should be in app coordinates. 900 final Rect screenBounds = mActivity.getBounds(); 901 assertEquals(screenBounds.left, (int) (currentBounds.left * scale + 0.5f)); 902 assertEquals(screenBounds.top, (int) (currentBounds.top * scale + 0.5f)); 903 904 // Activity max bounds are sandboxed due to size compat mode. 905 assertActivityMaxBoundsSandboxed(); 906 } 907 908 @Test testFixedAspectRatioOrientationChangeOrientation()909 public void testFixedAspectRatioOrientationChangeOrientation() { 910 setUpDisplaySizeWithApp(1000, 2500); 911 912 final float maxAspect = 1.4f; 913 prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_PORTRAIT); 914 // The display aspect ratio 2.5 > 1.4 (max of activity), so the size is fitted. 915 assertFitted(); 916 917 final Rect originalBounds = new Rect(mActivity.getBounds()); 918 final Rect originalAppBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds()); 919 920 assertEquals((int) (originalBounds.width() * maxAspect), originalBounds.height()); 921 // Activity is sandboxed due to fixed aspect ratio. 922 assertActivityMaxBoundsSandboxed(); 923 924 // Change the fixed orientation. 925 mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE); 926 927 assertFitted(); 928 assertEquals(originalBounds.width(), mActivity.getBounds().height()); 929 assertEquals(originalBounds.height(), mActivity.getBounds().width()); 930 assertEquals(originalAppBounds.width(), 931 mActivity.getWindowConfiguration().getAppBounds().height()); 932 assertEquals(originalAppBounds.height(), 933 mActivity.getWindowConfiguration().getAppBounds().width()); 934 // Activity is sandboxed due to fixed aspect ratio. 935 assertActivityMaxBoundsSandboxed(); 936 } 937 938 @Test testFixedScreenLayoutSizeBits()939 public void testFixedScreenLayoutSizeBits() { 940 setUpDisplaySizeWithApp(1000, 2500); 941 final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO 942 | Configuration.SCREENLAYOUT_SIZE_NORMAL 943 | Configuration.SCREENLAYOUT_COMPAT_NEEDED; 944 final int layoutMask = Configuration.SCREENLAYOUT_LONG_MASK 945 | Configuration.SCREENLAYOUT_SIZE_MASK 946 | Configuration.SCREENLAYOUT_LAYOUTDIR_MASK 947 | Configuration.SCREENLAYOUT_COMPAT_NEEDED; 948 Configuration c = new Configuration(mTask.getRequestedOverrideConfiguration()); 949 c.screenLayout = fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR; 950 mTask.onRequestedOverrideConfigurationChanged(c); 951 prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_UNSPECIFIED); 952 953 // The initial configuration should inherit from parent. 954 assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR, 955 mActivity.getConfiguration().screenLayout & layoutMask); 956 957 mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL 958 | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE; 959 mActivity.onConfigurationChanged(mTask.getConfiguration()); 960 961 // The size and aspect ratio bits don't change, but the layout direction should be updated. 962 assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL, 963 mActivity.getConfiguration().screenLayout & layoutMask); 964 } 965 966 @Test testResetNonVisibleActivity()967 public void testResetNonVisibleActivity() { 968 setUpDisplaySizeWithApp(1000, 2500); 969 prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_UNSPECIFIED); 970 final DisplayContent display = mTask.mDisplayContent; 971 // Resize the display so the activity is in size compatibility mode. 972 resizeDisplay(display, 900, 1800); 973 974 mActivity.setState(STOPPED, "testSizeCompatMode"); 975 mActivity.setVisibleRequested(false); 976 mActivity.visibleIgnoringKeyguard = false; 977 mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY); 978 mActivity.app.computeProcessActivityState(); 979 980 // Simulate the display changes orientation. 981 final Configuration rotatedConfig = rotateDisplay(display, ROTATION_90); 982 // Size compatibility mode is able to handle orientation change so the process shouldn't be 983 // restarted and the override configuration won't be cleared. 984 verify(mActivity, never()).restartProcessIfVisible(); 985 assertScaled(); 986 // Activity max bounds are sandboxed due to size compat mode, even if is not visible. 987 assertActivityMaxBoundsSandboxed(); 988 989 // Change display density 990 display.mBaseDisplayDensity = (int) (0.7f * display.mBaseDisplayDensity); 991 display.computeScreenConfiguration(rotatedConfig); 992 mAtm.mAmInternal = mock(ActivityManagerInternal.class); 993 display.onRequestedOverrideConfigurationChanged(rotatedConfig); 994 995 // The override configuration should be reset and the activity's process will be killed. 996 assertFitted(); 997 verify(mActivity).restartProcessIfVisible(); 998 waitHandlerIdle(mAtm.mH); 999 verify(mAtm.mAmInternal).killProcess( 1000 eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString()); 1001 } 1002 1003 /** 1004 * Ensures that {@link TaskOrganizerController} can receive callback about the activity in size 1005 * compatibility mode. 1006 */ 1007 @Test testHandleActivitySizeCompatModeChanged()1008 public void testHandleActivitySizeCompatModeChanged() { 1009 setUpDisplaySizeWithApp(1000, 2000); 1010 doReturn(true).when(mTask).isOrganized(); 1011 mActivity.setState(RESUMED, "testHandleActivitySizeCompatModeChanged"); 1012 prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 1013 assertFitted(); 1014 1015 // Resize the display so that the activity exercises size-compat mode. 1016 resizeDisplay(mTask.mDisplayContent, 1000, 2500); 1017 1018 // Expect the exact token when the activity is in size compatibility mode. 1019 verify(mTask).onSizeCompatActivityChanged(); 1020 ActivityManager.RunningTaskInfo taskInfo = mTask.getTaskInfo(); 1021 1022 assertTrue(taskInfo.topActivityInSizeCompat); 1023 1024 // Make the activity resizable again by restarting it 1025 clearInvocations(mTask); 1026 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1027 mActivity.setVisibleRequested(true); 1028 mActivity.restartProcessIfVisible(); 1029 // The full lifecycle isn't hooked up so manually set state to resumed 1030 mActivity.setState(RESUMED, "testHandleActivitySizeCompatModeChanged"); 1031 mTask.mDisplayContent.handleActivitySizeCompatModeIfNeeded(mActivity); 1032 1033 // Expect null token when switching to non-size-compat mode activity. 1034 verify(mTask).onSizeCompatActivityChanged(); 1035 taskInfo = mTask.getTaskInfo(); 1036 1037 assertFalse(taskInfo.topActivityInSizeCompat); 1038 } 1039 1040 @Test testHandleActivitySizeCompatModeChangedOnDifferentTask()1041 public void testHandleActivitySizeCompatModeChangedOnDifferentTask() { 1042 setUpDisplaySizeWithApp(1000, 2000); 1043 doReturn(true).when(mTask).isOrganized(); 1044 mActivity.setState(RESUMED, "testHandleActivitySizeCompatModeChanged"); 1045 prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 1046 assertFitted(); 1047 1048 // Resize the display so that the activity exercises size-compat mode. 1049 resizeDisplay(mTask.mDisplayContent, 1000, 2500); 1050 1051 // Expect the exact token when the activity is in size compatibility mode. 1052 verify(mTask).onSizeCompatActivityChanged(); 1053 ActivityManager.RunningTaskInfo taskInfo = mTask.getTaskInfo(); 1054 1055 assertTrue(taskInfo.topActivityInSizeCompat); 1056 1057 // Create another Task to hold another size compat activity. 1058 clearInvocations(mTask); 1059 final Task secondTask = new TaskBuilder(mSupervisor).setDisplay(mTask.getDisplayContent()) 1060 .setCreateActivity(true).build(); 1061 final ActivityRecord secondActivity = secondTask.getTopNonFinishingActivity(); 1062 doReturn(true).when(secondTask).isOrganized(); 1063 secondActivity.setState(RESUMED, 1064 "testHandleActivitySizeCompatModeChanged"); 1065 prepareUnresizable(secondActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 1066 1067 // Resize the display so that the activity exercises size-compat mode. 1068 resizeDisplay(mTask.mDisplayContent, 1000, 3000); 1069 1070 // Expect the exact token when the activity is in size compatibility mode. 1071 verify(secondTask).onSizeCompatActivityChanged(); 1072 verify(mTask, never()).onSizeCompatActivityChanged(); 1073 taskInfo = secondTask.getTaskInfo(); 1074 1075 assertTrue(taskInfo.topActivityInSizeCompat); 1076 } 1077 1078 @Test testShouldCreateCompatDisplayInsetsOnResizeableTask()1079 public void testShouldCreateCompatDisplayInsetsOnResizeableTask() { 1080 setUpDisplaySizeWithApp(1000, 2500); 1081 1082 // Make the task root resizable. 1083 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1084 1085 // Create an activity on the same task. 1086 final ActivityRecord activity = new ActivityBuilder(mAtm) 1087 .setTask(mTask) 1088 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 1089 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 1090 .build(); 1091 assertTrue(activity.shouldCreateCompatDisplayInsets()); 1092 1093 // The non-resizable activity should not be size compat because it is on a resizable task 1094 // in multi-window mode. 1095 mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); 1096 assertFalse(activity.shouldCreateCompatDisplayInsets()); 1097 // Activity should not be sandboxed. 1098 assertMaxBoundsInheritDisplayAreaBounds(); 1099 1100 // The non-resizable activity should not be size compat because the display support 1101 // changing windowing mode from fullscreen to freeform. 1102 mTask.mDisplayContent.getDefaultTaskDisplayArea() 1103 .setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); 1104 mTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); 1105 assertFalse(activity.shouldCreateCompatDisplayInsets()); 1106 // Activity should not be sandboxed. 1107 assertMaxBoundsInheritDisplayAreaBounds(); 1108 } 1109 1110 @Test testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesTrue()1111 public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesTrue() { 1112 setUpDisplaySizeWithApp(1000, 2500); 1113 1114 // Make the task root resizable. 1115 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1116 1117 // Create an activity on the same task. 1118 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */true, 1119 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1120 assertFalse(activity.shouldCreateCompatDisplayInsets()); 1121 } 1122 1123 @Test testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse()1124 public void testShouldCreateCompatDisplayInsetsWhenUnresizeableAndSupportsSizeChangesFalse() { 1125 setUpDisplaySizeWithApp(1000, 2500); 1126 1127 // Make the task root resizable. 1128 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1129 1130 // Create an activity on the same task. 1131 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1132 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1133 assertTrue(activity.shouldCreateCompatDisplayInsets()); 1134 } 1135 1136 @Test testShouldCreateCompatDisplayInsetsWhenResizeableAndSupportsSizeChangesFalse()1137 public void testShouldCreateCompatDisplayInsetsWhenResizeableAndSupportsSizeChangesFalse() { 1138 setUpDisplaySizeWithApp(1000, 2500); 1139 1140 // Make the task root resizable. 1141 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1142 1143 // Create an activity on the same task. 1144 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1145 RESIZE_MODE_RESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1146 assertFalse(activity.shouldCreateCompatDisplayInsets()); 1147 } 1148 1149 @Test 1150 public void testShouldCreateCompatDisplayInsetsWhenUnfixedOrientationSupportsSizeChangesFalse()1151 testShouldCreateCompatDisplayInsetsWhenUnfixedOrientationSupportsSizeChangesFalse() { 1152 setUpDisplaySizeWithApp(1000, 2500); 1153 1154 // Make the task root resizable. 1155 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1156 1157 // Create an activity on the same task. 1158 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1159 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1160 assertFalse(activity.shouldCreateCompatDisplayInsets()); 1161 } 1162 1163 @Test 1164 @EnableCompatChanges({ActivityInfo.FORCE_RESIZE_APP}) testShouldCreateCompatDisplayInsetsWhenForceResizeAppOverrideSet()1165 public void testShouldCreateCompatDisplayInsetsWhenForceResizeAppOverrideSet() { 1166 setUpDisplaySizeWithApp(1000, 2500); 1167 1168 // Make the task root resizable. 1169 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1170 1171 // Create an activity on the same task. 1172 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1173 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1174 assertFalse(activity.shouldCreateCompatDisplayInsets()); 1175 } 1176 1177 @Test 1178 @EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP}) testShouldCreateCompatDisplayInsetsWhenForceNonResizeOverrideSet()1179 public void testShouldCreateCompatDisplayInsetsWhenForceNonResizeOverrideSet() { 1180 setUpDisplaySizeWithApp(1000, 2500); 1181 1182 // Make the task root resizable. 1183 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1184 1185 // Create an activity on the same task. 1186 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */true, 1187 RESIZE_MODE_RESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1188 assertTrue(activity.shouldCreateCompatDisplayInsets()); 1189 } 1190 1191 @Test 1192 @EnableCompatChanges({ActivityInfo.FORCE_NON_RESIZE_APP}) testShouldCreateCompatDisplayInsetsWhenForceNonResizeSetAndUnfixedOrientation()1193 public void testShouldCreateCompatDisplayInsetsWhenForceNonResizeSetAndUnfixedOrientation() { 1194 setUpDisplaySizeWithApp(1000, 2500); 1195 1196 // Make the task root resizable. 1197 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1198 1199 // Create an activity on the same task. 1200 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */true, 1201 RESIZE_MODE_RESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1202 assertTrue(activity.shouldCreateCompatDisplayInsets()); 1203 } 1204 1205 @Test 1206 @EnableCompatChanges({ActivityInfo.NEVER_SANDBOX_DISPLAY_APIS}) testNeverSandboxDisplayApis_configEnabled_sandboxingNotApplied()1207 public void testNeverSandboxDisplayApis_configEnabled_sandboxingNotApplied() { 1208 setUpDisplaySizeWithApp(1000, 1200); 1209 1210 // Make the task root resizable. 1211 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1212 1213 // Create an activity with a max aspect ratio on the same task. 1214 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1215 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1216 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1217 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1218 1219 // Activity max bounds should not be sandboxed, even though it is letterboxed. 1220 assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); 1221 assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) 1222 .isEqualTo(activity.getDisplayArea().getBounds()); 1223 } 1224 1225 @Test 1226 @DisableCompatChanges({ActivityInfo.NEVER_SANDBOX_DISPLAY_APIS}) testNeverSandboxDisplayApis_configDisabled_sandboxingApplied()1227 public void testNeverSandboxDisplayApis_configDisabled_sandboxingApplied() { 1228 setUpDisplaySizeWithApp(1000, 1200); 1229 1230 // Make the task root resizable. 1231 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1232 1233 // Create an activity with a max aspect ratio on the same task. 1234 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1235 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1236 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1237 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1238 1239 // Activity max bounds should be sandboxed due to letterboxed and the config being disabled. 1240 assertActivityMaxBoundsSandboxed(activity); 1241 } 1242 1243 @Test testNeverConstrainDisplayApisDeviceConfig_allPackagesFlagTrue_sandboxNotApplied()1244 public void testNeverConstrainDisplayApisDeviceConfig_allPackagesFlagTrue_sandboxNotApplied() { 1245 setUpDisplaySizeWithApp(1000, 1200); 1246 1247 setNeverConstrainDisplayApisAllPackagesFlag(true, false); 1248 // Setting 'never_constrain_display_apis' as well to make sure it is ignored. 1249 setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::", false); 1250 1251 // Make the task root resizable. 1252 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1253 1254 // Create an activity with a max aspect ratio on the same task. 1255 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1256 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1257 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1258 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1259 1260 // Activity max bounds should not be sandboxed, even though it is letterboxed. 1261 assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); 1262 assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) 1263 .isEqualTo(activity.getDisplayArea().getBounds()); 1264 } 1265 1266 @Test testNeverConstrainDisplayApisDeviceConfig_packageInRange_sandboxingNotApplied()1267 public void testNeverConstrainDisplayApisDeviceConfig_packageInRange_sandboxingNotApplied() { 1268 setUpDisplaySizeWithApp(1000, 1200); 1269 1270 setNeverConstrainDisplayApisFlag( 1271 "com.android.frameworks.wmtests:20:,com.android.other::," 1272 + "com.android.frameworks.wmtests:0:10", false); 1273 1274 // Make the task root resizable. 1275 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1276 1277 // Create an activity with a max aspect ratio on the same task. 1278 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1279 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1280 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1281 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1282 1283 // Activity max bounds should not be sandboxed, even though it is letterboxed. 1284 assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); 1285 assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) 1286 .isEqualTo(activity.getDisplayArea().getBounds()); 1287 } 1288 1289 @Test testNeverConstrainDisplayApisDeviceConfig_packageOutsideRange_sandboxingApplied()1290 public void testNeverConstrainDisplayApisDeviceConfig_packageOutsideRange_sandboxingApplied() { 1291 setUpDisplaySizeWithApp(1000, 1200); 1292 1293 setNeverConstrainDisplayApisFlag("com.android.other::,com.android.frameworks.wmtests:1:5", 1294 false); 1295 1296 // Make the task root resizable. 1297 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1298 1299 // Create an activity with a max aspect ratio on the same task. 1300 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1301 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1302 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1303 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1304 1305 // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag. 1306 assertActivityMaxBoundsSandboxed(activity); 1307 } 1308 1309 @Test testNeverConstrainDisplayApisDeviceConfig_packageNotInFlag_sandboxingApplied()1310 public void testNeverConstrainDisplayApisDeviceConfig_packageNotInFlag_sandboxingApplied() { 1311 setUpDisplaySizeWithApp(1000, 1200); 1312 1313 setNeverConstrainDisplayApisFlag("com.android.other::,com.android.other2::", false); 1314 1315 // Make the task root resizable. 1316 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1317 1318 // Create an activity with a max aspect ratio on the same task. 1319 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1320 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1321 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1322 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1323 1324 // Activity max bounds should be sandboxed due to letterboxed and the mismatch with flag. 1325 assertActivityMaxBoundsSandboxed(activity); 1326 } 1327 1328 @Test 1329 @EnableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_unresizable()1330 public void testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_unresizable() { 1331 setUpDisplaySizeWithApp(1000, 1200); 1332 1333 // Make the task root resizable. 1334 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1335 1336 // Create an activity with a max aspect ratio on the same task. 1337 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1338 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1339 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1340 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1341 1342 // Activity max bounds should be sandboxed due to letterboxed and the config being enabled. 1343 assertActivityMaxBoundsSandboxed(activity); 1344 } 1345 1346 @Test 1347 @DisableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) testAlwaysSandboxDisplayApis_configDisabled_sandboxingApplied()1348 public void testAlwaysSandboxDisplayApis_configDisabled_sandboxingApplied() { 1349 setUpDisplaySizeWithApp(1000, 1200); 1350 1351 // Make the task root resizable. 1352 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1353 1354 // Create an activity with a max aspect ratio on the same task. 1355 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1356 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1357 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1358 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1359 1360 // Activity max bounds should be sandboxed due to letterbox and the config being disabled. 1361 assertActivityMaxBoundsSandboxed(activity); 1362 } 1363 1364 @Test 1365 @EnableCompatChanges({ActivityInfo.ALWAYS_SANDBOX_DISPLAY_APIS}) testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_resizableSplit()1366 public void testAlwaysSandboxDisplayApis_configEnabled_sandboxingApplied_resizableSplit() { 1367 setUpDisplaySizeWithApp(1000, 2800); 1368 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1369 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1370 RESIZE_MODE_RESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1371 final TestSplitOrganizer organizer = 1372 new TestSplitOrganizer(mAtm, activity.getDisplayContent()); 1373 1374 // Activity max bounds should be sandboxed due the config being enabled. 1375 assertFalse(activity.inSizeCompatMode()); 1376 assertActivityMaxBoundsSandboxed(activity); 1377 1378 // Move activity to split screen which takes half of the screen. 1379 mTask.reparent(organizer.mPrimary, POSITION_TOP, 1380 false /*moveParents*/, "test"); 1381 organizer.mPrimary.setBounds(0, 0, 1000, 1400); 1382 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 1383 assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode()); 1384 1385 // Resizable activity is sandboxed due to config being enabled. 1386 assertActivityMaxBoundsSandboxed(activity); 1387 } 1388 1389 @Test testAlwaysConstrainDisplayApisDeviceConfig_packageInRange_sandboxingApplied()1390 public void testAlwaysConstrainDisplayApisDeviceConfig_packageInRange_sandboxingApplied() { 1391 setUpDisplaySizeWithApp(1000, 1200); 1392 1393 setAlwaysConstrainDisplayApisFlag( 1394 "com.android.frameworks.wmtests:20:,com.android.other::," 1395 + "com.android.frameworks.wmtests:0:10", false); 1396 1397 // Make the task root resizable. 1398 mActivity.info.resizeMode = RESIZE_MODE_RESIZEABLE; 1399 1400 // Create an activity with a max aspect ratio on the same task. 1401 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */false, 1402 RESIZE_MODE_UNRESIZEABLE, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1403 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1404 prepareUnresizable(activity, /* maxAspect=*/ 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 1405 1406 // Resizable activity is sandboxed due to match with flag. 1407 assertActivityMaxBoundsSandboxed(activity); 1408 } 1409 1410 @Test 1411 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1412 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) testOverrideMinAspectRatioMedium()1413 public void testOverrideMinAspectRatioMedium() { 1414 setUpDisplaySizeWithApp(1000, 1200); 1415 1416 // Create a size compat activity on the same task. 1417 final ActivityRecord activity = new ActivityBuilder(mAtm) 1418 .setTask(mTask) 1419 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1420 .setComponent(ComponentName.createRelative(mContext, 1421 SizeCompatTests.class.getName())) 1422 .setUid(android.os.Process.myUid()) 1423 .build(); 1424 1425 // The per-package override forces the activity into a 3:2 aspect ratio 1426 assertEquals(1200, activity.getBounds().height()); 1427 assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 1428 activity.getBounds().width(), 0.5); 1429 } 1430 1431 @Test 1432 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1433 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) testOverrideMinAspectRatioLowerThanManifest()1434 public void testOverrideMinAspectRatioLowerThanManifest() { 1435 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1400, 1800) 1436 .setNotch(200).setSystemDecorations(true).build(); 1437 mTask = new TaskBuilder(mSupervisor).setDisplay(display).build(); 1438 1439 // Create a size compat activity on the same task. 1440 final ActivityRecord activity = new ActivityBuilder(mAtm) 1441 .setTask(mTask) 1442 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1443 .setComponent(ComponentName.createRelative(mContext, 1444 SizeCompatTests.class.getName())) 1445 .setMinAspectRatio(2f) 1446 .setUid(android.os.Process.myUid()) 1447 .build(); 1448 1449 // The per-package override should have no effect, because the manifest aspect ratio is 1450 // larger (2:1) 1451 final Rect appBounds = activity.getWindowConfiguration().getAppBounds(); 1452 assertEquals("App bounds must have min aspect ratio", 2f, 1453 (float) appBounds.height() / appBounds.width(), 0.0001f /* delta */); 1454 assertEquals("Long side must fit task", 1455 mTask.getWindowConfiguration().getAppBounds().height(), appBounds.height()); 1456 assertEquals("Bounds can include insets", mTask.getBounds().height(), 1457 activity.getBounds().height()); 1458 } 1459 1460 @Test 1461 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1462 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE}) testOverrideMinAspectRatioLargerThanManifest()1463 public void testOverrideMinAspectRatioLargerThanManifest() { 1464 setUpDisplaySizeWithApp(1400, 1600); 1465 1466 // Create a size compat activity on the same task. 1467 final ActivityRecord activity = new ActivityBuilder(mAtm) 1468 .setTask(mTask) 1469 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1470 .setComponent(ComponentName.createRelative(mContext, 1471 SizeCompatTests.class.getName())) 1472 .setMinAspectRatio(1.1f) 1473 .setUid(android.os.Process.myUid()) 1474 .build(); 1475 1476 // The per-package override should have no effect, because the manifest aspect ratio is 1477 // larger (2:1) 1478 assertEquals(1600, activity.getBounds().height()); 1479 assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 1480 activity.getBounds().width(), 0.5); 1481 } 1482 1483 @Test 1484 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1485 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE}) testOverrideMinAspectRatioLarge()1486 public void testOverrideMinAspectRatioLarge() { 1487 setUpDisplaySizeWithApp(1500, 1600); 1488 1489 // Create a size compat activity on the same task. 1490 final ActivityRecord activity = new ActivityBuilder(mAtm) 1491 .setTask(mTask) 1492 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1493 .setComponent(ComponentName.createRelative(mContext, 1494 SizeCompatTests.class.getName())) 1495 .setUid(android.os.Process.myUid()) 1496 .build(); 1497 1498 // The per-package override forces the activity into a 16:9 aspect ratio 1499 assertEquals(1600, activity.getBounds().height()); 1500 assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 1501 activity.getBounds().width(), 0.5); 1502 } 1503 1504 @Test 1505 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1506 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM, 1507 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE}) testOverrideMinAspectRatio_Both()1508 public void testOverrideMinAspectRatio_Both() { 1509 // If multiple override aspect ratios are set, we should use the largest one 1510 1511 setUpDisplaySizeWithApp(1400, 1600); 1512 1513 // Create a size compat activity on the same task. 1514 final ActivityRecord activity = new ActivityBuilder(mAtm) 1515 .setTask(mTask) 1516 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1517 .setComponent(ComponentName.createRelative(mContext, 1518 SizeCompatTests.class.getName())) 1519 .setUid(android.os.Process.myUid()) 1520 .build(); 1521 1522 // The per-package override forces the activity into a 16:9 aspect ratio 1523 assertEquals(1600, activity.getBounds().height()); 1524 assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 1525 activity.getBounds().width(), 0.5); 1526 } 1527 1528 @Test 1529 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1530 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY, 1531 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) testOverrideMinAspectRatioScreenOrientationNotSetThenChangedToPortrait()1532 public void testOverrideMinAspectRatioScreenOrientationNotSetThenChangedToPortrait() { 1533 // In this test, the activity's orientation isn't fixed to portrait, therefore the override 1534 // isn't applied. 1535 1536 setUpDisplaySizeWithApp(1000, 1200); 1537 1538 // Create a size compat activity on the same task. 1539 final ActivityRecord activity = new ActivityBuilder(mAtm) 1540 .setTask(mTask) 1541 .setComponent(ComponentName.createRelative(mContext, 1542 SizeCompatTests.class.getName())) 1543 .setUid(android.os.Process.myUid()) 1544 .build(); 1545 1546 // The per-package override should have no effect 1547 assertEquals(1200, activity.getBounds().height()); 1548 assertEquals(1000, activity.getBounds().width()); 1549 1550 // After changing the orientation to portrait the override should be applied. 1551 activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1552 activity.clearSizeCompatMode(); 1553 1554 // The per-package override forces the activity into a 3:2 aspect ratio 1555 assertEquals(1200, activity.getBounds().height()); 1556 assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 1557 activity.getBounds().width(), 0.5); 1558 } 1559 1560 @Test 1561 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1562 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY, 1563 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) testOverrideMinAspectRatioScreenOrientationLandscapeThenChangedToPortrait()1564 public void testOverrideMinAspectRatioScreenOrientationLandscapeThenChangedToPortrait() { 1565 // In this test, the activity's orientation isn't fixed to portrait, therefore the override 1566 // isn't applied. 1567 1568 setUpDisplaySizeWithApp(1000, 1200); 1569 1570 // Create a size compat activity on the same task. 1571 final ActivityRecord activity = new ActivityBuilder(mAtm) 1572 .setTask(mTask) 1573 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) 1574 .setComponent(ComponentName.createRelative(mContext, 1575 SizeCompatTests.class.getName())) 1576 .setUid(android.os.Process.myUid()) 1577 .build(); 1578 1579 // The per-package override should have no effect 1580 assertEquals(1200, activity.getBounds().height()); 1581 assertEquals(1000, activity.getBounds().width()); 1582 1583 // After changing the orientation to portrait the override should be applied. 1584 activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1585 activity.clearSizeCompatMode(); 1586 1587 // The per-package override forces the activity into a 3:2 aspect ratio 1588 assertEquals(1200, activity.getBounds().height()); 1589 assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 1590 activity.getBounds().width(), 0.5); 1591 } 1592 1593 @Test 1594 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1595 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY, 1596 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) testOverrideMinAspectRatioScreenOrientationPortraitThenChangedToUnspecified()1597 public void testOverrideMinAspectRatioScreenOrientationPortraitThenChangedToUnspecified() { 1598 setUpDisplaySizeWithApp(1000, 1200); 1599 1600 // Create a size compat activity on the same task. 1601 final ActivityRecord activity = new ActivityBuilder(mAtm) 1602 .setTask(mTask) 1603 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1604 .setComponent(ComponentName.createRelative(mContext, 1605 SizeCompatTests.class.getName())) 1606 .setUid(android.os.Process.myUid()) 1607 .build(); 1608 1609 // The per-package override forces the activity into a 3:2 aspect ratio 1610 assertEquals(1200, activity.getBounds().height()); 1611 assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 1612 activity.getBounds().width(), 0.5); 1613 1614 // After changing the orientation to landscape the override shouldn't be applied. 1615 activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 1616 activity.clearSizeCompatMode(); 1617 1618 // The per-package override should have no effect 1619 assertEquals(1200, activity.getBounds().height()); 1620 assertEquals(1000, activity.getBounds().width()); 1621 } 1622 1623 @Test 1624 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1625 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) 1626 @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY}) testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationNotSet()1627 public void testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationNotSet() { 1628 setUpDisplaySizeWithApp(1000, 1200); 1629 1630 // Create a size compat activity on the same task. 1631 final ActivityRecord activity = new ActivityBuilder(mAtm) 1632 .setTask(mTask) 1633 .setComponent(ComponentName.createRelative(mContext, 1634 SizeCompatTests.class.getName())) 1635 .setUid(android.os.Process.myUid()) 1636 .build(); 1637 1638 // The per-package override forces the activity into a 3:2 aspect ratio 1639 assertEquals(1200, activity.getBounds().height()); 1640 assertEquals(1200 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 1641 activity.getBounds().width(), 0.5); 1642 } 1643 1644 @Test 1645 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1646 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) 1647 @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY}) testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationLandscape()1648 public void testOverrideMinAspectRatioPortraitOnlyDisabledScreenOrientationLandscape() { 1649 // In this test, the activity's orientation isn't fixed to portrait, therefore the override 1650 // isn't applied. 1651 1652 setUpDisplaySizeWithApp(1000, 1200); 1653 1654 // Create a size compat activity on the same task. 1655 final ActivityRecord activity = new ActivityBuilder(mAtm) 1656 .setTask(mTask) 1657 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) 1658 .setComponent(ComponentName.createRelative(mContext, 1659 SizeCompatTests.class.getName())) 1660 .setUid(android.os.Process.myUid()) 1661 .build(); 1662 1663 // The per-package override forces the activity into a 3:2 aspect ratio 1664 assertEquals(1000 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM_VALUE, 1665 activity.getBounds().height(), 0.5); 1666 assertEquals(1000, activity.getBounds().width()); 1667 } 1668 1669 @Test 1670 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM}) testOverrideMinAspectRatioWithoutGlobalOverride()1671 public void testOverrideMinAspectRatioWithoutGlobalOverride() { 1672 // In this test, only OVERRIDE_MIN_ASPECT_RATIO_1_5 is set, which has no effect without 1673 // OVERRIDE_MIN_ASPECT_RATIO being also set. 1674 1675 setUpDisplaySizeWithApp(1000, 1200); 1676 1677 // Create a size compat activity on the same task. 1678 final ActivityRecord activity = new ActivityBuilder(mAtm) 1679 .setTask(mTask) 1680 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1681 .setComponent(ComponentName.createRelative(mContext, 1682 SizeCompatTests.class.getName())) 1683 .setUid(android.os.Process.myUid()) 1684 .build(); 1685 1686 // The per-package override should have no effect 1687 assertEquals(1200, activity.getBounds().height()); 1688 assertEquals(1000, activity.getBounds().width()); 1689 } 1690 1691 @Test 1692 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 1693 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE}) testOverrideMinAspectRatioLargeForResizableAppInSplitScreen()1694 public void testOverrideMinAspectRatioLargeForResizableAppInSplitScreen() { 1695 setUpDisplaySizeWithApp(/* dw= */ 1000, /* dh= */ 2800); 1696 1697 // Create a size compat activity on the same task. 1698 final ActivityRecord activity = new ActivityBuilder(mAtm) 1699 .setTask(mTask) 1700 .setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) 1701 .setComponent(ComponentName.createRelative(mContext, 1702 SizeCompatTests.class.getName())) 1703 .setUid(android.os.Process.myUid()) 1704 .build(); 1705 1706 final TestSplitOrganizer organizer = 1707 new TestSplitOrganizer(mAtm, activity.getDisplayContent()); 1708 1709 // Move activity to split screen which takes half of the screen. 1710 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 1711 organizer.mPrimary.setBounds(0, 0, 1000, 1400); 1712 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 1713 assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode()); 1714 1715 // The per-package override forces the activity into a 16:9 aspect ratio 1716 assertEquals(1400, activity.getBounds().height()); 1717 assertEquals(1400 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 1718 activity.getBounds().width(), 0.5); 1719 } 1720 1721 @Test testGetLetterboxInnerBounds_noScalingApplied()1722 public void testGetLetterboxInnerBounds_noScalingApplied() { 1723 // Set up a display in portrait and ignoring orientation request. 1724 final int dw = 1400; 1725 final int dh = 2800; 1726 setUpDisplaySizeWithApp(dw, dh); 1727 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1728 1729 // Rotate display to landscape. 1730 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 1731 1732 // Portrait fixed app without max aspect. 1733 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE); 1734 1735 // Need a window to call adjustBoundsForTaskbar with. 1736 addWindowToActivity(mActivity); 1737 1738 // App should launch in fullscreen. 1739 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1740 assertFalse(mActivity.inSizeCompatMode()); 1741 1742 // Activity inherits max bounds from TaskDisplayArea. 1743 assertMaxBoundsInheritDisplayAreaBounds(); 1744 1745 // Rotate display to portrait. 1746 rotateDisplay(mActivity.mDisplayContent, ROTATION_0); 1747 1748 final Rect rotatedDisplayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 1749 final Rect rotatedActivityBounds = new Rect(mActivity.getBounds()); 1750 assertTrue(rotatedDisplayBounds.width() < rotatedDisplayBounds.height()); 1751 1752 // App should be in size compat. 1753 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1754 assertScaled(); 1755 assertThat(mActivity.inSizeCompatMode()).isTrue(); 1756 assertActivityMaxBoundsSandboxed(); 1757 1758 1759 final int scale = dh / dw; 1760 1761 // App bounds should be dh / scale x dw / scale 1762 assertEquals(dw, rotatedDisplayBounds.width()); 1763 assertEquals(dh, rotatedDisplayBounds.height()); 1764 1765 assertEquals(dh / scale, rotatedActivityBounds.width()); 1766 assertEquals(dw / scale, rotatedActivityBounds.height()); 1767 1768 // Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}. 1769 mActivity.mRootWindowContainer.performSurfacePlacement(); 1770 1771 LetterboxDetails letterboxDetails = mActivity.mLetterboxUiController.getLetterboxDetails(); 1772 1773 assertEquals(dh / scale, letterboxDetails.getLetterboxInnerBounds().width()); 1774 assertEquals(dw / scale, letterboxDetails.getLetterboxInnerBounds().height()); 1775 1776 assertEquals(dw, letterboxDetails.getLetterboxFullBounds().width()); 1777 assertEquals(dh, letterboxDetails.getLetterboxFullBounds().height()); 1778 } 1779 1780 @Test 1781 public void testLaunchWithFixedRotationTransform() { 1782 final int dw = 1000; 1783 final int dh = 2500; 1784 final int notchHeight = 200; 1785 setUpApp(new TestDisplayContent.Builder(mAtm, dw, dh).setNotch(notchHeight).build()); 1786 addStatusBar(mActivity.mDisplayContent); 1787 1788 mActivity.setVisible(false); 1789 mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN); 1790 mActivity.mDisplayContent.mOpeningApps.add(mActivity); 1791 final float maxAspect = 1.8f; 1792 prepareUnresizable(mActivity, maxAspect, SCREEN_ORIENTATION_LANDSCAPE); 1793 1794 assertFitted(); 1795 assertTrue(mActivity.isFixedRotationTransforming()); 1796 // Display keeps in original orientation. 1797 assertEquals(Configuration.ORIENTATION_PORTRAIT, 1798 mActivity.mDisplayContent.getConfiguration().orientation); 1799 // The width should be restricted by the max aspect ratio = 1000 * 1.8 = 1800. 1800 assertEquals((int) (dw * maxAspect), mActivity.getBounds().width()); 1801 // The notch is at the left side of the landscape activity. The bounds should be horizontal 1802 // centered in the remaining area [200, 0 - 2500, 1000], so its left should be 1803 // 200 + (2300 - 1800) / 2 = 450. The bounds should be [450, 0 - 2250, 1000]. 1804 assertEquals(notchHeight + (dh - notchHeight - mActivity.getBounds().width()) / 2, 1805 mActivity.getBounds().left); 1806 1807 // The letterbox needs a main window to layout. 1808 final WindowState w = addWindowToActivity(mActivity); 1809 // Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}. 1810 mActivity.mRootWindowContainer.performSurfacePlacement(); 1811 // The letterbox insets should be [450, 0 - 250, 0]. 1812 assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0), 1813 mActivity.getLetterboxInsets()); 1814 1815 final DisplayPolicy displayPolicy = mActivity.mDisplayContent.getDisplayPolicy(); 1816 // The activity doesn't fill the display, so the letterbox of the rotated activity is 1817 // overlapped with the rotated content frame of status bar. Hence the status bar shouldn't 1818 // be transparent. 1819 assertFalse(displayPolicy.isFullyTransparentAllowed(w, ITYPE_STATUS_BAR)); 1820 1821 // Activity is sandboxed. 1822 assertActivityMaxBoundsSandboxed(); 1823 1824 // Make the activity fill the display. 1825 prepareUnresizable(mActivity, 10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE); 1826 w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; 1827 // Refresh the letterbox. 1828 mActivity.mRootWindowContainer.performSurfacePlacement(); 1829 1830 // The letterbox should only cover the notch area, so status bar can be transparent. 1831 assertEquals(new Rect(notchHeight, 0, 0, 0), mActivity.getLetterboxInsets()); 1832 assertTrue(displayPolicy.isFullyTransparentAllowed(w, ITYPE_STATUS_BAR)); 1833 assertActivityMaxBoundsSandboxed(); 1834 } 1835 1836 @Test 1837 public void testDisplayIgnoreOrientationRequest_fixedOrientationAppLaunchedLetterbox() { 1838 // Set up a display in landscape and ignoring orientation request. 1839 setUpDisplaySizeWithApp(2800, 1400); 1840 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1841 1842 // Portrait fixed app without max aspect. 1843 prepareUnresizable(mActivity, /* maxAspect= */ 0, SCREEN_ORIENTATION_PORTRAIT); 1844 1845 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 1846 final Rect activityBounds = new Rect(mActivity.getBounds()); 1847 1848 // Display shouldn't be rotated. 1849 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, 1850 mActivity.mDisplayContent.getLastOrientation()); 1851 assertTrue(displayBounds.width() > displayBounds.height()); 1852 1853 // App should launch in fixed orientation letterbox. 1854 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1855 assertFalse(mActivity.inSizeCompatMode()); 1856 assertActivityMaxBoundsSandboxed(); 1857 1858 // Activity bounds should be 700x1400 with the ratio as the display. 1859 assertEquals(displayBounds.height(), activityBounds.height()); 1860 assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(), 1861 activityBounds.width()); 1862 } 1863 1864 @Test testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMinAspectRatio()1865 public void testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMinAspectRatio() { 1866 // Set up a display in landscape and ignoring orientation request. 1867 setUpDisplaySizeWithApp(2800, 1400); 1868 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1869 1870 // Portrait fixed app with min aspect ratio higher that aspect ratio override for fixed 1871 // orientation letterbox. 1872 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); 1873 mActivity.info.setMinAspectRatio(3); 1874 prepareUnresizable(mActivity, /* maxAspect= */ 0, SCREEN_ORIENTATION_PORTRAIT); 1875 1876 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 1877 final Rect activityBounds = new Rect(mActivity.getBounds()); 1878 1879 // Display shouldn't be rotated. 1880 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, 1881 mActivity.mDisplayContent.getLastOrientation()); 1882 assertTrue(displayBounds.width() > displayBounds.height()); 1883 1884 // App should launch in fixed orientation letterbox. 1885 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1886 assertFalse(mActivity.inSizeCompatMode()); 1887 1888 // Activity bounds should respect minimum aspect ratio for activity. 1889 assertEquals(displayBounds.height(), activityBounds.height()); 1890 assertEquals((int) Math.rint(displayBounds.height() 1891 / mActivity.info.getManifestMinAspectRatio()), 1892 activityBounds.width()); 1893 } 1894 1895 @Test testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMaxAspectRatio()1896 public void testDisplayIgnoreOrientationRequest_fixedOrientationAppRespectMaxAspectRatio() { 1897 // Set up a display in landscape and ignoring orientation request. 1898 setUpDisplaySizeWithApp(2800, 1400); 1899 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1900 1901 // Portrait fixed app with max aspect ratio lower that aspect ratio override for fixed 1902 // orientation letterbox. 1903 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(3); 1904 prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT); 1905 1906 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 1907 final Rect activityBounds = new Rect(mActivity.getBounds()); 1908 1909 // Display shouldn't be rotated. 1910 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, 1911 mActivity.mDisplayContent.getLastOrientation()); 1912 assertTrue(displayBounds.width() > displayBounds.height()); 1913 1914 // App should launch in fixed orientation letterbox. 1915 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1916 assertFalse(mActivity.inSizeCompatMode()); 1917 1918 // Activity bounds should respect maximum aspect ratio for activity. 1919 assertEquals(displayBounds.height(), activityBounds.height()); 1920 assertEquals((int) Math.rint(displayBounds.height() 1921 / mActivity.info.getMaxAspectRatio()), 1922 activityBounds.width()); 1923 } 1924 1925 @Test testDisplayIgnoreOrientationRequest_fixedOrientationAppWithAspectRatioOverride()1926 public void testDisplayIgnoreOrientationRequest_fixedOrientationAppWithAspectRatioOverride() { 1927 // Set up a display in landscape and ignoring orientation request. 1928 setUpDisplaySizeWithApp(2800, 1400); 1929 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1930 1931 final float fixedOrientationLetterboxAspectRatio = 1.1f; 1932 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio( 1933 fixedOrientationLetterboxAspectRatio); 1934 prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false); 1935 1936 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 1937 final Rect activityBounds = new Rect(mActivity.getBounds()); 1938 1939 // Display shouldn't be rotated. 1940 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, 1941 mActivity.mDisplayContent.getLastOrientation()); 1942 assertTrue(displayBounds.width() > displayBounds.height()); 1943 1944 // App should launch in fixed orientation letterbox. 1945 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1946 assertFalse(mActivity.inSizeCompatMode()); 1947 1948 // Activity bounds should respect aspect ratio override for fixed orientation letterbox. 1949 assertEquals(displayBounds.height(), activityBounds.height()); 1950 assertEquals((int) Math.rint(displayBounds.height() / fixedOrientationLetterboxAspectRatio), 1951 activityBounds.width()); 1952 } 1953 1954 @Test testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio()1955 public void testDisplayIgnoreOrientationRequest_unresizableWithCorrespondingMinAspectRatio() { 1956 // Set up a display in landscape and ignoring orientation request. 1957 setUpDisplaySizeWithApp(2800, 1400); 1958 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1959 1960 final float fixedOrientationLetterboxAspectRatio = 1.1f; 1961 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio( 1962 fixedOrientationLetterboxAspectRatio); 1963 mActivity.mWmService.mLetterboxConfiguration.setDefaultMinAspectRatioForUnresizableApps( 1964 1.5f); 1965 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 1966 1967 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 1968 final Rect activityBounds = new Rect(mActivity.getBounds()); 1969 1970 // Display shouldn't be rotated. 1971 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, 1972 mActivity.mDisplayContent.getLastOrientation()); 1973 assertTrue(displayBounds.width() > displayBounds.height()); 1974 1975 // App should launch in fixed orientation letterbox. 1976 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 1977 assertFalse(mActivity.inSizeCompatMode()); 1978 1979 // Letterbox logic should use config_letterboxDefaultMinAspectRatioForUnresizableApps over 1980 // config_fixedOrientationLetterboxAspectRatio. 1981 assertEquals(displayBounds.height(), activityBounds.height()); 1982 final float defaultAspectRatio = mActivity.mWmService.mLetterboxConfiguration 1983 .getDefaultMinAspectRatioForUnresizableApps(); 1984 assertEquals(displayBounds.height() / defaultAspectRatio, activityBounds.width(), 0.5); 1985 } 1986 1987 @Test testComputeConfigResourceOverrides_unresizableApp()1988 public void testComputeConfigResourceOverrides_unresizableApp() { 1989 // Set up a display in landscape and ignoring orientation request. 1990 setUpDisplaySizeWithApp(2800, 1400); 1991 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 1992 1993 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 1994 1995 final Rect activityBounds = new Rect(mActivity.getBounds()); 1996 1997 int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp; 1998 int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp; 1999 2000 // App should launch in fixed orientation letterbox. 2001 // Activity bounds should be 700x1400 with the ratio as the display. 2002 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2003 assertFitted(); 2004 assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp); 2005 assertTrue(originalScreenWidthDp < originalScreenHeighthDp); 2006 2007 // Rotate display to portrait. 2008 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 2009 2010 // After we rotate, the activity should go in the size-compat mode and report the same 2011 // configuration values. 2012 assertScaled(); 2013 assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp); 2014 assertEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp); 2015 assertEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp); 2016 2017 // Restart activity 2018 mActivity.restartProcessIfVisible(); 2019 2020 // Now configuration should be updated 2021 assertFitted(); 2022 assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp); 2023 assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp); 2024 assertEquals(mActivity.getConfiguration().screenWidthDp, 2025 mActivity.getConfiguration().smallestScreenWidthDp); 2026 } 2027 2028 @Test 2029 public void testComputeConfigResourceOverrides_resizableFixedOrientationActivity() { 2030 // Set up a display in landscape and ignoring orientation request. 2031 setUpDisplaySizeWithApp(2800, 1400); 2032 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2033 2034 // Portrait fixed app without max aspect. 2035 prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */); 2036 2037 final Rect activityBounds = new Rect(mActivity.getBounds()); 2038 2039 int originalScreenWidthDp = mActivity.getConfiguration().screenWidthDp; 2040 int originalScreenHeighthDp = mActivity.getConfiguration().screenHeightDp; 2041 2042 // App should launch in fixed orientation letterbox. 2043 // Activity bounds should be 700x1400 with the ratio as the display. 2044 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2045 assertFitted(); 2046 assertEquals(originalScreenWidthDp, mActivity.getConfiguration().smallestScreenWidthDp); 2047 assertTrue(originalScreenWidthDp < originalScreenHeighthDp); 2048 2049 // Rotate display to portrait. 2050 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 2051 2052 // Now configuration should be updated 2053 assertFitted(); 2054 assertNotEquals(originalScreenWidthDp, mActivity.getConfiguration().screenWidthDp); 2055 assertNotEquals(originalScreenHeighthDp, mActivity.getConfiguration().screenHeightDp); 2056 assertEquals(mActivity.getConfiguration().screenWidthDp, 2057 mActivity.getConfiguration().smallestScreenWidthDp); 2058 } 2059 2060 @Test 2061 public void testSplitAspectRatioForUnresizablePortraitApps() { 2062 // Set up a display in landscape and ignoring orientation request. 2063 int screenWidth = 1600; 2064 int screenHeight = 1400; 2065 setUpDisplaySizeWithApp(screenWidth, screenHeight); 2066 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2067 mActivity.mWmService.mLetterboxConfiguration 2068 .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true); 2069 2070 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); 2071 2072 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 2073 2074 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 2075 final Rect activityBounds = new Rect(mActivity.getBounds()); 2076 2077 // App should launch in fixed orientation letterbox. 2078 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2079 // Checking that there is no size compat mode. 2080 assertFitted(); 2081 2082 assertEquals(displayBounds.height(), activityBounds.height()); 2083 assertTrue(activityBounds.width() < displayBounds.width() / 2); 2084 2085 final TestSplitOrganizer organizer = 2086 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 2087 // Move activity to split screen which takes half of the screen. 2088 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 2089 organizer.mPrimary.setBounds(0, 0, getExpectedSplitSize(screenWidth), screenHeight); 2090 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2091 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 2092 // Checking that there is no size compat mode. 2093 assertFitted(); 2094 } 2095 2096 @Test 2097 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2098 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) 2099 public void testOverrideSplitScreenAspectRatioForUnresizablePortraitApps() { 2100 final int displayWidth = 1400; 2101 final int displayHeight = 1600; 2102 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2103 final ActivityRecord activity = new ActivityBuilder(mAtm) 2104 .setTask(mTask) 2105 .setComponent(ComponentName.createRelative(mContext, 2106 SizeCompatTests.class.getName())) 2107 .setMinAspectRatio(1.1f) 2108 .setUid(android.os.Process.myUid()) 2109 .build(); 2110 // Setup Letterbox Configuration 2111 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2112 activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f); 2113 // Non-resizable portrait activity 2114 prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 2115 float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight); 2116 final Rect afterBounds = activity.getBounds(); 2117 final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width(); 2118 assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); 2119 } 2120 2121 @Test 2122 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2123 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) 2124 public void testOverrideSplitScreenAspectRatioForUnresizablePortraitAppsFromLandscape() { 2125 final int displayWidth = 1600; 2126 final int displayHeight = 1400; 2127 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2128 final ActivityRecord activity = new ActivityBuilder(mAtm) 2129 .setTask(mTask) 2130 .setComponent(ComponentName.createRelative(mContext, 2131 SizeCompatTests.class.getName())) 2132 .setMinAspectRatio(1.1f) 2133 .setUid(android.os.Process.myUid()) 2134 .build(); 2135 // Setup Letterbox Configuration 2136 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2137 activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f); 2138 // Non-resizable portrait activity 2139 prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 2140 float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth); 2141 final Rect afterBounds = activity.getBounds(); 2142 final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width(); 2143 assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); 2144 } 2145 2146 @Test 2147 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2148 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) 2149 @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY}) 2150 public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeApps() { 2151 final int displayWidth = 1400; 2152 final int displayHeight = 1600; 2153 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2154 final ActivityRecord activity = new ActivityBuilder(mAtm) 2155 .setTask(mTask) 2156 .setComponent(ComponentName.createRelative(mContext, 2157 SizeCompatTests.class.getName())) 2158 .setMinAspectRatio(1.1f) 2159 .setUid(android.os.Process.myUid()) 2160 .build(); 2161 // Setup Letterbox Configuration 2162 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2163 activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f); 2164 // Non-resizable portrait activity 2165 prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 2166 float expectedAspectRatio = 1f * displayWidth / getExpectedSplitSize(displayHeight); 2167 final Rect afterBounds = activity.getBounds(); 2168 final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height(); 2169 assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); 2170 } 2171 2172 @Test 2173 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2174 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) 2175 @DisableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY}) 2176 public void testOverrideSplitScreenAspectRatioForUnresizableLandscapeAppsFromLandscape() { 2177 final int displayWidth = 1600; 2178 final int displayHeight = 1400; 2179 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2180 final ActivityRecord activity = new ActivityBuilder(mAtm) 2181 .setTask(mTask) 2182 .setComponent(ComponentName.createRelative(mContext, 2183 SizeCompatTests.class.getName())) 2184 .setMinAspectRatio(1.1f) 2185 .setUid(android.os.Process.myUid()) 2186 .build(); 2187 // Setup Letterbox Configuration 2188 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2189 activity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.5f); 2190 // Non-resizable portrait activity 2191 prepareUnresizable(activity, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 2192 float expectedAspectRatio = 1f * displayHeight / getExpectedSplitSize(displayWidth); 2193 final Rect afterBounds = activity.getBounds(); 2194 final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height(); 2195 assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); 2196 } 2197 2198 @Test 2199 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2200 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) 2201 public void testOverrideSplitScreenAspectRatio_splitScreenActivityInPortrait_notLetterboxed() { 2202 mAtm.mDevEnableNonResizableMultiWindow = true; 2203 final int screenWidth = 1800; 2204 final int screenHeight = 1000; 2205 setUpDisplaySizeWithApp(screenWidth, screenHeight); 2206 final ActivityRecord activity = new ActivityBuilder(mAtm) 2207 .setTask(mTask) 2208 .setComponent(ComponentName.createRelative(mContext, 2209 SizeCompatTests.class.getName())) 2210 .setUid(android.os.Process.myUid()) 2211 .build(); 2212 2213 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2214 // Simulate real display with top insets. 2215 final int topInset = 30; 2216 activity.mDisplayContent.getWindowConfiguration() 2217 .setAppBounds(0, topInset, screenWidth, screenHeight); 2218 2219 final TestSplitOrganizer organizer = 2220 new TestSplitOrganizer(mAtm, activity.getDisplayContent()); 2221 // Move activity to split screen which takes half of the screen. 2222 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 2223 organizer.mPrimary.setBounds(0, 0, getExpectedSplitSize(screenWidth), screenHeight); 2224 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2225 assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode()); 2226 2227 // Unresizable portrait-only activity. 2228 prepareUnresizable(activity, 3f, SCREEN_ORIENTATION_PORTRAIT); 2229 2230 // Activity should have the aspect ratio of a split screen activity and occupy exactly one 2231 // half of the screen, so there is no letterbox 2232 float expectedAspectRatio = 1f * screenHeight / getExpectedSplitSize(screenWidth); 2233 final Rect afterBounds = activity.getBounds(); 2234 final float afterAspectRatio = (float) (afterBounds.height()) / afterBounds.width(); 2235 assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); 2236 assertFalse(activity.areBoundsLetterboxed()); 2237 } 2238 2239 @Test 2240 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2241 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN}) 2242 public void testOverrideSplitScreenAspectRatio_splitScreenActivityInLandscape_notLetterboxed() { 2243 mAtm.mDevEnableNonResizableMultiWindow = true; 2244 final int screenWidth = 1000; 2245 final int screenHeight = 1800; 2246 setUpDisplaySizeWithApp(screenWidth, screenHeight); 2247 final ActivityRecord activity = new ActivityBuilder(mAtm) 2248 .setTask(mTask) 2249 .setComponent(ComponentName.createRelative(mContext, 2250 SizeCompatTests.class.getName())) 2251 .setUid(android.os.Process.myUid()) 2252 .build(); 2253 2254 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2255 // Simulate real display with top insets. 2256 final int leftInset = 30; 2257 activity.mDisplayContent.getWindowConfiguration() 2258 .setAppBounds(leftInset, 0, screenWidth, screenHeight); 2259 2260 final TestSplitOrganizer organizer = 2261 new TestSplitOrganizer(mAtm, activity.getDisplayContent()); 2262 // Move activity to split screen which takes half of the screen. 2263 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 2264 organizer.mPrimary.setBounds(0, 0, screenWidth, getExpectedSplitSize(screenHeight)); 2265 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2266 assertEquals(WINDOWING_MODE_MULTI_WINDOW, activity.getWindowingMode()); 2267 2268 // Unresizable landscape-only activity. 2269 prepareUnresizable(activity, 3f, SCREEN_ORIENTATION_LANDSCAPE); 2270 2271 // Activity should have the aspect ratio of a split screen activity and occupy exactly one 2272 // half of the screen, so there is no letterbox 2273 float expectedAspectRatio = 1f * screenWidth / getExpectedSplitSize(screenHeight); 2274 final Rect afterBounds = activity.getBounds(); 2275 final float afterAspectRatio = (float) (afterBounds.width()) / afterBounds.height(); 2276 assertEquals(expectedAspectRatio, afterAspectRatio, 0.001f); 2277 assertFalse(activity.areBoundsLetterboxed()); 2278 } 2279 2280 @Test 2281 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2282 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE, 2283 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN}) 2284 public void testOverrideMinAspectRatioExcludePortraitFullscreen() { 2285 setUpDisplaySizeWithApp(2600, 1600); 2286 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2287 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f); 2288 2289 // Create a size compat activity on the same task. 2290 final ActivityRecord activity = new ActivityBuilder(mAtm) 2291 .setTask(mTask) 2292 .setComponent(ComponentName.createRelative(mContext, 2293 SizeCompatTests.class.getName())) 2294 .setUid(android.os.Process.myUid()) 2295 .build(); 2296 2297 // Non-resizable portrait activity 2298 prepareUnresizable(activity, 0f, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 2299 2300 // At first, OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply, because the 2301 // display is in landscape 2302 assertEquals(1600, activity.getBounds().height()); 2303 assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 2304 activity.getBounds().width(), 0.5); 2305 2306 rotateDisplay(activity.mDisplayContent, ROTATION_90); 2307 prepareUnresizable(activity, /* maxAspect */ 0, SCREEN_ORIENTATION_PORTRAIT); 2308 2309 // Now the display is in portrait fullscreen, so the override is applied making the content 2310 // fullscreen 2311 assertEquals(activity.getBounds(), activity.mDisplayContent.getBounds()); 2312 } 2313 2314 @Test 2315 @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO, 2316 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE, 2317 ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN}) 2318 public void testOverrideMinAspectRatioExcludePortraitFullscreenNotApplied() { 2319 // In this test, the activity is not in fullscreen, so the override is not applied 2320 setUpDisplaySizeWithApp(2600, 1600); 2321 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2322 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f); 2323 2324 // Create a size compat activity on the same task. 2325 final ActivityRecord activity = new ActivityBuilder(mAtm) 2326 .setTask(mTask) 2327 .setComponent(ComponentName.createRelative(mContext, 2328 SizeCompatTests.class.getName())) 2329 .setUid(android.os.Process.myUid()) 2330 .build(); 2331 2332 final TestSplitOrganizer organizer = 2333 new TestSplitOrganizer(mAtm, activity.getDisplayContent()); 2334 2335 // Move first activity to split screen which takes half of the screen. 2336 organizer.mPrimary.setBounds(0, 0, 1300, 1600); 2337 organizer.putTaskToPrimary(mTask, true); 2338 2339 // Non-resizable portrait activity 2340 prepareUnresizable(activity, /* maxAspect */ 0, SCREEN_ORIENTATION_PORTRAIT); 2341 2342 // OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply here because the 2343 // display is not in fullscreen, so OVERRIDE_MIN_ASPECT_RATIO_LARGE applies instead 2344 assertEquals(1600, activity.getBounds().height()); 2345 assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, 2346 activity.getBounds().width(), 0.5); 2347 } 2348 2349 @Test 2350 @EnableCompatChanges({ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION}) 2351 public void testOverrideRespectRequestedOrientationIsEnabled_orientationIsRespected() { 2352 // Set up a display in landscape 2353 setUpDisplaySizeWithApp(2800, 1400); 2354 2355 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */ false, 2356 RESIZE_MODE_UNRESIZEABLE, SCREEN_ORIENTATION_PORTRAIT); 2357 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2358 2359 // Display should be rotated. 2360 assertEquals(SCREEN_ORIENTATION_PORTRAIT, activity.mDisplayContent.getOrientation()); 2361 2362 // No size compat mode 2363 assertFalse(activity.inSizeCompatMode()); 2364 } 2365 2366 @Test 2367 @EnableCompatChanges({ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION}) 2368 public void testOverrideRespectRequestedOrientationIsEnabled_multiWindow_orientationIgnored() { 2369 // Set up a display in landscape 2370 setUpDisplaySizeWithApp(2800, 1400); 2371 2372 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */ false, 2373 RESIZE_MODE_UNRESIZEABLE, SCREEN_ORIENTATION_PORTRAIT); 2374 TaskFragment taskFragment = activity.getTaskFragment(); 2375 spyOn(taskFragment); 2376 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2377 doReturn(WINDOWING_MODE_MULTI_WINDOW).when(taskFragment).getWindowingMode(); 2378 2379 // Display should not be rotated. 2380 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.mDisplayContent.getOrientation()); 2381 2382 // No size compat mode 2383 assertFalse(activity.inSizeCompatMode()); 2384 } 2385 2386 @Test 2387 public void testSplitAspectRatioForUnresizableLandscapeApps() { 2388 // Set up a display in portrait and ignoring orientation request. 2389 int screenWidth = 1400; 2390 int screenHeight = 1600; 2391 setUpDisplaySizeWithApp(screenWidth, screenHeight); 2392 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2393 mActivity.mWmService.mLetterboxConfiguration 2394 .setIsSplitScreenAspectRatioForUnresizableAppsEnabled(true); 2395 2396 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); 2397 2398 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 2399 2400 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 2401 final Rect activityBounds = new Rect(mActivity.getBounds()); 2402 2403 // App should launch in fixed orientation letterbox. 2404 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2405 // Checking that there is no size compat mode. 2406 assertFitted(); 2407 2408 assertEquals(displayBounds.width(), activityBounds.width()); 2409 assertTrue(activityBounds.height() < displayBounds.height() / 2); 2410 2411 final TestSplitOrganizer organizer = 2412 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 2413 // Move activity to split screen which takes half of the screen. 2414 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 2415 organizer.mPrimary.setBounds(0, 0, screenWidth, getExpectedSplitSize(screenHeight)); 2416 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2417 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 2418 // Checking that there is no size compat mode. 2419 assertFitted(); 2420 } 2421 2422 @Test 2423 public void testDisplayAspectRatioForResizablePortraitApps() { 2424 // Set up a display in portrait and ignoring orientation request. 2425 int displayWidth = 1400; 2426 int displayHeight = 1600; 2427 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2428 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2429 mWm.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(2f); 2430 2431 // Enable display aspect ratio to take precedence before 2432 // fixedOrientationLetterboxAspectRatio 2433 mWm.mLetterboxConfiguration 2434 .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true); 2435 2436 // Set up resizable app in portrait 2437 prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_PORTRAIT, false /* isUnresizable */); 2438 2439 final TestSplitOrganizer organizer = 2440 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 2441 // Move activity to split screen which takes half of the screen. 2442 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 2443 organizer.mPrimary.setBounds(0, 0, displayWidth, getExpectedSplitSize(displayHeight)); 2444 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2445 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 2446 2447 // App should launch in fixed orientation letterbox. 2448 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2449 // Checking that there is no size compat mode. 2450 assertFitted(); 2451 // Check that the display aspect ratio is used by the app. 2452 final float targetMinAspectRatio = 1f * displayHeight / displayWidth; 2453 final float delta = 0.01f; 2454 assertEquals(targetMinAspectRatio, ActivityRecord 2455 .computeAspectRatio(mActivity.getBounds()), delta); 2456 } 2457 2458 @Test 2459 public void testDisplayAspectRatioForResizableLandscapeApps() { 2460 // Set up a display in landscape and ignoring orientation request. 2461 int displayWidth = 1600; 2462 int displayHeight = 1400; 2463 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2464 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2465 mWm.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(2f); 2466 2467 // Enable display aspect ratio to take precedence before 2468 // fixedOrientationLetterboxAspectRatio 2469 mWm.mLetterboxConfiguration 2470 .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true); 2471 2472 // Set up resizable app in landscape 2473 prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_LANDSCAPE, false /* isUnresizable */); 2474 2475 final TestSplitOrganizer organizer = 2476 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 2477 // Move activity to split screen which takes half of the screen. 2478 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 2479 organizer.mPrimary.setBounds(0, 0, getExpectedSplitSize(displayWidth), displayHeight); 2480 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2481 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 2482 2483 // App should launch in fixed orientation letterbox. 2484 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2485 // Checking that there is no size compat mode. 2486 assertFitted(); 2487 // Check that the display aspect ratio is used by the app. 2488 final float targetMinAspectRatio = 1f * displayWidth / displayHeight; 2489 final float delta = 0.01f; 2490 assertEquals(targetMinAspectRatio, ActivityRecord 2491 .computeAspectRatio(mActivity.getBounds()), delta); 2492 } 2493 2494 @Test 2495 public void testDisplayAspectRatioForUnresizableLandscapeApps() { 2496 // Set up a display in portrait and ignoring orientation request. 2497 int displayWidth = 1400; 2498 int displayHeight = 1600; 2499 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2500 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2501 2502 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); 2503 // Enable display aspect ratio to take precedence before 2504 // fixedOrientationLetterboxAspectRatio 2505 mWm.mLetterboxConfiguration 2506 .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true); 2507 2508 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 2509 2510 // App should launch in fixed orientation letterbox. 2511 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2512 // Checking that there is no size compat mode. 2513 assertFitted(); 2514 // Check that the display aspect ratio is used by the app. 2515 final float targetMinAspectRatio = 1f * displayHeight / displayWidth; 2516 final float delta = 0.01f; 2517 assertEquals(targetMinAspectRatio, ActivityRecord 2518 .computeAspectRatio(mActivity.getBounds()), delta); 2519 } 2520 2521 @Test 2522 public void testDisplayAspectRatioForUnresizablePortraitApps() { 2523 // Set up a display in landscape and ignoring orientation request. 2524 int displayWidth = 1600; 2525 int displayHeight = 1400; 2526 setUpDisplaySizeWithApp(displayWidth, displayHeight); 2527 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2528 2529 mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.1f); 2530 // Enable display aspect ratio to take precedence before 2531 // fixedOrientationLetterboxAspectRatio 2532 mWm.mLetterboxConfiguration 2533 .setIsDisplayAspectRatioEnabledForFixedOrientationLetterbox(true); 2534 2535 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 2536 2537 // App should launch in fixed orientation letterbox. 2538 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2539 // Checking that there is no size compat mode. 2540 assertFitted(); 2541 // Check that the display aspect ratio is used by the app. 2542 final float targetMinAspectRatio = 1f * displayWidth / displayHeight; 2543 final float delta = 0.01f; 2544 assertEquals(targetMinAspectRatio, ActivityRecord 2545 .computeAspectRatio(mActivity.getBounds()), delta); 2546 } 2547 2548 @Test 2549 public void 2550 testDisplayIgnoreOrientationRequest_orientationLetterboxBecameSizeCompatAfterRotate() { 2551 // Set up a display in landscape and ignoring orientation request. 2552 setUpDisplaySizeWithApp(2800, 1400); 2553 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2554 2555 // Portrait fixed app without max aspect. 2556 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2557 2558 final Rect activityBounds = new Rect(mActivity.getBounds()); 2559 2560 // Rotate display to portrait. 2561 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 2562 2563 final Rect displayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 2564 final Rect newActivityBounds = new Rect(mActivity.getBounds()); 2565 assertTrue(displayBounds.width() < displayBounds.height()); 2566 2567 // App should be in size compat. 2568 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2569 assertScaled(); 2570 assertEquals(activityBounds.width(), newActivityBounds.width()); 2571 assertEquals(activityBounds.height(), newActivityBounds.height()); 2572 assertActivityMaxBoundsSandboxed(); 2573 } 2574 2575 @Test 2576 public void testDisplayIgnoreOrientationRequest_sizeCompatAfterRotate() { 2577 // Set up a display in portrait and ignoring orientation request. 2578 setUpDisplaySizeWithApp(1400, 2800); 2579 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2580 2581 // Portrait fixed app without max aspect. 2582 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2583 2584 // App should launch in fullscreen. 2585 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2586 assertFalse(mActivity.inSizeCompatMode()); 2587 // Activity inherits max bounds from TaskDisplayArea. 2588 assertMaxBoundsInheritDisplayAreaBounds(); 2589 2590 // Rotate display to landscape. 2591 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 2592 2593 final Rect rotatedDisplayBounds = new Rect(mActivity.mDisplayContent.getBounds()); 2594 final Rect rotatedActivityBounds = new Rect(mActivity.getBounds()); 2595 assertTrue(rotatedDisplayBounds.width() > rotatedDisplayBounds.height()); 2596 2597 // App should be in size compat. 2598 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2599 assertScaled(); 2600 assertThat(mActivity.inSizeCompatMode()).isTrue(); 2601 assertActivityMaxBoundsSandboxed(); 2602 2603 // App bounds should be 700x1400 with the ratio as the display. 2604 assertEquals(rotatedDisplayBounds.height(), rotatedActivityBounds.height()); 2605 assertEquals(rotatedDisplayBounds.height() * rotatedDisplayBounds.height() 2606 / rotatedDisplayBounds.width(), rotatedActivityBounds.width()); 2607 } 2608 2609 @Test 2610 public void testDisplayIgnoreOrientationRequest_newLaunchedOrientationAppInLetterbox() { 2611 // Set up a display in landscape and ignoring orientation request. 2612 setUpDisplaySizeWithApp(2800, 1400); 2613 final DisplayContent display = mActivity.mDisplayContent; 2614 display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2615 2616 // Portrait fixed app without max aspect. 2617 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2618 2619 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2620 assertFalse(mActivity.inSizeCompatMode()); 2621 2622 // Launch another portrait fixed app. 2623 spyOn(mTask); 2624 setBooted(display.mWmService.mAtmService); 2625 final ActivityRecord newActivity = new ActivityBuilder(display.mWmService.mAtmService) 2626 .setResizeMode(RESIZE_MODE_UNRESIZEABLE) 2627 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 2628 .setTask(mTask) 2629 .build(); 2630 2631 // Update with new activity requested orientation and recompute bounds with no previous 2632 // size compat cache. 2633 verify(mTask).onDescendantOrientationChanged(same(newActivity)); 2634 2635 final Rect displayBounds = new Rect(display.getBounds()); 2636 final Rect taskBounds = new Rect(mTask.getBounds()); 2637 final Rect newActivityBounds = new Rect(newActivity.getBounds()); 2638 2639 // Task and display bounds should be equal while activity should be letterboxed and 2640 // has 700x1400 bounds with the ratio as the display. 2641 assertTrue(newActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2642 assertFalse(newActivity.inSizeCompatMode()); 2643 // Activity max bounds are sandboxed due to size compat mode. 2644 assertThat(newActivity.getConfiguration().windowConfiguration.getMaxBounds()) 2645 .isEqualTo(newActivity.getWindowConfiguration().getBounds()); 2646 assertEquals(taskBounds, displayBounds); 2647 assertEquals(displayBounds.height(), newActivityBounds.height()); 2648 assertEquals(displayBounds.height() * displayBounds.height() / displayBounds.width(), 2649 newActivityBounds.width()); 2650 } 2651 2652 @Test 2653 public void testDisplayIgnoreOrientationRequest_orientationChangedToUnspecified() { 2654 // Set up a display in landscape and ignoring orientation request. 2655 setUpDisplaySizeWithApp(2800, 1400); 2656 final DisplayContent display = mActivity.mDisplayContent; 2657 display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2658 2659 // Portrait fixed app without max aspect. 2660 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2661 2662 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2663 assertFalse(mActivity.inSizeCompatMode()); 2664 2665 mActivity.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED); 2666 // Activity is not in size compat mode because the orientation change request came from the 2667 // app itself 2668 assertFalse(mActivity.inSizeCompatMode()); 2669 assertEquals(mActivity.getResolvedOverrideConfiguration().orientation, 2670 Configuration.ORIENTATION_UNDEFINED); 2671 } 2672 2673 @Test 2674 public void testDisplayIgnoreOrientationRequest_newLaunchedMaxAspectApp() { 2675 // Set up a display in landscape and ignoring orientation request. 2676 setUpDisplaySizeWithApp(2800, 1400); 2677 final DisplayContent display = mActivity.mDisplayContent; 2678 display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2679 2680 // Portrait fixed app without max aspect. 2681 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2682 2683 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2684 assertFalse(mActivity.inSizeCompatMode()); 2685 2686 // Launch another portrait fixed app with max aspect ratio as 1.3. 2687 spyOn(mTask); 2688 setBooted(display.mWmService.mAtmService); 2689 final ActivityRecord newActivity = new ActivityBuilder(display.mWmService.mAtmService) 2690 .setResizeMode(RESIZE_MODE_UNRESIZEABLE) 2691 .setMaxAspectRatio(1.3f) 2692 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 2693 .setTask(mTask) 2694 .build(); 2695 2696 // Update with new activity requested orientation and recompute bounds with no previous 2697 // size compat cache. 2698 verify(mTask).onDescendantOrientationChanged(same(newActivity)); 2699 2700 final Rect displayBounds = new Rect(display.getBounds()); 2701 final Rect taskBounds = new Rect(mTask.getBounds()); 2702 final Rect newActivityBounds = new Rect(newActivity.getBounds()); 2703 2704 // Task bounds should fill parent bounds. 2705 assertEquals(displayBounds, taskBounds); 2706 2707 // Prior and new activity max bounds are sandboxed due to letterbox. 2708 assertThat(newActivity.getConfiguration().windowConfiguration.getMaxBounds()) 2709 .isEqualTo(newActivityBounds); 2710 assertActivityMaxBoundsSandboxed(); 2711 2712 // Activity bounds should be (1400 / 1.3 = 1076)x1400 with the app requested ratio. 2713 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2714 assertFalse(newActivity.inSizeCompatMode()); 2715 assertEquals(displayBounds.height(), newActivityBounds.height()); 2716 assertEquals((long) Math.rint(newActivityBounds.height() 2717 / newActivity.info.getMaxAspectRatio()), 2718 newActivityBounds.width()); 2719 } 2720 2721 @Test 2722 public void testDisplayIgnoreOrientationRequest_pausedAppNotLostSizeCompat() { 2723 // Set up a display in landscape and ignoring orientation request. 2724 setUpDisplaySizeWithApp(2800, 1400); 2725 final DisplayContent display = mActivity.mDisplayContent; 2726 display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2727 2728 // Portrait fixed app. 2729 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2730 clearInvocations(mActivity); 2731 2732 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2733 assertFalse(mActivity.inSizeCompatMode()); 2734 2735 // Rotate display to portrait. 2736 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 2737 2738 // App should be in size compat. 2739 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2740 assertScaled(); 2741 assertThat(mActivity.inSizeCompatMode()).isTrue(); 2742 // Activity max bounds are sandboxed due to size compat mode. 2743 assertActivityMaxBoundsSandboxed(); 2744 2745 final Rect activityBounds = new Rect(mActivity.getBounds()); 2746 mTask.resumeTopActivityUncheckedLocked(null /* prev */, null /* options */); 2747 2748 // App still in size compat, and the bounds don't change. 2749 verify(mActivity, never()).clearSizeCompatMode(); 2750 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2751 assertScaled(); 2752 assertEquals(activityBounds, mActivity.getBounds()); 2753 // Activity max bounds are sandboxed due to size compat. 2754 assertActivityMaxBoundsSandboxed(); 2755 } 2756 2757 @Test 2758 public void testDisplayIgnoreOrientationRequest_rotated180_notInSizeCompat() { 2759 // Set up a display in landscape and ignoring orientation request. 2760 setUpDisplaySizeWithApp(2800, 1400); 2761 final DisplayContent display = mActivity.mDisplayContent; 2762 display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2763 2764 // Portrait fixed app. 2765 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_PORTRAIT); 2766 2767 // In fixed orientation letterbox 2768 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2769 assertFalse(mActivity.inSizeCompatMode()); 2770 assertActivityMaxBoundsSandboxed(); 2771 2772 // Rotate display to portrait. 2773 rotateDisplay(display, ROTATION_90); 2774 2775 // App should be in size compat. 2776 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2777 assertScaled(); 2778 assertActivityMaxBoundsSandboxed(); 2779 2780 // Rotate display to landscape. 2781 rotateDisplay(display, ROTATION_180); 2782 2783 // In activity letterbox 2784 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2785 assertFalse(mActivity.inSizeCompatMode()); 2786 assertActivityMaxBoundsSandboxed(); 2787 } 2788 2789 @Test 2790 public void testDisplayIgnoreOrientationRequestWithInsets_rotated180_notInSizeCompat() { 2791 // Set up a display in portrait with display cutout and ignoring orientation request. 2792 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1400, 2800) 2793 .setNotch(75) 2794 .build(); 2795 setUpApp(display); 2796 display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2797 2798 // Landscape fixed app. 2799 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE); 2800 2801 // In fixed orientation letterbox 2802 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2803 assertFalse(mActivity.inSizeCompatMode()); 2804 assertActivityMaxBoundsSandboxed(); 2805 2806 // Rotate display to landscape. 2807 rotateDisplay(display, ROTATION_90); 2808 2809 // App should be in size compat. 2810 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2811 assertScaled(); 2812 assertActivityMaxBoundsSandboxed(); 2813 2814 // Rotate display to portrait. 2815 rotateDisplay(display, ROTATION_180); 2816 2817 // In fixed orientation letterbox 2818 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 2819 assertFalse(mActivity.inSizeCompatMode()); 2820 assertActivityMaxBoundsSandboxed(); 2821 } 2822 2823 @Test 2824 public void testDisplayIgnoreOrientationRequest_disabledViaDeviceConfig_orientationRespected() { 2825 // Set up a display in landscape 2826 setUpDisplaySizeWithApp(2800, 1400); 2827 2828 final ActivityRecord activity = buildActivityRecord(/* supportsSizeChanges= */ false, 2829 RESIZE_MODE_UNRESIZEABLE, SCREEN_ORIENTATION_PORTRAIT); 2830 activity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2831 2832 spyOn(activity.mWmService.mLetterboxConfiguration); 2833 doReturn(true).when(activity.mWmService.mLetterboxConfiguration) 2834 .isIgnoreOrientationRequestAllowed(); 2835 2836 // Display should not be rotated. 2837 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.mDisplayContent.getOrientation()); 2838 2839 doReturn(false).when(activity.mWmService.mLetterboxConfiguration) 2840 .isIgnoreOrientationRequestAllowed(); 2841 2842 // Display should be rotated. 2843 assertEquals(SCREEN_ORIENTATION_PORTRAIT, activity.mDisplayContent.getOrientation()); 2844 } 2845 2846 @Test 2847 public void testSandboxDisplayApis_unresizableAppNotSandboxed() { 2848 // Set up a display in landscape with an unresizable app. 2849 setUpDisplaySizeWithApp(2500, 1000); 2850 mActivity.mDisplayContent.setSandboxDisplayApis(false /* sandboxDisplayApis */); 2851 prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 2852 assertFitted(); 2853 2854 // Activity max bounds not be sandboxed since sandboxing is disabled. 2855 assertMaxBoundsInheritDisplayAreaBounds(); 2856 } 2857 2858 @Test 2859 public void testSandboxDisplayApis_unresizableAppSandboxed() { 2860 // Set up a display in landscape with an unresizable app. 2861 setUpDisplaySizeWithApp(2500, 1000); 2862 mActivity.mDisplayContent.setSandboxDisplayApis(true /* sandboxDisplayApis */); 2863 prepareUnresizable(mActivity, 1.5f, SCREEN_ORIENTATION_LANDSCAPE); 2864 assertFitted(); 2865 2866 // Activity max bounds should be sandboxed since sandboxing is enabled. 2867 assertActivityMaxBoundsSandboxed(); 2868 } 2869 2870 @Test 2871 public void testResizableApp_notSandboxed() { 2872 // Set up a display in landscape with a fully resizable app. 2873 setUpDisplaySizeWithApp(2500, 1000); 2874 prepareLimitedBounds(mActivity, /* maxAspect= */ -1, 2875 SCREEN_ORIENTATION_UNSPECIFIED, /* isUnresizable= */ false); 2876 assertFitted(); 2877 2878 // Activity max bounds not be sandboxed since app is fully resizable. 2879 assertMaxBoundsInheritDisplayAreaBounds(); 2880 } 2881 2882 @Test 2883 public void testResizableMaxAspectApp_notSandboxed() { 2884 // Set up a display in landscape with a fully resizable app. 2885 setUpDisplaySizeWithApp(2500, 1000); 2886 prepareLimitedBounds(mActivity, /* maxAspect= */ 1, 2887 SCREEN_ORIENTATION_UNSPECIFIED, /* isUnresizable= */ false); 2888 assertFitted(); 2889 2890 // Activity max bounds not be sandboxed since app is fully resizable. 2891 assertMaxBoundsInheritDisplayAreaBounds(); 2892 } 2893 2894 @Test 2895 public void testResizableOrientationRequestApp_notSandboxed() { 2896 // Set up a display in landscape with a fully resizable app. 2897 setUpDisplaySizeWithApp(2500, 1000); 2898 prepareLimitedBounds(mActivity, /* maxAspect= */ -1, 2899 SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false); 2900 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2901 assertFitted(); 2902 2903 // Activity max bounds not be sandboxed since app is fully resizable. 2904 assertMaxBoundsInheritDisplayAreaBounds(); 2905 } 2906 2907 @Test 2908 public void testResizableMaxAspectOrientationRequestApp_notSandboxed() { 2909 // Set up a display in landscape with a fully resizable app. 2910 setUpDisplaySizeWithApp(2500, 1000); 2911 prepareLimitedBounds(mActivity, /* maxAspect= */ 1, 2912 SCREEN_ORIENTATION_PORTRAIT, /* isUnresizable= */ false); 2913 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 2914 assertFitted(); 2915 2916 // Activity max bounds not be sandboxed since app is fully resizable. 2917 assertMaxBoundsInheritDisplayAreaBounds(); 2918 } 2919 2920 @Test 2921 public void testUnresizableApp_isSandboxed() { 2922 // Set up a display in landscape with a fully resizable app. 2923 setUpDisplaySizeWithApp(2500, 1000); 2924 prepareLimitedBounds(mActivity, /* maxAspect= */ -1, 2925 SCREEN_ORIENTATION_UNSPECIFIED, /* isUnresizable= */ true); 2926 assertFitted(); 2927 2928 // Activity max bounds are sandboxed since app may enter size compat mode. 2929 assertActivityMaxBoundsSandboxed(); 2930 assertFalse(mActivity.inSizeCompatMode()); 2931 } 2932 2933 @Test 2934 public void testUnresizableMaxAspectApp_isSandboxed() { 2935 // Set up a display in landscape with a fully resizable app. 2936 setUpDisplaySizeWithApp(2500, 1000); 2937 prepareLimitedBounds(mActivity, /* maxAspect= */ 1, 2938 SCREEN_ORIENTATION_UNSPECIFIED, /* isUnresizable= */ true); 2939 assertFitted(); 2940 2941 // Activity max bounds are sandboxed since app may enter size compat mode. 2942 assertActivityMaxBoundsSandboxed(); 2943 assertFalse(mActivity.inSizeCompatMode()); 2944 assertTrue(mActivity.shouldCreateCompatDisplayInsets()); 2945 2946 // Resize display to half the width. 2947 resizeDisplay(mActivity.getDisplayContent(), 500, 1000); 2948 2949 // Activity now in size compat mode. 2950 assertActivityMaxBoundsSandboxed(); 2951 assertTrue(mActivity.inSizeCompatMode()); 2952 } 2953 2954 @Test 2955 public void testTaskDisplayAreaNotFillDisplay() { 2956 setUpDisplaySizeWithApp(1400, 2800); 2957 final DisplayContent display = mActivity.mDisplayContent; 2958 final TaskDisplayArea taskDisplayArea = mActivity.getDisplayArea(); 2959 taskDisplayArea.setBounds(0, 0, 1000, 2400); 2960 2961 // Portrait fixed app. 2962 prepareUnresizable(mActivity, 0, SCREEN_ORIENTATION_LANDSCAPE); 2963 2964 final Rect displayBounds = new Rect(display.getBounds()); 2965 assertEquals(ORIENTATION_LANDSCAPE, display.getConfiguration().orientation); 2966 assertEquals(2800, displayBounds.width()); 2967 assertEquals(1400, displayBounds.height()); 2968 Rect displayAreaBounds = new Rect(0, 0, 2400, 1000); 2969 taskDisplayArea.setBounds(displayAreaBounds); 2970 2971 final Rect activityBounds = new Rect(mActivity.getBounds()); 2972 assertFalse(mActivity.inSizeCompatMode()); 2973 assertEquals(2400, activityBounds.width()); 2974 assertEquals(1000, activityBounds.height()); 2975 // Task and activity maximum bounds inherit from TaskDisplayArea bounds. 2976 assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds()) 2977 .isEqualTo(displayAreaBounds); 2978 assertThat(mTask.getConfiguration().windowConfiguration.getMaxBounds()) 2979 .isEqualTo(displayAreaBounds); 2980 } 2981 2982 @Test 2983 public void testSupportsNonResizableInSplitScreen_letterboxForDifferentOrientation() { 2984 // Support non resizable in multi window 2985 mAtm.mDevEnableNonResizableMultiWindow = true; 2986 setUpDisplaySizeWithApp(1000, 2800); 2987 final TestSplitOrganizer organizer = 2988 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 2989 2990 // Non-resizable landscape activity 2991 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 2992 final Rect originalBounds = new Rect(mActivity.getBounds()); 2993 2994 // Move activity to split screen which takes half of the screen. 2995 mTask.reparent(organizer.mPrimary, POSITION_TOP, 2996 false /*moveParents*/, "test"); 2997 organizer.mPrimary.setBounds(0, 0, 1000, 1400); 2998 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 2999 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 3000 3001 // Non-resizable activity in size compat mode 3002 assertScaled(); 3003 final Rect newBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 3004 assertEquals(originalBounds.width(), newBounds.width()); 3005 assertEquals(originalBounds.height(), newBounds.height()); 3006 assertActivityMaxBoundsSandboxed(); 3007 3008 recomputeNaturalConfigurationOfUnresizableActivity(); 3009 3010 // Split screen is also in portrait [1000,1400], so activity should be in fixed orientation 3011 // letterbox. 3012 assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation); 3013 assertEquals(ORIENTATION_LANDSCAPE, mActivity.getConfiguration().orientation); 3014 assertFitted(); 3015 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 3016 assertActivityMaxBoundsSandboxed(); 3017 3018 // Letterbox should fill the gap between the split screen and the letterboxed activity. 3019 assertLetterboxSurfacesDrawnBetweenActivityAndParentBounds(organizer.mPrimary.getBounds()); 3020 } 3021 3022 @Test 3023 public void testResizableFixedOrientationAppInSplitScreen_letterboxForDifferentOrientation() { 3024 setUpDisplaySizeWithApp(1000, 2800); 3025 final TestSplitOrganizer organizer = 3026 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3027 3028 // Resizable landscape-only activity. 3029 prepareLimitedBounds(mActivity, SCREEN_ORIENTATION_LANDSCAPE, /* isUnresizable= */ false); 3030 3031 final Rect originalBounds = new Rect(mActivity.getBounds()); 3032 3033 // Move activity to split screen which takes half of the screen. 3034 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 3035 organizer.mPrimary.setBounds(0, 0, 1000, 1400); 3036 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 3037 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 3038 3039 // Resizable activity is not in size compat mode but in the letterbox for fixed orientation. 3040 assertFitted(); 3041 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 3042 } 3043 3044 @Test 3045 public void testSupportsNonResizableInSplitScreen_aspectRatioLetterboxInSameOrientation() { 3046 // Support non resizable in multi window 3047 mAtm.mDevEnableNonResizableMultiWindow = true; 3048 setUpDisplaySizeWithApp(1000, 2800); 3049 final TestSplitOrganizer organizer = 3050 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3051 3052 // Non-resizable portrait activity 3053 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 3054 final Rect originalBounds = new Rect(mActivity.getBounds()); 3055 3056 // Move activity to split screen which takes half of the screen. 3057 mTask.reparent(organizer.mPrimary, POSITION_TOP, 3058 false /*moveParents*/, "test"); 3059 organizer.mPrimary.setBounds(0, 0, 1000, 1400); 3060 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 3061 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 3062 3063 // Non-resizable activity in size compat mode 3064 assertScaled(); 3065 final Rect newBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 3066 assertEquals(originalBounds.width(), newBounds.width()); 3067 assertEquals(originalBounds.height(), newBounds.height()); 3068 assertActivityMaxBoundsSandboxed(); 3069 3070 recomputeNaturalConfigurationOfUnresizableActivity(); 3071 3072 // Split screen is also in portrait [1000,1400], which meets the activity request. It should 3073 // sandbox to the activity bounds for non-resizable. 3074 assertEquals(ORIENTATION_PORTRAIT, mTask.getConfiguration().orientation); 3075 assertEquals(ORIENTATION_PORTRAIT, mActivity.getConfiguration().orientation); 3076 assertFitted(); 3077 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 3078 assertActivityMaxBoundsSandboxed(); 3079 3080 // Activity bounds fill split screen. 3081 final Rect primarySplitBounds = new Rect(organizer.mPrimary.getBounds()); 3082 final Rect letterboxedBounds = new Rect(mActivity.getBounds()); 3083 assertEquals(primarySplitBounds, letterboxedBounds); 3084 } 3085 3086 @Test 3087 public void testSupportsNonResizableInSplitScreen_letterboxForAspectRatioRestriction() { 3088 // Support non resizable in multi window 3089 mAtm.mDevEnableNonResizableMultiWindow = true; 3090 setUpDisplaySizeWithApp(/* dw */ 1000, /* dh */ 2800); 3091 final TestSplitOrganizer organizer = 3092 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3093 3094 prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3095 3096 // Bounds are letterboxed to respect the provided max aspect ratio. 3097 assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 1100)); 3098 3099 // Move activity to split screen which has landscape size. 3100 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents */ false, "test"); 3101 organizer.mPrimary.setBounds(0, 0, 1000, 800); 3102 3103 // Non-resizable activity should be in size compat mode. 3104 assertScaled(); 3105 assertEquals(mActivity.getBounds(), new Rect(60, 0, 940, 800)); 3106 3107 recomputeNaturalConfigurationOfUnresizableActivity(); 3108 3109 // Activity should still be letterboxed but not in the size compat mode. 3110 assertFitted(); 3111 assertEquals(mActivity.getBounds(), new Rect(60, 0, 940, 800)); 3112 3113 // Letterbox should fill the gap between the split screen and the letterboxed activity. 3114 assertLetterboxSurfacesDrawnBetweenActivityAndParentBounds(organizer.mPrimary.getBounds()); 3115 } 3116 3117 @Test 3118 public void testIsHorizontalReachabilityEnabled_splitScreen_false() { 3119 mAtm.mDevEnableNonResizableMultiWindow = true; 3120 setUpDisplaySizeWithApp(2800, 1000); 3121 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3122 mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true); 3123 final TestSplitOrganizer organizer = 3124 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3125 3126 // Unresizable portrait-only activity. 3127 prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_PORTRAIT); 3128 3129 // Move activity to split screen which takes half of the screen. 3130 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 3131 organizer.mPrimary.setBounds(0, 0, 1400, 1000); 3132 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 3133 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 3134 3135 // Horizontal reachability is disabled because the app is in split screen. 3136 assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); 3137 } 3138 3139 @Test 3140 public void testIsVerticalReachabilityEnabled_splitScreen_false() { 3141 mAtm.mDevEnableNonResizableMultiWindow = true; 3142 setUpDisplaySizeWithApp(1000, 2800); 3143 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3144 mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); 3145 final TestSplitOrganizer organizer = 3146 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3147 3148 // Unresizable landscape-only activity. 3149 prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_LANDSCAPE); 3150 3151 // Move activity to split screen which takes half of the screen. 3152 mTask.reparent(organizer.mPrimary, POSITION_TOP, /* moveParents= */ false , "test"); 3153 organizer.mPrimary.setBounds(0, 0, 1000, 1400); 3154 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mTask.getWindowingMode()); 3155 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 3156 3157 // Vertical reachability is disabled because the app is in split screen. 3158 assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); 3159 } 3160 3161 @Test 3162 public void testIsVerticalReachabilityEnabled_doesNotMatchParentWidth_false() { 3163 setUpDisplaySizeWithApp(1000, 2800); 3164 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3165 mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); 3166 3167 // Unresizable landscape-only activity. 3168 prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_LANDSCAPE); 3169 3170 // Rotate to put activity in size compat mode. 3171 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3172 3173 // Activity now in size compat mode. 3174 assertTrue(mActivity.inSizeCompatMode()); 3175 3176 // Vertical reachability is disabled because the app does not match parent width 3177 assertNotEquals(mActivity.getScreenResolvedBounds().width(), 3178 mActivity.mDisplayContent.getBounds().width()); 3179 assertFalse(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); 3180 } 3181 3182 @Test 3183 public void testIsVerticalReachabilityEnabled_emptyBounds_true() { 3184 setUpDisplaySizeWithApp(/* dw */ 1000, /* dh */ 2800); 3185 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3186 mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); 3187 3188 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3189 3190 // Set up activity with empty bounds to mock loading of app 3191 mActivity.getWindowConfiguration().setBounds(null); 3192 assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); 3193 3194 // Vertical reachability is still enabled as resolved bounds is not empty 3195 assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); 3196 } 3197 3198 @Test 3199 public void testIsHorizontalReachabilityEnabled_emptyBounds_true() { 3200 setUpDisplaySizeWithApp(/* dw */ 2800, /* dh */ 1000); 3201 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3202 mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true); 3203 3204 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 3205 3206 // Set up activity with empty bounds to mock loading of app 3207 mActivity.getWindowConfiguration().setBounds(null); 3208 assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); 3209 3210 // Horizontal reachability is still enabled as resolved bounds is not empty 3211 assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); 3212 } 3213 3214 @Test 3215 public void testIsHorizontalReachabilityEnabled_doesNotMatchParentHeight_false() { 3216 setUpDisplaySizeWithApp(2800, 1000); 3217 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3218 mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true); 3219 3220 // Unresizable portrait-only activity. 3221 prepareUnresizable(mActivity, 1.1f, SCREEN_ORIENTATION_PORTRAIT); 3222 3223 // Rotate to put activity in size compat mode. 3224 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3225 3226 // Activity now in size compat mode. 3227 assertTrue(mActivity.inSizeCompatMode()); 3228 3229 // Horizontal reachability is disabled because the app does not match parent height 3230 assertNotEquals(mActivity.getScreenResolvedBounds().height(), 3231 mActivity.mDisplayContent.getBounds().height()); 3232 assertFalse(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); 3233 } 3234 3235 @Test 3236 public void testIsHorizontalReachabilityEnabled_inSizeCompatMode_matchesParentHeight_true() { 3237 setUpDisplaySizeWithApp(1800, 2200); 3238 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3239 mWm.mLetterboxConfiguration.setIsHorizontalReachabilityEnabled(true); 3240 3241 // Unresizable portrait-only activity. 3242 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 3243 3244 // Rotate to put activity in size compat mode. 3245 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3246 3247 // Activity now in size compat mode. 3248 assertTrue(mActivity.inSizeCompatMode()); 3249 3250 // Horizontal reachability is enabled because the app matches parent height 3251 assertEquals(mActivity.getScreenResolvedBounds().height(), 3252 mActivity.mDisplayContent.getBounds().height()); 3253 assertTrue(mActivity.mLetterboxUiController.isHorizontalReachabilityEnabled()); 3254 } 3255 3256 @Test 3257 public void testIsVerticalReachabilityEnabled_inSizeCompatMode_matchesParentWidth_true() { 3258 setUpDisplaySizeWithApp(2200, 1800); 3259 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3260 mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); 3261 3262 // Unresizable landscape-only activity. 3263 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3264 3265 // Rotate to put activity in size compat mode. 3266 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3267 3268 // Activity now in size compat mode. 3269 assertTrue(mActivity.inSizeCompatMode()); 3270 3271 // Vertical reachability is enabled because the app matches parent width 3272 assertEquals(mActivity.getScreenResolvedBounds().width(), 3273 mActivity.mDisplayContent.getBounds().width()); 3274 assertTrue(mActivity.mLetterboxUiController.isVerticalReachabilityEnabled()); 3275 } 3276 3277 @Test 3278 public void testAppRequestsOrientationChange_notInSizeCompat() { 3279 setUpDisplaySizeWithApp(2200, 1800); 3280 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3281 3282 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3283 3284 mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT); 3285 3286 // Activity is not in size compat mode because the orientation change request came from the 3287 // app itself 3288 assertFalse(mActivity.inSizeCompatMode()); 3289 3290 rotateDisplay(mActivity.mDisplayContent, ROTATION_270); 3291 // Activity should go into size compat mode now because the orientation change came from the 3292 // system (device rotation) 3293 assertTrue(mActivity.inSizeCompatMode()); 3294 } 3295 3296 @Test 3297 public void testLetterboxDetailsForStatusBar_noLetterbox() { 3298 setUpDisplaySizeWithApp(2800, 1000); 3299 addStatusBar(mActivity.mDisplayContent); 3300 addWindowToActivity(mActivity); // Add a window to the activity so that we can get an 3301 // appearance inside letterboxDetails 3302 3303 DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); 3304 StatusBarManagerInternal statusBar = displayPolicy.getStatusBarManagerInternal(); 3305 // We should get a null LetterboxDetails object as there is no letterboxed activity, so 3306 // nothing will get passed to SysUI 3307 verify(statusBar, never()).onSystemBarAttributesChanged(anyInt(), anyInt(), 3308 any(), anyBoolean(), anyInt(), 3309 any(InsetsVisibilities.class), isNull(), isNull()); 3310 3311 } 3312 3313 @Test 3314 public void testLetterboxDetailsForStatusBar_letterboxedForMaxAspectRatio() { 3315 setUpDisplaySizeWithApp(2800, 1000); 3316 addStatusBar(mActivity.mDisplayContent); 3317 addWindowToActivity(mActivity); // Add a window to the activity so that we can get an 3318 // appearance inside letterboxDetails 3319 // Prepare unresizable activity with max aspect ratio 3320 prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3321 // Refresh the letterbox 3322 mActivity.mRootWindowContainer.performSurfacePlacement(); 3323 3324 Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 3325 assertEquals(mBounds, new Rect(850, 0, 1950, 1000)); 3326 3327 DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); 3328 LetterboxDetails[] expectedLetterboxDetails = {new LetterboxDetails( 3329 mBounds, 3330 mActivity.getDisplayContent().getBounds(), 3331 mActivity.findMainWindow().mAttrs.insetsFlags.appearance 3332 )}; 3333 3334 // Check that letterboxDetails actually gets passed to SysUI 3335 StatusBarManagerInternal statusBar = displayPolicy.getStatusBarManagerInternal(); 3336 verify(statusBar).onSystemBarAttributesChanged(anyInt(), anyInt(), 3337 any(), anyBoolean(), anyInt(), 3338 any(InsetsVisibilities.class), isNull(), eq(expectedLetterboxDetails)); 3339 } 3340 3341 @Test 3342 public void testLetterboxDetailsForStatusBar_letterboxNotOverlappingStatusBar() { 3343 // Align to center so that we don't overlap with the status bar 3344 mAtm.mWindowManager.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); 3345 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800) 3346 .setNotch(100) 3347 .build(); 3348 setUpApp(display); 3349 TestWindowState statusBar = addStatusBar(mActivity.mDisplayContent); 3350 spyOn(statusBar); 3351 doReturn(new Rect(0, 0, statusBar.mRequestedWidth, statusBar.mRequestedHeight)) 3352 .when(statusBar).getFrame(); 3353 addWindowToActivity(mActivity); // Add a window to the activity so that we can get an 3354 // appearance inside letterboxDetails 3355 // Prepare unresizable activity with max aspect ratio 3356 prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3357 // Refresh the letterbox 3358 mActivity.mRootWindowContainer.performSurfacePlacement(); 3359 3360 Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 3361 assertEquals(mBounds, new Rect(0, 900, 1000, 2000)); 3362 3363 DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); 3364 LetterboxDetails[] expectedLetterboxDetails = {new LetterboxDetails( 3365 mBounds, 3366 mActivity.getDisplayContent().getBounds(), 3367 mActivity.findMainWindow().mAttrs.insetsFlags.appearance 3368 )}; 3369 3370 // Check that letterboxDetails actually gets passed to SysUI 3371 StatusBarManagerInternal statusBarManager = displayPolicy.getStatusBarManagerInternal(); 3372 verify(statusBarManager).onSystemBarAttributesChanged(anyInt(), anyInt(), 3373 any(), anyBoolean(), anyInt(), 3374 any(InsetsVisibilities.class), isNull(), eq(expectedLetterboxDetails)); 3375 } 3376 3377 @Test 3378 public void testLetterboxDetailsForTaskBar_letterboxNotOverlappingTaskBar() { 3379 mAtm.mDevEnableNonResizableMultiWindow = true; 3380 final int screenHeight = 2200; 3381 final int screenWidth = 1400; 3382 final int taskbarHeight = 200; 3383 setUpDisplaySizeWithApp(screenWidth, screenHeight); 3384 3385 final TestSplitOrganizer organizer = 3386 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3387 3388 // Move first activity to split screen which takes half of the screen. 3389 organizer.mPrimary.setBounds(0, screenHeight / 2, screenWidth, screenHeight); 3390 organizer.putTaskToPrimary(mTask, true); 3391 3392 final InsetsSource navSource = new InsetsSource(ITYPE_EXTRA_NAVIGATION_BAR); 3393 navSource.setFrame(new Rect(0, screenHeight - taskbarHeight, screenWidth, screenHeight)); 3394 3395 mActivity.mWmService.mLetterboxConfiguration.setLetterboxActivityCornersRadius(15); 3396 3397 final WindowState w1 = addWindowToActivity(mActivity); 3398 w1.mAboveInsetsState.addSource(navSource); 3399 3400 // Prepare unresizable activity with max aspect ratio 3401 prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3402 3403 // Refresh the letterboxes 3404 mActivity.mRootWindowContainer.performSurfacePlacement(); 3405 3406 final ArgumentCaptor<Rect> cropCapturer = ArgumentCaptor.forClass(Rect.class); 3407 verify(mTransaction, times(2)).setCrop( 3408 eq(w1.getSurfaceControl()), 3409 cropCapturer.capture() 3410 ); 3411 final List<Rect> capturedCrops = cropCapturer.getAllValues(); 3412 3413 final int expectedHeight = screenHeight / 2 - taskbarHeight; 3414 assertEquals(2, capturedCrops.size()); 3415 assertEquals(expectedHeight, capturedCrops.get(0).bottom); 3416 assertEquals(expectedHeight, capturedCrops.get(1).bottom); 3417 } 3418 3419 @Test 3420 public void testSplitScreenLetterboxDetailsForStatusBar_twoLetterboxedApps() { 3421 mAtm.mDevEnableNonResizableMultiWindow = true; 3422 setUpDisplaySizeWithApp(2800, 1000); 3423 addStatusBar(mActivity.mDisplayContent); 3424 // Create another task for the second activity 3425 final Task newTask = new TaskBuilder(mSupervisor).setDisplay(mActivity.getDisplayContent()) 3426 .setCreateActivity(true).build(); 3427 ActivityRecord newActivity = newTask.getTopNonFinishingActivity(); 3428 3429 final TestSplitOrganizer organizer = 3430 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 3431 3432 // Move first activity to split screen which takes half of the screen. 3433 organizer.mPrimary.setBounds(0, 0, 1400, 1000); 3434 organizer.putTaskToPrimary(mTask, true); 3435 // Move second activity to split screen which takes half of the screen. 3436 organizer.mSecondary.setBounds(1400, 0, 2800, 1000); 3437 organizer.putTaskToSecondary(newTask, true); 3438 3439 addWindowToActivity(mActivity); // Add a window to the activity so that we can get an 3440 // appearance inside letterboxDetails 3441 // Prepare unresizable activity with max aspect ratio 3442 prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3443 addWindowToActivity(newActivity); 3444 prepareUnresizable(newActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3445 3446 // Refresh the letterboxes 3447 newActivity.mRootWindowContainer.performSurfacePlacement(); 3448 3449 Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 3450 assertEquals(mBounds, new Rect(150, 0, 1250, 1000)); 3451 final Rect newBounds = new Rect(newActivity.getWindowConfiguration().getBounds()); 3452 assertEquals(newBounds, new Rect(1550, 0, 2650, 1000)); 3453 3454 DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); 3455 LetterboxDetails[] expectedLetterboxDetails = { new LetterboxDetails( 3456 mBounds, 3457 organizer.mPrimary.getBounds(), 3458 mActivity.findMainWindow().mAttrs.insetsFlags.appearance 3459 ), new LetterboxDetails( 3460 newBounds, 3461 organizer.mSecondary.getBounds(), 3462 newActivity.findMainWindow().mAttrs.insetsFlags.appearance 3463 )}; 3464 3465 // Check that letterboxDetails actually gets passed to SysUI 3466 StatusBarManagerInternal statusBar = displayPolicy.getStatusBarManagerInternal(); 3467 verify(statusBar).onSystemBarAttributesChanged(anyInt(), anyInt(), 3468 any(), anyBoolean(), anyInt(), 3469 any(InsetsVisibilities.class), isNull(), eq(expectedLetterboxDetails)); 3470 } 3471 3472 private void recomputeNaturalConfigurationOfUnresizableActivity() { 3473 // Recompute the natural configuration of the non-resizable activity and the split screen. 3474 mActivity.clearSizeCompatMode(); 3475 3476 // Draw letterbox. 3477 mActivity.setVisible(false); 3478 mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN); 3479 mActivity.mDisplayContent.mOpeningApps.add(mActivity); 3480 addWindowToActivity(mActivity); 3481 mActivity.mRootWindowContainer.performSurfacePlacement(); 3482 } 3483 3484 private void assertLetterboxSurfacesDrawnBetweenActivityAndParentBounds(Rect parentBounds) { 3485 // Letterbox should fill the gap between the parent bounds and the letterboxed activity. 3486 final Rect letterboxedBounds = new Rect(mActivity.getBounds()); 3487 assertTrue(parentBounds.contains(letterboxedBounds)); 3488 assertEquals(new Rect(letterboxedBounds.left - parentBounds.left, 3489 letterboxedBounds.top - parentBounds.top, 3490 parentBounds.right - letterboxedBounds.right, 3491 parentBounds.bottom - letterboxedBounds.bottom), 3492 mActivity.getLetterboxInsets()); 3493 } 3494 3495 @Test 3496 public void testUpdateResolvedBoundsHorizontalPosition_leftInsets_appCentered() { 3497 // Set up folded display 3498 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1100, 2100) 3499 .setCanRotate(true) 3500 .build(); 3501 display.setIgnoreOrientationRequest(true); 3502 final DisplayPolicy policy = display.getDisplayPolicy(); 3503 DisplayPolicy.DecorInsets.Info decorInfo = policy.getDecorInsetsInfo(ROTATION_90, 3504 display.mBaseDisplayHeight, display.mBaseDisplayWidth); 3505 decorInfo.mNonDecorInsets.set(130, 0, 60, 0); 3506 spyOn(policy); 3507 doReturn(decorInfo).when(policy).getDecorInsetsInfo(ROTATION_90, 3508 display.mBaseDisplayHeight, display.mBaseDisplayWidth); 3509 mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); 3510 3511 setUpApp(display); 3512 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 3513 3514 // Resize the display to simulate unfolding in portrait 3515 resizeDisplay(mTask.mDisplayContent, 2200, 1800); 3516 assertTrue(mActivity.inSizeCompatMode()); 3517 3518 // Simulate real display not taking non-decor insets into consideration 3519 display.getWindowConfiguration().setAppBounds(0, 0, 2200, 1800); 3520 3521 // Rotate display to landscape 3522 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3523 3524 // App is centered 3525 assertEquals(mActivity.getBounds(), new Rect(350, 50, 1450, 2150)); 3526 } 3527 3528 @Test 3529 public void testUpdateResolvedBoundsHorizontalPosition_left() { 3530 // Display configured as (2800, 1400). 3531 assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( 3532 /* letterboxHorizontalPositionMultiplier */ 0.0f, 3533 // At launch. 3534 /* fixedOrientationLetterbox */ new Rect(0, 0, 700, 1400), 3535 // After 90 degree rotation. 3536 /* sizeCompatUnscaled */ new Rect(0, 0, 700, 1400), 3537 // After the display is resized to (700, 1400). 3538 /* sizeCompatScaled */ new Rect(0, 0, 350, 700)); 3539 } 3540 3541 @Test 3542 public void testUpdateResolvedBoundsHorizontalPosition_center() { 3543 // Display configured as (2800, 1400). 3544 assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( 3545 /* letterboxHorizontalPositionMultiplier */ 0.5f, 3546 // At launch. 3547 /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), 3548 // After 90 degree rotation. 3549 /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), 3550 // After the display is resized to (700, 1400). 3551 /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); 3552 } 3553 3554 @Test 3555 public void testUpdateResolvedBoundsHorizontalPosition_invalidMultiplier_defaultToCenter() { 3556 // Display configured as (2800, 1400). 3557 3558 // Below 0.0. 3559 assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( 3560 /* letterboxHorizontalPositionMultiplier */ -1.0f, 3561 // At launch. 3562 /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), 3563 // After 90 degree rotation. 3564 /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), 3565 // After the display is resized to (700, 1400). 3566 /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); 3567 3568 // Above 1.0 3569 assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( 3570 /* letterboxHorizontalPositionMultiplier */ 2.0f, 3571 // At launch. 3572 /* fixedOrientationLetterbox */ new Rect(1050, 0, 1750, 1400), 3573 // After 90 degree rotation. 3574 /* sizeCompatUnscaled */ new Rect(350, 0, 1050, 1400), 3575 // After the display is resized to (700, 1400). 3576 /* sizeCompatScaled */ new Rect(525, 0, 875, 700)); 3577 } 3578 3579 @Test 3580 public void testUpdateResolvedBoundsHorizontalPosition_right() { 3581 // Display configured as (2800, 1400). 3582 assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( 3583 /* letterboxHorizontalPositionMultiplier */ 1.0f, 3584 // At launch. 3585 /* fixedOrientationLetterbox */ new Rect(2100, 0, 2800, 1400), 3586 // After 90 degree rotation. 3587 /* sizeCompatUnscaled */ new Rect(700, 0, 1400, 1400), 3588 // After the display is resized to (700, 1400). 3589 /* sizeCompatScaled */ new Rect(1050, 0, 1400, 700)); 3590 } 3591 3592 private void assertHorizontalPositionForDifferentDisplayConfigsForPortraitActivity( 3593 float letterboxHorizontalPositionMultiplier, Rect fixedOrientationLetterbox, 3594 Rect sizeCompatUnscaled, Rect sizeCompatScaled) { 3595 // Set up a display in landscape and ignoring orientation request. 3596 setUpDisplaySizeWithApp(2800, 1400); 3597 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3598 3599 mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 3600 letterboxHorizontalPositionMultiplier); 3601 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 3602 assertEquals(fixedOrientationLetterbox, mActivity.getBounds()); 3603 // Rotate to put activity in size compat mode. 3604 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3605 assertTrue(mActivity.inSizeCompatMode()); 3606 // Activity is in size compat mode but not scaled. 3607 assertEquals(sizeCompatUnscaled, mActivity.getBounds()); 3608 // Force activity to scaled down for size compat mode. 3609 resizeDisplay(mTask.mDisplayContent, 700, 1400); 3610 assertTrue(mActivity.inSizeCompatMode()); 3611 assertScaled(); 3612 assertEquals(sizeCompatScaled, mActivity.getBounds()); 3613 } 3614 3615 @Test 3616 public void testApplyAspectRatio_activityAlignWithParentAppVertical() { 3617 // The display's app bounds will be (0, 100, 1000, 2350) 3618 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2500) 3619 .setCanRotate(false) 3620 .setCutout(0, 100, 0, 150) 3621 .build(); 3622 3623 setUpApp(display); 3624 prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 3625 // The activity height is 2100 and the display's app bounds height is 2250, so the activity 3626 // can be aligned inside parentAppBounds 3627 assertEquals(mActivity.getBounds(), new Rect(0, 0, 1000, 2200)); 3628 } 3629 @Test 3630 public void testApplyAspectRatio_activityCannotAlignWithParentAppVertical() { 3631 // The display's app bounds will be (0, 100, 1000, 2150) 3632 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2300) 3633 .setCanRotate(false) 3634 .setCutout(0, 100, 0, 150) 3635 .build(); 3636 3637 setUpApp(display); 3638 prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 3639 // The activity height is 2100 and the display's app bounds height is 2050, so the activity 3640 // cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display 3641 assertEquals(mActivity.getBounds(), display.getBounds()); 3642 } 3643 3644 @Test 3645 public void testApplyAspectRatio_activityAlignWithParentAppHorizontal() { 3646 // The display's app bounds will be (100, 0, 2350, 1000) 3647 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2500, 1000) 3648 .setCanRotate(false) 3649 .setCutout(100, 0, 150, 0) 3650 .build(); 3651 3652 setUpApp(display); 3653 prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 3654 // The activity width is 2100 and the display's app bounds width is 2250, so the activity 3655 // can be aligned inside parentAppBounds 3656 assertEquals(mActivity.getBounds(), new Rect(175, 0, 2275, 1000)); 3657 } 3658 @Test 3659 public void testApplyAspectRatio_activityCannotAlignWithParentAppHorizontal() { 3660 // The display's app bounds will be (100, 0, 2150, 1000) 3661 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2300, 1000) 3662 .setCanRotate(false) 3663 .setCutout(100, 0, 150, 0) 3664 .build(); 3665 3666 setUpApp(display); 3667 prepareUnresizable(mActivity, 2.1f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED); 3668 // The activity width is 2100 and the display's app bounds width is 2050, so the activity 3669 // cannot be aligned inside parentAppBounds and it will fill the parentBounds of the display 3670 assertEquals(mActivity.getBounds(), display.getBounds()); 3671 } 3672 3673 @Test 3674 public void testApplyAspectRatio_containingRatioAlmostEqualToMaxRatio_boundsUnchanged() { 3675 setUpDisplaySizeWithApp(1981, 2576); 3676 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3677 mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); 3678 3679 final Rect originalBounds = new Rect(mActivity.getBounds()); 3680 prepareUnresizable(mActivity, 1.3f, SCREEN_ORIENTATION_UNSPECIFIED); 3681 3682 // The containing aspect ratio is now 1.3003534, while the desired aspect ratio is 1.3. The 3683 // bounds of the activity should not be changed as the difference is too small 3684 assertEquals(mActivity.getBounds(), originalBounds); 3685 } 3686 3687 @Test 3688 public void testUpdateResolvedBoundsHorizontalPosition_activityFillParentWidth() { 3689 // When activity width equals parent width, multiplier shouldn't have any effect. 3690 assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( 3691 /* letterboxHorizontalPositionMultiplier */ 0.0f); 3692 assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( 3693 /* letterboxHorizontalPositionMultiplier */ 0.5f); 3694 assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( 3695 /* letterboxHorizontalPositionMultiplier */ 1.0f); 3696 } 3697 3698 @Test 3699 public void testUpdateResolvedBoundsVerticalPosition_topInsets_appCentered() { 3700 // Set up folded display 3701 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 2100, 1100) 3702 .setCanRotate(true) 3703 .build(); 3704 display.setIgnoreOrientationRequest(true); 3705 final DisplayPolicy policy = display.getDisplayPolicy(); 3706 DisplayPolicy.DecorInsets.Info decorInfo = policy.getDecorInsetsInfo(ROTATION_90, 3707 display.mBaseDisplayHeight, display.mBaseDisplayWidth); 3708 decorInfo.mNonDecorInsets.set(0, 130, 0, 60); 3709 spyOn(policy); 3710 doReturn(decorInfo).when(policy).getDecorInsetsInfo(ROTATION_90, 3711 display.mBaseDisplayHeight, display.mBaseDisplayWidth); 3712 mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); 3713 3714 setUpApp(display); 3715 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3716 3717 // Resize the display to simulate unfolding in portrait 3718 resizeDisplay(mTask.mDisplayContent, 1800, 2200); 3719 assertTrue(mActivity.inSizeCompatMode()); 3720 3721 // Simulate real display not taking non-decor insets into consideration 3722 display.getWindowConfiguration().setAppBounds(0, 0, 1800, 2200); 3723 3724 // Rotate display to landscape 3725 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3726 3727 // App is centered 3728 assertEquals(mActivity.getBounds(), new Rect(50, 350, 2150, 1450)); 3729 } 3730 3731 @Test 3732 public void testUpdateResolvedBoundsVerticalPosition_top() { 3733 // Display configured as (1400, 2800). 3734 assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( 3735 /* letterboxVerticalPositionMultiplier */ 0.0f, 3736 // At launch. 3737 /* fixedOrientationLetterbox */ new Rect(0, 0, 1400, 700), 3738 // After 90 degree rotation. 3739 /* sizeCompatUnscaled */ new Rect(700, 0, 2100, 700), 3740 // After the display is resized to (1400, 700). 3741 /* sizeCompatScaled */ new Rect(0, 0, 700, 350)); 3742 } 3743 3744 @Test 3745 public void testUpdateResolvedBoundsVerticalPosition_center() { 3746 // Display configured as (1400, 2800). 3747 assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( 3748 /* letterboxVerticalPositionMultiplier */ 0.5f, 3749 // At launch. 3750 /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750), 3751 // After 90 degree rotation. 3752 /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050), 3753 // After the display is resized to (1400, 700). 3754 /* sizeCompatScaled */ new Rect(0, 525, 700, 875)); 3755 } 3756 3757 @Test 3758 public void testUpdateResolvedBoundsVerticalPosition_invalidMultiplier_defaultToCenter() { 3759 // Display configured as (1400, 2800). 3760 3761 // Below 0.0. 3762 assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( 3763 /* letterboxVerticalPositionMultiplier */ -1.0f, 3764 // At launch. 3765 /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750), 3766 // After 90 degree rotation. 3767 /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050), 3768 // After the display is resized to (1400, 700). 3769 /* sizeCompatScaled */ new Rect(0, 525, 700, 875)); 3770 3771 // Above 1.0 3772 assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( 3773 /* letterboxVerticalPositionMultiplier */ 2.0f, 3774 // At launch. 3775 /* fixedOrientationLetterbox */ new Rect(0, 1050, 1400, 1750), 3776 // After 90 degree rotation. 3777 /* sizeCompatUnscaled */ new Rect(700, 350, 2100, 1050), 3778 // After the display is resized to (1400, 700). 3779 /* sizeCompatScaled */ new Rect(0, 525, 700, 875)); 3780 } 3781 3782 @Test 3783 public void testUpdateResolvedBoundsVerticalPosition_bottom() { 3784 // Display configured as (1400, 2800). 3785 assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( 3786 /* letterboxVerticalPositionMultiplier */ 1.0f, 3787 // At launch. 3788 /* fixedOrientationLetterbox */ new Rect(0, 2100, 1400, 2800), 3789 // After 90 degree rotation. 3790 /* sizeCompatUnscaled */ new Rect(700, 700, 2100, 1400), 3791 // After the display is resized to (1400, 700). 3792 /* sizeCompatScaled */ new Rect(0, 1050, 700, 1400)); 3793 } 3794 3795 @Test 3796 public void testUpdateResolvedBoundsVerticalPosition_tabletop() { 3797 // Set up a display in portrait with a fixed-orientation LANDSCAPE app 3798 setUpDisplaySizeWithApp(1400, 2800); 3799 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3800 mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier( 3801 1.0f /*letterboxVerticalPositionMultiplier*/); 3802 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3803 3804 Rect letterboxNoFold = new Rect(0, 2100, 1400, 2800); 3805 assertEquals(letterboxNoFold, mActivity.getBounds()); 3806 3807 // Make the activity full-screen 3808 mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 3809 3810 setFoldablePosture(true /* isHalfFolded */, true /* isTabletop */); 3811 3812 Rect letterboxHalfFold = new Rect(0, 0, 1400, 700); 3813 assertEquals(letterboxHalfFold, mActivity.getBounds()); 3814 3815 setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */); 3816 3817 assertEquals(letterboxNoFold, mActivity.getBounds()); 3818 } 3819 3820 @Test 3821 public void testGetFixedOrientationLetterboxAspectRatio_tabletop_centered() { 3822 // Set up a display in portrait with a fixed-orientation LANDSCAPE app 3823 setUpDisplaySizeWithApp(1400, 2800); 3824 mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 3825 LETTERBOX_POSITION_MULTIPLIER_CENTER); 3826 mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier( 3827 1.0f /*letterboxVerticalPositionMultiplier*/); 3828 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3829 3830 setFoldablePosture(true /* isHalfFolded */, true /* isTabletop */); 3831 3832 Configuration parentConfig = mActivity.getParent().getConfiguration(); 3833 3834 float actual = mActivity.mLetterboxUiController 3835 .getFixedOrientationLetterboxAspectRatio(parentConfig); 3836 float expected = mActivity.mLetterboxUiController.getSplitScreenAspectRatio(); 3837 3838 assertEquals(expected, actual, 0.01); 3839 } 3840 3841 @Test 3842 public void testUpdateResolvedBoundsHorizontalPosition_bookModeEnabled() { 3843 // Set up a display in landscape with a fixed-orientation PORTRAIT app 3844 setUpDisplaySizeWithApp(2800, 1400); 3845 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3846 mWm.mLetterboxConfiguration.setIsAutomaticReachabilityInBookModeEnabled(true); 3847 mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 3848 1.0f /*letterboxVerticalPositionMultiplier*/); 3849 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 3850 3851 Rect letterboxNoFold = new Rect(2100, 0, 2800, 1400); 3852 assertEquals(letterboxNoFold, mActivity.getBounds()); 3853 3854 // Make the activity full-screen 3855 mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 3856 3857 setFoldablePosture(true /* isHalfFolded */, false /* isTabletop */); 3858 3859 Rect letterboxHalfFold = new Rect(0, 0, 700, 1400); 3860 assertEquals(letterboxHalfFold, mActivity.getBounds()); 3861 3862 setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */); 3863 3864 assertEquals(letterboxNoFold, mActivity.getBounds()); 3865 } 3866 3867 @Test 3868 public void testUpdateResolvedBoundsHorizontalPosition_bookModeDisabled_centered() { 3869 // Set up a display in landscape with a fixed-orientation PORTRAIT app 3870 setUpDisplaySizeWithApp(2800, 1400); 3871 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3872 mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier(0.5f); 3873 prepareUnresizable(mActivity, 1.75f, SCREEN_ORIENTATION_PORTRAIT); 3874 3875 Rect letterboxNoFold = new Rect(1000, 0, 1800, 1400); 3876 assertEquals(letterboxNoFold, mActivity.getBounds()); 3877 3878 // Make the activity full-screen 3879 mTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 3880 3881 // Stay centered and bounds don't change 3882 setFoldablePosture(true /* isHalfFolded */, false /* isTabletop */); 3883 assertEquals(letterboxNoFold, mActivity.getBounds()); 3884 3885 setFoldablePosture(false /* isHalfFolded */, false /* isTabletop */); 3886 assertEquals(letterboxNoFold, mActivity.getBounds()); 3887 } 3888 3889 private void setFoldablePosture(ActivityRecord activity, boolean isHalfFolded, 3890 boolean isTabletop) { 3891 final DisplayRotation r = activity.mDisplayContent.getDisplayRotation(); 3892 doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge(); 3893 doReturn(false).when(r).isDeviceInPosture(any(DeviceState.class), anyBoolean()); 3894 if (isHalfFolded) { 3895 doReturn(true).when(r) 3896 .isDeviceInPosture(DeviceState.HALF_FOLDED, isTabletop); 3897 } 3898 activity.recomputeConfiguration(); 3899 } 3900 3901 private void setFoldablePosture(boolean isHalfFolded, boolean isTabletop) { 3902 setFoldablePosture(mActivity, isHalfFolded, isTabletop); 3903 } 3904 3905 @Test 3906 public void testUpdateResolvedBoundsPosition_alignToTop() { 3907 final int notchHeight = 100; 3908 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1000, 2800) 3909 .setNotch(notchHeight) 3910 .build(); 3911 setUpApp(display); 3912 3913 // Prepare unresizable activity with max aspect ratio 3914 prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); 3915 3916 Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); 3917 Rect appBounds = new Rect(mActivity.getWindowConfiguration().getAppBounds()); 3918 // The insets should be cut for aspect ratio and then added back because the appBounds 3919 // are aligned to the top of the parentAppBounds 3920 assertEquals(mBounds, new Rect(0, 0, 1000, 1200)); 3921 assertEquals(appBounds, new Rect(0, notchHeight, 1000, 1200)); 3922 } 3923 3924 private void assertVerticalPositionForDifferentDisplayConfigsForLandscapeActivity( 3925 float letterboxVerticalPositionMultiplier, Rect fixedOrientationLetterbox, 3926 Rect sizeCompatUnscaled, Rect sizeCompatScaled) { 3927 // Set up a display in portrait and ignoring orientation request. 3928 setUpDisplaySizeWithApp(1400, 2800); 3929 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 3930 3931 mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier( 3932 letterboxVerticalPositionMultiplier); 3933 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 3934 3935 assertEquals(fixedOrientationLetterbox, mActivity.getBounds()); 3936 3937 // Rotate to put activity in size compat mode. 3938 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3939 3940 assertTrue(mActivity.inSizeCompatMode()); 3941 // Activity is in size compat mode but not scaled. 3942 assertEquals(sizeCompatUnscaled, mActivity.getBounds()); 3943 3944 // Force activity to scaled down for size compat mode. 3945 resizeDisplay(mTask.mDisplayContent, 1400, 700); 3946 3947 assertTrue(mActivity.inSizeCompatMode()); 3948 assertScaled(); 3949 assertEquals(sizeCompatScaled, mActivity.getBounds()); 3950 } 3951 3952 @Test 3953 public void testUpdateResolvedBoundsVerticalPosition_activityFillParentHeight() { 3954 // When activity height equals parent height, multiplier shouldn't have any effect. 3955 assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity( 3956 /* letterboxVerticalPositionMultiplier */ 0.0f); 3957 assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity( 3958 /* letterboxVerticalPositionMultiplier */ 0.5f); 3959 assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity( 3960 /* letterboxVerticalPositionMultiplier */ 1.0f); 3961 } 3962 3963 @Test 3964 public void testAreBoundsLetterboxed_letterboxedForAspectRatio_returnsTrue() { 3965 setUpDisplaySizeWithApp(1000, 2500); 3966 3967 assertFalse(mActivity.areBoundsLetterboxed()); 3968 verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED); 3969 3970 prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT); 3971 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 3972 assertFalse(mActivity.inSizeCompatMode()); 3973 assertTrue(mActivity.areBoundsLetterboxed()); 3974 3975 verifyLogAppCompatState(mActivity, 3976 APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO); 3977 3978 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 3979 verifyLogAppCompatState(mActivity, 3980 APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE); 3981 rotateDisplay(mActivity.mDisplayContent, ROTATION_0); 3982 3983 // After returning to the original rotation, bounds are computed in 3984 // ActivityRecord#resolveSizeCompatModeConfiguration because mCompatDisplayInsets aren't 3985 // null but activity doesn't enter size compat mode. Checking that areBoundsLetterboxed() 3986 // still returns true because of the aspect ratio restrictions. 3987 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 3988 assertFalse(mActivity.inSizeCompatMode()); 3989 assertTrue(mActivity.areBoundsLetterboxed()); 3990 verifyLogAppCompatState(mActivity, 3991 APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO); 3992 3993 // After setting the visibility of the activity to false, areBoundsLetterboxed() still 3994 // returns true but the NOT_VISIBLE App Compat state is logged. 3995 mActivity.setVisibility(false); 3996 assertTrue(mActivity.areBoundsLetterboxed()); 3997 verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE); 3998 mActivity.setVisibility(true); 3999 assertTrue(mActivity.areBoundsLetterboxed()); 4000 verifyLogAppCompatState(mActivity, 4001 APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO); 4002 } 4003 4004 @Test 4005 public void testAreBoundsLetterboxed_letterboxedForFixedOrientation_returnsTrue() { 4006 setUpDisplaySizeWithApp(2500, 1000); 4007 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4008 4009 assertFalse(mActivity.areBoundsLetterboxed()); 4010 verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED); 4011 4012 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4013 4014 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 4015 assertFalse(mActivity.inSizeCompatMode()); 4016 assertTrue(mActivity.areBoundsLetterboxed()); 4017 verifyLogAppCompatState(mActivity, 4018 APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION); 4019 } 4020 4021 @Test 4022 public void testAreBoundsLetterboxed_letterboxedForSizeCompat_returnsTrue() { 4023 setUpDisplaySizeWithApp(1000, 2500); 4024 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4025 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4026 4027 assertFalse(mActivity.areBoundsLetterboxed()); 4028 verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED); 4029 4030 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 4031 4032 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 4033 assertTrue(mActivity.inSizeCompatMode()); 4034 assertTrue(mActivity.areBoundsLetterboxed()); 4035 verifyLogAppCompatState(mActivity, 4036 APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE); 4037 } 4038 4039 @Test 4040 public void testIsEligibleForLetterboxEducation_educationNotEnabled_returnsFalse() { 4041 setUpDisplaySizeWithApp(2500, 1000); 4042 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4043 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(false); 4044 4045 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4046 4047 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4048 } 4049 4050 @Test 4051 public void testIsEligibleForLetterboxEducation_notEligibleForFixedOrientation_returnsFalse() { 4052 setUpDisplaySizeWithApp(1000, 2500); 4053 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4054 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(true); 4055 4056 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4057 4058 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4059 } 4060 4061 @Test 4062 public void testIsEligibleForLetterboxEducation_windowingModeMultiWindow_returnsFalse() { 4063 // Support non resizable in multi window 4064 mAtm.mDevEnableNonResizableMultiWindow = true; 4065 setUpDisplaySizeWithApp(1000, 1200); 4066 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4067 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(true); 4068 final TestSplitOrganizer organizer = 4069 new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); 4070 4071 // Non-resizable landscape activity 4072 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4073 final Rect originalBounds = new Rect(mActivity.getBounds()); 4074 4075 // Move activity to split screen which takes half of the screen. 4076 mTask.reparent(organizer.mPrimary, POSITION_TOP, 4077 false /*moveParents*/, "test"); 4078 organizer.mPrimary.setBounds(0, 0, 1000, 600); 4079 4080 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4081 assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); 4082 } 4083 4084 @Test 4085 public void testIsEligibleForLetterboxEducation_fixedOrientationLandscape_returnsFalse() { 4086 setUpDisplaySizeWithApp(1000, 2500); 4087 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4088 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(true); 4089 4090 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 4091 4092 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4093 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 4094 } 4095 4096 @Test 4097 public void testIsEligibleForLetterboxEducation_hasStartingWindow_returnsFalseUntilRemoved() { 4098 setUpDisplaySizeWithApp(2500, 1000); 4099 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4100 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(true); 4101 4102 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4103 mActivity.mStartingData = mock(StartingData.class); 4104 mActivity.attachStartingWindow( 4105 createWindowState(new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), 4106 mActivity)); 4107 4108 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4109 4110 // Verify that after removing the starting window isEligibleForLetterboxEducation returns 4111 // true and mTask.dispatchTaskInfoChangedIfNeeded is called. 4112 spyOn(mTask); 4113 mActivity.removeStartingWindow(); 4114 4115 assertTrue(mActivity.isEligibleForLetterboxEducation()); 4116 verify(mTask).dispatchTaskInfoChangedIfNeeded(true); 4117 } 4118 4119 @Test 4120 public void testIsEligibleForLetterboxEducation_hasStartingWindowAndEducationNotEnabled() { 4121 setUpDisplaySizeWithApp(2500, 1000); 4122 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4123 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(false); 4124 4125 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4126 mActivity.mStartingData = mock(StartingData.class); 4127 mActivity.attachStartingWindow( 4128 createWindowState(new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), 4129 mActivity)); 4130 4131 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4132 4133 // Verify that after removing the starting window isEligibleForLetterboxEducation still 4134 // returns false and mTask.dispatchTaskInfoChangedIfNeeded isn't called. 4135 spyOn(mTask); 4136 mActivity.removeStartingWindow(); 4137 4138 assertFalse(mActivity.isEligibleForLetterboxEducation()); 4139 verify(mTask, never()).dispatchTaskInfoChangedIfNeeded(true); 4140 } 4141 4142 @Test 4143 public void testIsEligibleForLetterboxEducation_letterboxedForFixedOrientation_returnsTrue() { 4144 setUpDisplaySizeWithApp(2500, 1000); 4145 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4146 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(true); 4147 4148 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4149 4150 assertTrue(mActivity.isEligibleForLetterboxEducation()); 4151 assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 4152 } 4153 4154 @Test 4155 public void testIsEligibleForLetterboxEducation_sizeCompatAndEligibleForFixedOrientation() { 4156 setUpDisplaySizeWithApp(1000, 2500); 4157 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4158 mActivity.mWmService.mLetterboxConfiguration.setIsEducationEnabled(true); 4159 4160 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4161 4162 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 4163 4164 assertTrue(mActivity.isEligibleForLetterboxEducation()); 4165 assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio()); 4166 assertTrue(mActivity.inSizeCompatMode()); 4167 } 4168 4169 @Test 4170 public void testTopActivityInSizeCompatMode_pausedAndInSizeCompatMode_returnsTrue() { 4171 setUpDisplaySizeWithApp(1000, 2500); 4172 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4173 4174 spyOn(mActivity); 4175 doReturn(mTask).when(mActivity).getOrganizedTask(); 4176 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4177 4178 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 4179 mActivity.setState(PAUSED, "test"); 4180 4181 assertTrue(mActivity.inSizeCompatMode()); 4182 assertEquals(mActivity.getState(), PAUSED); 4183 assertTrue(mActivity.isVisible()); 4184 assertTrue(mTask.getTaskInfo().topActivityInSizeCompat); 4185 } 4186 4187 /** 4188 * Tests that all three paths in which aspect ratio logic can be applied yield the same 4189 * result, which is that aspect ratio is respected on app bounds. The three paths are 4190 * fixed orientation, no fixed orientation but fixed aspect ratio, and size compat mode. 4191 */ 4192 @Test 4193 public void testAllAspectRatioLogicConsistent() { 4194 // Create display that has all stable insets and does not rotate. Make sure that status bar 4195 // height is greater than notch height so that stable bounds do not equal app bounds. 4196 final int notchHeight = 75; 4197 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 1080, 600) 4198 .setSystemDecorations(true).setNotch(notchHeight) 4199 .setStatusBarHeight(notchHeight + 20).setCanRotate(false).build(); 4200 4201 // Create task on test display. 4202 final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); 4203 4204 // Target min aspect ratio must be larger than parent aspect ratio to be applied. 4205 final float targetMinAspectRatio = 3.0f; 4206 4207 // Create fixed portait activity with min aspect ratio greater than parent aspect ratio. 4208 final ActivityRecord fixedOrientationActivity = new ActivityBuilder(mAtm) 4209 .setTask(task).setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 4210 .setMinAspectRatio(targetMinAspectRatio).build(); 4211 final Rect fixedOrientationAppBounds = new Rect(fixedOrientationActivity.getConfiguration() 4212 .windowConfiguration.getAppBounds()); 4213 4214 // Create activity with no fixed orientation and min aspect ratio greater than parent aspect 4215 // ratio. 4216 final ActivityRecord minAspectRatioActivity = new ActivityBuilder(mAtm).setTask(task) 4217 .setMinAspectRatio(targetMinAspectRatio).build(); 4218 final Rect minAspectRatioAppBounds = new Rect(minAspectRatioActivity.getConfiguration() 4219 .windowConfiguration.getAppBounds()); 4220 4221 // Create unresizeable fixed portait activity with min aspect ratio greater than parent 4222 // aspect ratio. 4223 final ActivityRecord sizeCompatActivity = new ActivityBuilder(mAtm) 4224 .setTask(task).setResizeMode(RESIZE_MODE_UNRESIZEABLE) 4225 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 4226 .setMinAspectRatio(targetMinAspectRatio).build(); 4227 // Resize display running unresizeable activity to make it enter size compat mode. 4228 resizeDisplay(display, 1800, 1000); 4229 final Rect sizeCompatAppBounds = new Rect(sizeCompatActivity.getConfiguration() 4230 .windowConfiguration.getAppBounds()); 4231 4232 // Check that aspect ratio of app bounds is equal to the min aspect ratio. 4233 final float delta = 0.01f; 4234 assertEquals(targetMinAspectRatio, ActivityRecord 4235 .computeAspectRatio(fixedOrientationAppBounds), delta); 4236 assertEquals(targetMinAspectRatio, ActivityRecord 4237 .computeAspectRatio(minAspectRatioAppBounds), delta); 4238 assertEquals(targetMinAspectRatio, ActivityRecord 4239 .computeAspectRatio(sizeCompatAppBounds), delta); 4240 } 4241 4242 @Test 4243 public void testClearSizeCompat_resetOverrideConfig() { 4244 final int origDensity = 480; 4245 final int newDensity = 520; 4246 final DisplayContent display = new TestDisplayContent.Builder(mAtm, 600, 800) 4247 .setDensityDpi(origDensity) 4248 .build(); 4249 setUpApp(display); 4250 prepareUnresizable(mActivity, -1.f /* maxAspect */, SCREEN_ORIENTATION_PORTRAIT); 4251 4252 // Activity should enter size compat with old density after display density change. 4253 display.setForcedDensity(newDensity, UserHandle.USER_CURRENT); 4254 4255 assertScaled(); 4256 assertEquals(origDensity, mActivity.getConfiguration().densityDpi); 4257 4258 // Activity should exit size compat with new density. 4259 mActivity.clearSizeCompatMode(); 4260 4261 assertFitted(); 4262 assertEquals(newDensity, mActivity.getConfiguration().densityDpi); 4263 } 4264 4265 @Test 4266 public void testShouldSendFakeFocus_compatFakeFocusEnabled() { 4267 final ActivityRecord activity = new ActivityBuilder(mAtm) 4268 .setCreateTask(true) 4269 .setOnTop(true) 4270 // Set the component to be that of the test class in order to enable compat changes 4271 .setComponent(ComponentName.createRelative(mContext, 4272 com.android.server.wm.SizeCompatTests.class.getName())) 4273 .build(); 4274 final Task task = activity.getTask(); 4275 spyOn(activity.mLetterboxUiController); 4276 doReturn(true).when(activity.mLetterboxUiController).shouldSendFakeFocus(); 4277 4278 task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 4279 assertTrue(activity.shouldSendCompatFakeFocus()); 4280 4281 task.setWindowingMode(WINDOWING_MODE_PINNED); 4282 assertFalse(activity.shouldSendCompatFakeFocus()); 4283 4284 task.setWindowingMode(WINDOWING_MODE_FREEFORM); 4285 assertFalse(activity.shouldSendCompatFakeFocus()); 4286 } 4287 4288 @Test 4289 public void testShouldSendFakeFocus_compatFakeFocusDisabled() { 4290 final ActivityRecord activity = new ActivityBuilder(mAtm) 4291 .setCreateTask(true) 4292 .setOnTop(true) 4293 // Set the component to be that of the test class in order to enable compat changes 4294 .setComponent(ComponentName.createRelative(mContext, 4295 com.android.server.wm.SizeCompatTests.class.getName())) 4296 .build(); 4297 final Task task = activity.getTask(); 4298 spyOn(activity.mLetterboxUiController); 4299 doReturn(false).when(activity.mLetterboxUiController).shouldSendFakeFocus(); 4300 4301 task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 4302 assertFalse(activity.shouldSendCompatFakeFocus()); 4303 4304 task.setWindowingMode(WINDOWING_MODE_PINNED); 4305 assertFalse(activity.shouldSendCompatFakeFocus()); 4306 4307 task.setWindowingMode(WINDOWING_MODE_FREEFORM); 4308 assertFalse(activity.shouldSendCompatFakeFocus()); 4309 } 4310 4311 private int getExpectedSplitSize(int dimensionToSplit) { 4312 int dividerWindowWidth = 4313 mActivity.mWmService.mContext.getResources().getDimensionPixelSize( 4314 com.android.internal.R.dimen.docked_stack_divider_thickness); 4315 int dividerInsets = 4316 mActivity.mWmService.mContext.getResources().getDimensionPixelSize( 4317 com.android.internal.R.dimen.docked_stack_divider_insets); 4318 return (dimensionToSplit - (dividerWindowWidth - dividerInsets * 2)) / 2; 4319 } 4320 4321 private void assertHorizontalPositionForDifferentDisplayConfigsForLandscapeActivity( 4322 float letterboxHorizontalPositionMultiplier) { 4323 // Set up a display in landscape and ignoring orientation request. 4324 setUpDisplaySizeWithApp(2800, 1400); 4325 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4326 4327 mActivity.mWmService.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( 4328 letterboxHorizontalPositionMultiplier); 4329 prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); 4330 assertFitted(); 4331 // Rotate to put activity in size compat mode. 4332 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 4333 assertTrue(mActivity.inSizeCompatMode()); 4334 // Activity is in size compat mode but not scaled. 4335 assertEquals(new Rect(0, 0, 1400, 700), mActivity.getBounds()); 4336 } 4337 4338 private void assertVerticalPositionForDifferentDisplayConfigsForPortraitActivity( 4339 float letterboxVerticalPositionMultiplier) { 4340 // Set up a display in portrait and ignoring orientation request. 4341 setUpDisplaySizeWithApp(1400, 2800); 4342 mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); 4343 4344 mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier( 4345 letterboxVerticalPositionMultiplier); 4346 prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); 4347 4348 assertFitted(); 4349 4350 // Rotate to put activity in size compat mode. 4351 rotateDisplay(mActivity.mDisplayContent, ROTATION_90); 4352 4353 assertTrue(mActivity.inSizeCompatMode()); 4354 // Activity is in size compat mode but not scaled. 4355 assertEquals(new Rect(1050, 0, 1750, 1400), mActivity.getBounds()); 4356 } 4357 4358 private static WindowState addWindowToActivity(ActivityRecord activity) { 4359 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 4360 params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 4361 params.setFitInsetsSides(0); 4362 params.setFitInsetsTypes(0); 4363 final TestWindowState w = new TestWindowState( 4364 activity.mWmService, mock(Session.class), new TestIWindow(), params, activity); 4365 makeWindowVisible(w); 4366 w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; 4367 activity.addWindow(w); 4368 return w; 4369 } 4370 4371 private static TestWindowState addStatusBar(DisplayContent displayContent) { 4372 final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); 4373 doReturn(true).when(displayPolicy).hasStatusBar(); 4374 displayPolicy.onConfigurationChanged(); 4375 4376 final TestWindowToken token = createTestWindowToken( 4377 TYPE_STATUS_BAR, displayContent); 4378 final WindowManager.LayoutParams attrs = 4379 new WindowManager.LayoutParams(TYPE_STATUS_BAR); 4380 attrs.gravity = android.view.Gravity.TOP; 4381 attrs.layoutInDisplayCutoutMode = 4382 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 4383 attrs.setFitInsetsTypes(0 /* types */); 4384 final TestWindowState statusBar = new TestWindowState( 4385 displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token); 4386 token.addWindow(statusBar); 4387 statusBar.setRequestedSize(displayContent.mBaseDisplayWidth, 4388 SystemBarUtils.getStatusBarHeight(displayContent.getDisplayUiContext())); 4389 4390 displayPolicy.addWindowLw(statusBar, attrs); 4391 displayPolicy.layoutWindowLw(statusBar, null, displayContent.mDisplayFrames); 4392 return statusBar; 4393 } 4394 4395 /** 4396 * Returns an ActivityRecord instance with the specified attributes on the same task. By 4397 * constructing the ActivityRecord, forces {@link ActivityInfo} to be loaded with the compat 4398 * config settings. 4399 */ 4400 private ActivityRecord buildActivityRecord(boolean supportsSizeChanges, int resizeMode, 4401 @ScreenOrientation int screenOrientation) { 4402 return new ActivityBuilder(mAtm) 4403 .setTask(mTask) 4404 .setResizeMode(resizeMode) 4405 .setSupportsSizeChanges(supportsSizeChanges) 4406 .setScreenOrientation(screenOrientation) 4407 .setComponent(ComponentName.createRelative(mContext, 4408 SizeCompatTests.class.getName())) 4409 .setUid(android.os.Process.myUid()) 4410 .build(); 4411 } 4412 4413 static void prepareUnresizable(ActivityRecord activity, int screenOrientation) { 4414 prepareUnresizable(activity, -1 /* maxAspect */, screenOrientation); 4415 } 4416 4417 static void prepareUnresizable(ActivityRecord activity, float maxAspect, 4418 int screenOrientation) { 4419 prepareLimitedBounds(activity, maxAspect, screenOrientation, true /* isUnresizable */); 4420 } 4421 4422 static void prepareLimitedBounds(ActivityRecord activity, int screenOrientation, 4423 boolean isUnresizable) { 4424 prepareLimitedBounds(activity, -1 /* maxAspect */, screenOrientation, isUnresizable); 4425 } 4426 4427 /** 4428 * Setups {@link #mActivity} with restriction on its bounds, such as maxAspect, fixed 4429 * orientation, and/or whether it is resizable. 4430 */ 4431 static void prepareLimitedBounds(ActivityRecord activity, float maxAspect, 4432 int screenOrientation, boolean isUnresizable) { 4433 activity.info.resizeMode = isUnresizable 4434 ? RESIZE_MODE_UNRESIZEABLE 4435 : RESIZE_MODE_RESIZEABLE; 4436 final Task task = activity.getTask(); 4437 if (task != null) { 4438 // Update the Task resize value as activity will follow the task. 4439 task.mResizeMode = activity.info.resizeMode; 4440 task.getRootActivity().info.resizeMode = activity.info.resizeMode; 4441 } 4442 activity.setVisibleRequested(true); 4443 if (maxAspect >= 0) { 4444 activity.info.setMaxAspectRatio(maxAspect); 4445 } 4446 if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { 4447 activity.info.screenOrientation = screenOrientation; 4448 activity.setRequestedOrientation(screenOrientation); 4449 } 4450 // Make sure to use the provided configuration to construct the size compat fields. 4451 activity.clearSizeCompatMode(); 4452 activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 4453 // Make sure the display configuration reflects the change of activity. 4454 if (activity.mDisplayContent.updateOrientation()) { 4455 activity.mDisplayContent.sendNewConfiguration(); 4456 } 4457 } 4458 4459 /** Asserts that the size of activity is larger than its parent so it is scaling. */ 4460 private void assertScaled() { 4461 assertTrue(mActivity.inSizeCompatMode()); 4462 assertNotEquals(1f, mActivity.getCompatScale(), 0.0001f /* delta */); 4463 } 4464 4465 /** Asserts that the activity is best fitted in the parent. */ 4466 private void assertFitted() { 4467 final boolean inSizeCompatMode = mActivity.inSizeCompatMode(); 4468 final String failedConfigInfo = inSizeCompatMode 4469 ? ("ParentConfig=" + mActivity.getParent().getConfiguration() 4470 + " ActivityConfig=" + mActivity.getConfiguration()) 4471 : ""; 4472 assertFalse(failedConfigInfo, inSizeCompatMode); 4473 assertFalse(mActivity.hasSizeCompatBounds()); 4474 } 4475 4476 /** Asserts the activity max bounds inherit from the TaskDisplayArea. */ 4477 private void assertMaxBoundsInheritDisplayAreaBounds() { 4478 assertThat(mActivity.getConfiguration().windowConfiguration.getMaxBounds()) 4479 .isEqualTo(mTask.getDisplayArea().getBounds()); 4480 } 4481 4482 /** 4483 * Asserts activity-level letterbox or size compat mode size compat mode, so activity max 4484 * bounds are sandboxed. 4485 */ 4486 private void assertActivityMaxBoundsSandboxed() { 4487 assertActivityMaxBoundsSandboxed(mActivity); 4488 } 4489 4490 /** 4491 * Asserts activity-level letterbox or size compat mode size compat mode on the specified 4492 * activity, so activity max bounds are sandboxed. 4493 */ 4494 private void assertActivityMaxBoundsSandboxed(ActivityRecord activity) { 4495 // Activity max bounds are sandboxed due to size compat mode. 4496 assertThat(activity.getConfiguration().windowConfiguration.getMaxBounds()) 4497 .isEqualTo(activity.getWindowConfiguration().getBounds()); 4498 } 4499 4500 private void verifyLogAppCompatState(ActivityRecord activity, int state) { 4501 verify(mActivityMetricsLogger, atLeastOnce()).logAppCompatState( 4502 argThat(r -> activity == r && r.getAppCompatState() == state)); 4503 } 4504 4505 static Configuration rotateDisplay(DisplayContent display, int rotation) { 4506 final Configuration c = new Configuration(); 4507 display.getDisplayRotation().setRotation(rotation); 4508 display.computeScreenConfiguration(c); 4509 display.onRequestedOverrideConfigurationChanged(c); 4510 return c; 4511 } 4512 4513 private static void resizeDisplay(DisplayContent displayContent, int width, int height) { 4514 displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity, 4515 displayContent.mBaseDisplayPhysicalXDpi, displayContent.mBaseDisplayPhysicalYDpi); 4516 final Configuration c = new Configuration(); 4517 displayContent.computeScreenConfiguration(c); 4518 displayContent.onRequestedOverrideConfigurationChanged(c); 4519 } 4520 4521 private static void setNeverConstrainDisplayApisFlag(@Nullable String value, 4522 boolean makeDefault) { 4523 DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, 4524 CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS, value, makeDefault); 4525 } 4526 4527 private static void setNeverConstrainDisplayApisAllPackagesFlag(boolean value, 4528 boolean makeDefault) { 4529 DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, 4530 CONFIG_NEVER_CONSTRAIN_DISPLAY_APIS_ALL_PACKAGES, String.valueOf(value), 4531 makeDefault); 4532 } 4533 4534 private static void setAlwaysConstrainDisplayApisFlag(@Nullable String value, 4535 boolean makeDefault) { 4536 DeviceConfig.setProperty(NAMESPACE_CONSTRAIN_DISPLAY_APIS, 4537 CONFIG_ALWAYS_CONSTRAIN_DISPLAY_APIS, value, makeDefault); 4538 } 4539 } 4540