Loading services/core/java/com/android/server/wm/ActivityRecord.java +48 −17 Original line number Diff line number Diff line Loading @@ -315,6 +315,7 @@ import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; Loading Loading @@ -356,6 +357,7 @@ import android.view.RemoteAnimationTarget; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; Loading Loading @@ -8560,6 +8562,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (isFixedOrientationLetterboxAllowed) { resolveFixedOrientationConfiguration(newParentConfiguration); } // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds // are already calculated in resolveFixedOrientationConfiguration. // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mLetterboxUiController.hasFullscreenOverride()) { resolveAspectRatioRestriction(newParentConfiguration); } final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets(); if (compatDisplayInsets != null) { resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets); Loading @@ -8572,14 +8581,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!matchParentBounds()) { computeConfigByResolveHint(resolvedConfig, newParentConfiguration); } // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds // are already calculated in resolveFixedOrientationConfiguration, or if in size compat // mode, it should already be calculated in resolveSizeCompatModeConfiguration. // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. } if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mInSizeCompatModeForBounds && !mLetterboxUiController.hasFullscreenOverride()) { resolveAspectRatioRestriction(newParentConfiguration); } if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null Loading Loading @@ -8801,7 +8802,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION; } // Letterbox for limited aspect ratio. if (mIsAspectRatioApplied) { if (isLetterboxedForAspectRatioOnly()) { return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO; } Loading Loading @@ -8830,13 +8831,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); final float screenResolvedBoundsWidth = screenResolvedBounds.width(); final float parentAppBoundsWidth = parentAppBounds.width(); final boolean isImmersiveMode = isImmersiveMode(parentBounds); final Insets navBarInsets; if (isImmersiveMode) { navBarInsets = mDisplayContent.getInsetsStateController() .getRawInsetsState().calculateInsets( parentBounds, WindowInsets.Type.navigationBars(), true /* ignoreVisibility */); } else { navBarInsets = Insets.NONE; } // Horizontal position int offsetX = 0; if (parentBounds.width() != screenResolvedBoundsWidth) { if (screenResolvedBoundsWidth <= parentAppBoundsWidth) { float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier( newParentConfiguration); offsetX = Math.max(0, (int) Math.ceil((parentAppBoundsWidth // If in immersive mode, always align to right and overlap right insets (task bar) // as they are transient and hidden. This removes awkward right spacing. final int appWidth = (int) (parentAppBoundsWidth + navBarInsets.right); offsetX = Math.max(0, (int) Math.ceil((appWidth - screenResolvedBoundsWidth) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment Loading @@ -8856,9 +8871,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A newParentConfiguration); // 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 final int appHeight = (int) (parentAppBoundsHeight + navBarInsets.bottom); offsetY = Math.max(0, (int) Math.ceil((appHeight - screenResolvedBoundsHeight) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment Loading @@ -8878,7 +8892,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the top is aligned with parentAppBounds add the vertical insets back so that the app // content aligns with the status bar if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top) { if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top && !isImmersiveMode) { resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top; if (mSizeCompatBounds != null) { mSizeCompatBounds.top = parentBounds.top; Loading @@ -8901,6 +8916,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } boolean isImmersiveMode(@NonNull Rect parentBounds) { if (!mResolveConfigHint.mUseOverrideInsetsForConfig) { return false; } final Insets navBarInsets = mDisplayContent.getInsetsStateController() .getRawInsetsState().calculateInsets( parentBounds, WindowInsets.Type.navigationBars(), false /* ignoreVisibility */); return Insets.NONE.equals(navBarInsets); } @NonNull Rect getScreenResolvedBounds() { final Configuration resolvedConfig = getResolvedOverrideConfiguration(); final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); Loading Loading @@ -8943,6 +8970,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mLetterboxBoundsForFixedOrientationAndAspectRatio != null; } boolean isLetterboxedForAspectRatioOnly() { return mLetterboxBoundsForAspectRatio != null; } boolean isAspectRatioApplied() { return mIsAspectRatioApplied; } Loading Loading @@ -9235,11 +9266,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // orientation bounds (stored in resolved bounds) instead of parent bounds since the // activity will be displayed within them even if it is in size compat mode. They should be // saved here before resolved bounds are overridden below. final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio() final Rect containerBounds = isAspectRatioApplied() ? new Rect(resolvedBounds) : newParentConfiguration.windowConfiguration.getBounds(); final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio() ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds()) final Rect containerAppBounds = isAspectRatioApplied() ? new Rect(resolvedConfig.windowConfiguration.getAppBounds()) : newParentConfiguration.windowConfiguration.getAppBounds(); final int requestedOrientation = getRequestedConfigurationOrientation(); Loading services/core/java/com/android/server/wm/LetterboxUiController.java +1 −1 Original line number Diff line number Diff line Loading @@ -1704,7 +1704,7 @@ final class LetterboxUiController { if (mainWin.isLetterboxedForDisplayCutout()) { return "DISPLAY_CUTOUT"; } if (mActivityRecord.isAspectRatioApplied()) { if (mActivityRecord.isLetterboxedForAspectRatioOnly()) { return "ASPECT_RATIO"; } return "UNKNOWN_REASON"; Loading services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +52 −2 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.view.InsetsFrameProvider; Loading Loading @@ -188,6 +189,7 @@ public class SizeCompatTests extends WindowTestsBase { private void setUpApp(DisplayContent display) { mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build(); mActivity = mTask.getTopNonFinishingActivity(); doReturn(false).when(mActivity).isImmersiveMode(any()); } private void setUpDisplaySizeWithApp(int dw, int dh) { Loading Loading @@ -396,6 +398,55 @@ public class SizeCompatTests extends WindowTestsBase { verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); } // TODO(b/333663877): Enable test after fix @Test @RequiresFlagsDisabled({Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION}) public void testRepositionLandscapeImmersiveAppWithDisplayCutout() { final int dw = 2100; final int dh = 2000; final int cutoutHeight = 150; final TestDisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh) .setCanRotate(false) .setNotch(cutoutHeight) .build(); setUpApp(display); display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); doReturn(true).when(mActivity).isImmersiveMode(any()); prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, SCREEN_ORIENTATION_LANDSCAPE); addWindowToActivity(mActivity); mActivity.mRootWindowContainer.performSurfacePlacement(); final Function<ActivityRecord, Rect> innerBoundsOf = (ActivityRecord a) -> { final Rect bounds = new Rect(); a.mLetterboxUiController.getLetterboxInnerBounds(bounds); return bounds; }; final Consumer<Integer> doubleClick = (Integer y) -> { mActivity.mLetterboxUiController.handleVerticalDoubleTap(y); mActivity.mRootWindowContainer.performSurfacePlacement(); }; final Rect bounds = mActivity.getBounds(); assertTrue(bounds.top > cutoutHeight && bounds.bottom < dh); assertEquals(dw, bounds.width()); // Double click bottom. doubleClick.accept(dh - 10); assertEquals(dh, innerBoundsOf.apply(mActivity).bottom); // Double click top. doubleClick.accept(10); doubleClick.accept(10); assertEquals(cutoutHeight, innerBoundsOf.apply(mActivity).top); } @Test public void testResetOpaqueReferenceWhenOpaqueIsDestroyed() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); Loading Loading @@ -4034,8 +4085,7 @@ public class SizeCompatTests extends WindowTestsBase { // Prepare unresizable landscape activity prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); final DisplayPolicy displayPolicy = mActivity.mDisplayContent.getDisplayPolicy(); doReturn(immersive).when(displayPolicy).isImmersiveMode(); doReturn(immersive).when(mActivity).isImmersiveMode(any()); mActivity.mRootWindowContainer.performSurfacePlacement(); Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +48 −17 Original line number Diff line number Diff line Loading @@ -315,6 +315,7 @@ import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; Loading Loading @@ -356,6 +357,7 @@ import android.view.RemoteAnimationTarget; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; Loading Loading @@ -8560,6 +8562,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (isFixedOrientationLetterboxAllowed) { resolveFixedOrientationConfiguration(newParentConfiguration); } // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds // are already calculated in resolveFixedOrientationConfiguration. // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mLetterboxUiController.hasFullscreenOverride()) { resolveAspectRatioRestriction(newParentConfiguration); } final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets(); if (compatDisplayInsets != null) { resolveSizeCompatModeConfiguration(newParentConfiguration, compatDisplayInsets); Loading @@ -8572,14 +8581,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (!matchParentBounds()) { computeConfigByResolveHint(resolvedConfig, newParentConfiguration); } // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds // are already calculated in resolveFixedOrientationConfiguration, or if in size compat // mode, it should already be calculated in resolveSizeCompatModeConfiguration. // Don't apply aspect ratio if app is overridden to fullscreen by device user/manufacturer. } if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mInSizeCompatModeForBounds && !mLetterboxUiController.hasFullscreenOverride()) { resolveAspectRatioRestriction(newParentConfiguration); } if (isFixedOrientationLetterboxAllowed || compatDisplayInsets != null Loading Loading @@ -8801,7 +8802,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION; } // Letterbox for limited aspect ratio. if (mIsAspectRatioApplied) { if (isLetterboxedForAspectRatioOnly()) { return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO; } Loading Loading @@ -8830,13 +8831,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); final float screenResolvedBoundsWidth = screenResolvedBounds.width(); final float parentAppBoundsWidth = parentAppBounds.width(); final boolean isImmersiveMode = isImmersiveMode(parentBounds); final Insets navBarInsets; if (isImmersiveMode) { navBarInsets = mDisplayContent.getInsetsStateController() .getRawInsetsState().calculateInsets( parentBounds, WindowInsets.Type.navigationBars(), true /* ignoreVisibility */); } else { navBarInsets = Insets.NONE; } // Horizontal position int offsetX = 0; if (parentBounds.width() != screenResolvedBoundsWidth) { if (screenResolvedBoundsWidth <= parentAppBoundsWidth) { float positionMultiplier = mLetterboxUiController.getHorizontalPositionMultiplier( newParentConfiguration); offsetX = Math.max(0, (int) Math.ceil((parentAppBoundsWidth // If in immersive mode, always align to right and overlap right insets (task bar) // as they are transient and hidden. This removes awkward right spacing. final int appWidth = (int) (parentAppBoundsWidth + navBarInsets.right); offsetX = Math.max(0, (int) Math.ceil((appWidth - screenResolvedBoundsWidth) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment Loading @@ -8856,9 +8871,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A newParentConfiguration); // 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 final int appHeight = (int) (parentAppBoundsHeight + navBarInsets.bottom); offsetY = Math.max(0, (int) Math.ceil((appHeight - screenResolvedBoundsHeight) * positionMultiplier) // This is added to make sure that insets added inside // CompatDisplayInsets#getContainerBounds() do not break the alignment Loading @@ -8878,7 +8892,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the top is aligned with parentAppBounds add the vertical insets back so that the app // content aligns with the status bar if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top) { if (resolvedConfig.windowConfiguration.getAppBounds().top == parentAppBounds.top && !isImmersiveMode) { resolvedConfig.windowConfiguration.getBounds().top = parentBounds.top; if (mSizeCompatBounds != null) { mSizeCompatBounds.top = parentBounds.top; Loading @@ -8901,6 +8916,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } boolean isImmersiveMode(@NonNull Rect parentBounds) { if (!mResolveConfigHint.mUseOverrideInsetsForConfig) { return false; } final Insets navBarInsets = mDisplayContent.getInsetsStateController() .getRawInsetsState().calculateInsets( parentBounds, WindowInsets.Type.navigationBars(), false /* ignoreVisibility */); return Insets.NONE.equals(navBarInsets); } @NonNull Rect getScreenResolvedBounds() { final Configuration resolvedConfig = getResolvedOverrideConfiguration(); final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); Loading Loading @@ -8943,6 +8970,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return mLetterboxBoundsForFixedOrientationAndAspectRatio != null; } boolean isLetterboxedForAspectRatioOnly() { return mLetterboxBoundsForAspectRatio != null; } boolean isAspectRatioApplied() { return mIsAspectRatioApplied; } Loading Loading @@ -9235,11 +9266,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // orientation bounds (stored in resolved bounds) instead of parent bounds since the // activity will be displayed within them even if it is in size compat mode. They should be // saved here before resolved bounds are overridden below. final Rect containerBounds = isLetterboxedForFixedOrientationAndAspectRatio() final Rect containerBounds = isAspectRatioApplied() ? new Rect(resolvedBounds) : newParentConfiguration.windowConfiguration.getBounds(); final Rect containerAppBounds = isLetterboxedForFixedOrientationAndAspectRatio() ? new Rect(getResolvedOverrideConfiguration().windowConfiguration.getAppBounds()) final Rect containerAppBounds = isAspectRatioApplied() ? new Rect(resolvedConfig.windowConfiguration.getAppBounds()) : newParentConfiguration.windowConfiguration.getAppBounds(); final int requestedOrientation = getRequestedConfigurationOrientation(); Loading
services/core/java/com/android/server/wm/LetterboxUiController.java +1 −1 Original line number Diff line number Diff line Loading @@ -1704,7 +1704,7 @@ final class LetterboxUiController { if (mainWin.isLetterboxedForDisplayCutout()) { return "DISPLAY_CUTOUT"; } if (mActivityRecord.isAspectRatioApplied()) { if (mActivityRecord.isLetterboxedForAspectRatioOnly()) { return "ASPECT_RATIO"; } return "UNKNOWN_REASON"; Loading
services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +52 −2 Original line number Diff line number Diff line Loading @@ -108,6 +108,7 @@ import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsDisabled; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.view.InsetsFrameProvider; Loading Loading @@ -188,6 +189,7 @@ public class SizeCompatTests extends WindowTestsBase { private void setUpApp(DisplayContent display) { mTask = new TaskBuilder(mSupervisor).setDisplay(display).setCreateActivity(true).build(); mActivity = mTask.getTopNonFinishingActivity(); doReturn(false).when(mActivity).isImmersiveMode(any()); } private void setUpDisplaySizeWithApp(int dw, int dh) { Loading Loading @@ -396,6 +398,55 @@ public class SizeCompatTests extends WindowTestsBase { verify(translucentActivity.mLetterboxUiController).updateInheritedLetterbox(); } // TODO(b/333663877): Enable test after fix @Test @RequiresFlagsDisabled({Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION}) public void testRepositionLandscapeImmersiveAppWithDisplayCutout() { final int dw = 2100; final int dh = 2000; final int cutoutHeight = 150; final TestDisplayContent display = new TestDisplayContent.Builder(mAtm, dw, dh) .setCanRotate(false) .setNotch(cutoutHeight) .build(); setUpApp(display); display.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */); mWm.mLetterboxConfiguration.setLetterboxVerticalPositionMultiplier(0.5f); mWm.mLetterboxConfiguration.setIsVerticalReachabilityEnabled(true); doReturn(true).when(mActivity).isImmersiveMode(any()); prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, SCREEN_ORIENTATION_LANDSCAPE); addWindowToActivity(mActivity); mActivity.mRootWindowContainer.performSurfacePlacement(); final Function<ActivityRecord, Rect> innerBoundsOf = (ActivityRecord a) -> { final Rect bounds = new Rect(); a.mLetterboxUiController.getLetterboxInnerBounds(bounds); return bounds; }; final Consumer<Integer> doubleClick = (Integer y) -> { mActivity.mLetterboxUiController.handleVerticalDoubleTap(y); mActivity.mRootWindowContainer.performSurfacePlacement(); }; final Rect bounds = mActivity.getBounds(); assertTrue(bounds.top > cutoutHeight && bounds.bottom < dh); assertEquals(dw, bounds.width()); // Double click bottom. doubleClick.accept(dh - 10); assertEquals(dh, innerBoundsOf.apply(mActivity).bottom); // Double click top. doubleClick.accept(10); doubleClick.accept(10); assertEquals(cutoutHeight, innerBoundsOf.apply(mActivity).top); } @Test public void testResetOpaqueReferenceWhenOpaqueIsDestroyed() { mWm.mLetterboxConfiguration.setTranslucentLetterboxingOverrideEnabled(true); Loading Loading @@ -4034,8 +4085,7 @@ public class SizeCompatTests extends WindowTestsBase { // Prepare unresizable landscape activity prepareUnresizable(mActivity, SCREEN_ORIENTATION_LANDSCAPE); final DisplayPolicy displayPolicy = mActivity.mDisplayContent.getDisplayPolicy(); doReturn(immersive).when(displayPolicy).isImmersiveMode(); doReturn(immersive).when(mActivity).isImmersiveMode(any()); mActivity.mRootWindowContainer.performSurfacePlacement(); Loading