Merge "Fix immersive app resizing when repositioning" into 24D1-dev
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 65d5c04..78cb8d0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -76,7 +76,6 @@
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
@@ -86,6 +85,7 @@
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
@@ -311,6 +311,7 @@
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;
@@ -352,6 +353,7 @@
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;
@@ -8533,6 +8535,13 @@
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);
@@ -8545,14 +8554,6 @@
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
@@ -8764,7 +8765,7 @@
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;
}
@@ -8793,13 +8794,27 @@
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
@@ -8819,9 +8834,8 @@
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
@@ -8841,7 +8855,8 @@
// 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;
@@ -8864,6 +8879,18 @@
}
}
+ boolean isImmersiveMode(@NonNull Rect parentBounds) {
+ if (!mResolveConfigHint.mUseOverrideInsetsForStableBounds) {
+ 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();
@@ -8906,6 +8933,10 @@
return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
}
+ boolean isLetterboxedForAspectRatioOnly() {
+ return mLetterboxBoundsForAspectRatio != null;
+ }
+
boolean isAspectRatioApplied() {
return mIsAspectRatioApplied;
}
@@ -9198,11 +9229,11 @@
// 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();
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 691176a..7192a20 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -1686,7 +1686,7 @@
if (mainWin.isLetterboxedForDisplayCutout()) {
return "DISPLAY_CUTOUT";
}
- if (mActivityRecord.isAspectRatioApplied()) {
+ if (mActivityRecord.isLetterboxedForAspectRatioOnly()) {
return "ASPECT_RATIO";
}
return "UNKNOWN_REASON";
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 bf15bc8..c6476df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -108,6 +108,7 @@
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;
@@ -123,6 +124,7 @@
import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.DeviceStateController.DeviceState;
+import com.android.window.flags.Flags;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -187,6 +189,7 @@
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) {
@@ -395,6 +398,55 @@
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);
@@ -3994,8 +4046,7 @@
// 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();