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