diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d93778e18748b..fd74dacaf2d65 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -8445,21 +8445,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private void updateResolvedBoundsPosition(Configuration newParentConfiguration) { final Configuration resolvedConfig = getResolvedOverrideConfiguration(); final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); + if (resolvedBounds.isEmpty()) { + return; + } final Rect screenResolvedBounds = mSizeCompatBounds != null ? mSizeCompatBounds : resolvedBounds; final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); - if (resolvedBounds.isEmpty()) { - return; - } + final float screenResolvedBoundsWidth = screenResolvedBounds.width(); + final float parentAppBoundsWidth = parentAppBounds.width(); // Horizontal position int offsetX = 0; - if (parentBounds.width() != screenResolvedBounds.width()) { - if (screenResolvedBounds.width() <= parentAppBounds.width()) { + if (parentBounds.width() != screenResolvedBoundsWidth) { + if (screenResolvedBoundsWidth <= parentAppBoundsWidth) { float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier( newParentConfiguration); - offsetX = Math.max(0, (int) Math.ceil((parentAppBounds.width() - - screenResolvedBounds.width()) * positionMultiplier) + offsetX = Math.max(0, (int) Math.ceil((parentAppBoundsWidth + - screenResolvedBoundsWidth) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment // provided by the positionMultiplier @@ -8467,14 +8469,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + final float parentAppBoundsHeight = parentAppBounds.height(); + final float parentBoundsHeight = parentBounds.height(); + final float screenResolvedBoundsHeight = screenResolvedBounds.height(); // Vertical position int offsetY = 0; - if (parentBounds.height() != screenResolvedBounds.height()) { - if (screenResolvedBounds.height() <= parentAppBounds.height()) { + if (parentBoundsHeight != screenResolvedBoundsHeight) { + if (screenResolvedBoundsHeight <= parentAppBoundsHeight) { float positionMultiplier = mLetterboxUiController.getVerticalPositionMultiplier( newParentConfiguration); - offsetY = Math.max(0, (int) Math.ceil((parentAppBounds.height() - - screenResolvedBounds.height()) * positionMultiplier) + // If in immersive mode, always align to bottom and overlap bottom insets (nav bar, + // task bar) as they are transient and hidden. This removes awkward bottom spacing. + final float newHeight = mDisplayContent.getDisplayPolicy().isImmersiveMode() + ? parentBoundsHeight : parentAppBoundsHeight; + offsetY = Math.max(0, (int) Math.ceil((newHeight + - screenResolvedBoundsHeight) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment // provided by the positionMultiplier diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 899c36c4a1a73..77e70a25d497f 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1254,6 +1254,10 @@ public class DisplayPolicy { return mNavigationBar; } + boolean isImmersiveMode() { + return mIsImmersiveMode; + } + /** * Control the animation to run when a window's state changes. Return a positive number to * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 06bcbf34e0427..2dd34eb5ac4d7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -3510,6 +3510,51 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(expectedHeight, capturedCrops.get(1).bottom); } + @Test + public void testLetterboxAlignedToBottom_NotOverlappingNavbar() { + assertLandscapeActivityAlignedToBottomWithNavbar(false /* immersive */); + } + + @Test + public void testImmersiveLetterboxAlignedToBottom_OverlappingNavbar() { + assertLandscapeActivityAlignedToBottomWithNavbar(true /* immersive */); + } + + private void assertLandscapeActivityAlignedToBottomWithNavbar(boolean immersive) { + final int screenHeight = 2800; + final int screenWidth = 1400; + final int taskbarHeight = 200; + setUpDisplaySizeWithApp(screenWidth, screenHeight); + + mActivity.mDisplayContent.setIgnoreOrientationRequest(true); + mActivity.mWmService.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(1.0f); + + final InsetsSource navSource = new InsetsSource( + InsetsSource.createId(null, 0, navigationBars()), navigationBars()); + navSource.setInsetsRoundedCornerFrame(true); + // Immersive activity has transient navbar + navSource.setVisible(!immersive); + navSource.setFrame(new Rect(0, screenHeight - taskbarHeight, screenWidth, screenHeight)); + mActivity.mWmService.mLetterboxConfiguration.setLetterboxActivityCornersRadius(15); + + final WindowState w1 = addWindowToActivity(mActivity); + w1.mAboveInsetsState.addSource(navSource); + + // Prepare unresizable landscape activity + prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); + final DisplayPolicy displayPolicy = mActivity.mDisplayContent.getDisplayPolicy(); + doReturn(immersive).when(displayPolicy).isImmersiveMode(); + + mActivity.mRootWindowContainer.performSurfacePlacement(); + + LetterboxDetails letterboxDetails = mActivity.mLetterboxUiController.getLetterboxDetails(); + + // Letterboxed activity at bottom + assertEquals(new Rect(0, 2100, 1400, 2800), mActivity.getBounds()); + final int expectedHeight = immersive ? screenHeight : screenHeight - taskbarHeight; + assertEquals(expectedHeight, letterboxDetails.getLetterboxInnerBounds().bottom); + } + @Test public void testSplitScreenLetterboxDetailsForStatusBar_twoLetterboxedApps() { mAtm.mDevEnableNonResizableMultiWindow = true; @@ -3938,7 +3983,7 @@ public class SizeCompatTests extends WindowTestsBase { mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); mWm.mLetterboxConfiguration.setIsAutomaticReachabilityInBookModeEnabled(true); mWm.mLetterboxConfiguration.setLetterboxHorizontalPositionMultiplier( - 1.0f /*letterboxVerticalPositionMultiplier*/); + 1.0f /*letterboxHorizontalPositionMultiplier*/); prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT); Rect letterboxNoFold = new Rect(2100, 0, 2800, 1400);