diff options
6 files changed, 108 insertions, 13 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index 9b850de6fede..c5ee3137e5ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -33,6 +33,7 @@ import android.util.Size import com.android.wm.shell.R import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout +import kotlin.math.ceil val DESKTOP_MODE_INITIAL_BOUNDS_SCALE: Float = SystemProperties.getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f @@ -190,22 +191,22 @@ fun maximizeSizeGivenAspectRatio( val finalWidth: Int // Get orientation either through top activity or task's orientation if (taskInfo.hasPortraitTopActivity()) { - val tempWidth = (targetHeight / aspectRatio).toInt() + val tempWidth = ceil(targetHeight / aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight finalWidth = tempWidth } else { finalWidth = targetWidth - finalHeight = (finalWidth * aspectRatio).toInt() + finalHeight = ceil(finalWidth * aspectRatio).toInt() } } else { - val tempWidth = (targetHeight * aspectRatio).toInt() + val tempWidth = ceil(targetHeight * aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight finalWidth = tempWidth } else { finalWidth = targetWidth - finalHeight = (finalWidth / aspectRatio).toInt() + finalHeight = ceil(finalWidth / aspectRatio).toInt() } } return Size(finalWidth, finalHeight + captionInsets) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index edb9b2d2fede..fbfdb79eaaec 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -279,7 +279,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() private val DEFAULT_PORTRAIT_BOUNDS = Rect(200, 165, 1400, 2085) private val RESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 435, 1575, 1635) private val RESIZABLE_PORTRAIT_BOUNDS = Rect(680, 75, 1880, 1275) - private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 449, 1575, 1611) + private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 448, 1575, 1611) private val UNRESIZABLE_PORTRAIT_BOUNDS = Rect(830, 75, 1730, 1275) private val wallpaperToken = MockToken().token() diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java index dff072e2dcf8..600216440090 100644 --- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; @@ -48,6 +49,8 @@ import java.io.PrintWriter; */ class AppCompatLetterboxPolicy { + private static final int DIFF_TOLERANCE_PX = 1; + @NonNull private final ActivityRecord mActivityRecord; @NonNull @@ -56,6 +59,9 @@ class AppCompatLetterboxPolicy { private final AppCompatRoundedCorners mAppCompatRoundedCorners; @NonNull private final AppCompatConfiguration mAppCompatConfiguration; + // Convenience temporary object to save allocation when calculating Rect. + @NonNull + private final Rect mTmpRect = new Rect(); private boolean mLastShouldShowLetterboxUi; @@ -71,7 +77,7 @@ class AppCompatLetterboxPolicy { : new LegacyLetterboxPolicyState(); // TODO (b/358334569) Improve cutout logic dependency on app compat. mAppCompatRoundedCorners = new AppCompatRoundedCorners(mActivityRecord, - this::isLetterboxedNotForDisplayCutout); + this::ieEligibleForRoundedCorners); mAppCompatConfiguration = appCompatConfiguration; } @@ -84,7 +90,7 @@ class AppCompatLetterboxPolicy { mLetterboxPolicyState.stop(); } - /** @return {@value true} if the letterbox policy is running and the activity letterboxed. */ + /** @return {@code true} if the letterbox policy is running and the activity letterboxed. */ boolean isRunning() { return mLetterboxPolicyState.isRunning(); } @@ -130,7 +136,7 @@ class AppCompatLetterboxPolicy { * <li>The activity is in fullscreen. * <li>The activity is portrait-only. * <li>The activity doesn't have a starting window (education should only be displayed - * once the starting window is removed in {@link #removeStartingWindow}). + * once the starting window is removed in {@link ActivityRecord#removeStartingWindow}). * </ul> */ boolean isEligibleForLetterboxEducation() { @@ -294,16 +300,40 @@ class AppCompatLetterboxPolicy { } } + private boolean ieEligibleForRoundedCorners(@NonNull WindowState mainWindow) { + return isLetterboxedNotForDisplayCutout(mainWindow) + && !isFreeformActivityMatchParentAppBoundsHeight(); + } + private boolean isLetterboxedNotForDisplayCutout(@NonNull WindowState mainWindow) { return shouldShowLetterboxUi(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout(); } + private boolean isFreeformActivityMatchParentAppBoundsHeight() { + if (!Flags.excludeCaptionFromAppBounds()) { + return false; + } + final Task task = mActivityRecord.getTask(); + if (task == null) { + return false; + } + final Rect parentAppBounds = task.getWindowConfiguration().getAppBounds(); + if (parentAppBounds == null) { + return false; + } + + mLetterboxPolicyState.getLetterboxInnerBounds(mTmpRect); + final int diff = parentAppBounds.height() - mTmpRect.height(); + // Compare bounds with tolerance of 1 px to account for rounding error calculations. + return task.getWindowingMode() == WINDOWING_MODE_FREEFORM && diff <= DIFF_TOLERANCE_PX; + } + private static boolean shouldNotLayoutLetterbox(@Nullable WindowState w) { if (w == null) { return true; } - final int type = w.mAttrs.type; + final int type = w.getAttrs().type; // Allow letterbox to be displayed early for base application or application starting // windows even if it is not on the top z order to prevent flickering when the // letterboxed window is brought to the top diff --git a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java index 92d76e5616d8..8165638d4bda 100644 --- a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java +++ b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java @@ -35,12 +35,12 @@ class AppCompatRoundedCorners { @NonNull private final ActivityRecord mActivityRecord; @NonNull - private final Predicate<WindowState> mIsLetterboxedNotForDisplayCutout; + private final Predicate<WindowState> mRoundedCornersWindowCondition; AppCompatRoundedCorners(@NonNull ActivityRecord activityRecord, - @NonNull Predicate<WindowState> isLetterboxedNotForDisplayCutout) { + @NonNull Predicate<WindowState> roundedCornersWindowCondition) { mActivityRecord = activityRecord; - mIsLetterboxedNotForDisplayCutout = isLetterboxedNotForDisplayCutout; + mRoundedCornersWindowCondition = roundedCornersWindowCondition; } void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) { @@ -136,7 +136,7 @@ class AppCompatRoundedCorners { private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getLetterboxOverrides(); - return mIsLetterboxedNotForDisplayCutout.test(mainWindow) + return mRoundedCornersWindowCondition.test(mainWindow) && letterboxOverrides.isLetterboxActivityCornersRounded(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java index 018ea58e7120..d016e735f0c7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java @@ -151,6 +151,10 @@ class AppCompatActivityRobot { doReturn(taskBounds).when(mTaskStack.top()).getBounds(); } + void configureTaskAppBounds(@NonNull Rect appBounds) { + mTaskStack.top().getWindowConfiguration().setAppBounds(appBounds); + } + void configureTopActivityBounds(@NonNull Rect activityBounds) { doReturn(activityBounds).when(mActivityStack.top()).getBounds(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java index 0c310324ce67..2603d787ae37 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java @@ -16,7 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -27,6 +29,7 @@ import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; import android.graphics.Rect; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; @@ -40,6 +43,7 @@ import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import com.android.internal.R; +import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; @@ -225,6 +229,53 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { }); } + @Test + @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS) + public void testGetRoundedCornersRadius_letterboxBoundsMatchHeightInFreeform_notRounded() { + runTestScenario((robot) -> { + robot.conf().setLetterboxActivityCornersRadius(15); + robot.configureWindowState(); + robot.activity().createActivityWithComponent(); + robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false); + robot.activity().setTopActivityVisible(/* isVisible */ true); + robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true); + robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true); + robot.resources().configureGetDimensionPixelSize(R.dimen.taskbar_frame_height, 20); + + robot.activity().setTaskWindowingMode(WINDOWING_MODE_FREEFORM); + final Rect appBounds = new Rect(0, 0, 100, 500); + robot.configureWindowStateFrame(appBounds); + robot.activity().configureTaskAppBounds(appBounds); + + robot.startLetterbox(); + + robot.checkWindowStateRoundedCornersRadius(/* expected */ 0); + }); + } + + @Test + @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS) + public void testGetRoundedCornersRadius_letterboxBoundsNotMatchHeightInFreeform_rounded() { + runTestScenario((robot) -> { + robot.conf().setLetterboxActivityCornersRadius(15); + robot.configureWindowState(); + robot.activity().createActivityWithComponent(); + robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false); + robot.activity().setTopActivityVisible(/* isVisible */ true); + robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true); + robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true); + robot.resources().configureGetDimensionPixelSize(R.dimen.taskbar_frame_height, 20); + + robot.activity().setTaskWindowingMode(WINDOWING_MODE_FREEFORM); + robot.configureWindowStateFrame(new Rect(0, 0, 500, 200)); + robot.activity().configureTaskAppBounds(new Rect(0, 0, 500, 500)); + + robot.startLetterbox(); + + robot.checkWindowStateRoundedCornersRadius(/* expected */ 15); + }); + } + /** * Runs a test scenario providing a Robot. */ @@ -265,6 +316,10 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { spyOn(getTransparentPolicy()); } + void startLetterbox() { + getAppCompatLetterboxPolicy().start(mWindowState); + } + void configureWindowStateWithTaskBar(boolean hasInsetsRoundedCorners) { configureWindowState(/* withTaskBar */ true, hasInsetsRoundedCorners); } @@ -273,6 +328,10 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { configureWindowState(/* withTaskBar */ false, /* hasInsetsRoundedCorners */ false); } + void configureWindowStateFrame(@NonNull Rect frame) { + doReturn(frame).when(mWindowState).getFrame(); + } + void configureInsetsRoundedCorners(@NonNull RoundedCorners roundedCorners) { mInsetsState.setRoundedCorners(roundedCorners); } @@ -290,6 +349,7 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { } mWindowState.mInvGlobalScale = 1f; final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(); + attrs.type = TYPE_BASE_APPLICATION; doReturn(mInsetsState).when(mWindowState).getInsetsState(); doReturn(attrs).when(mWindowState).getAttrs(); doReturn(true).when(mWindowState).isDrawn(); |