summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Graciela Wissen Putri <gracielawputri@google.com> 2025-01-29 17:59:10 +0000
committer Graciela Wissen Putri <gracielawputri@google.com> 2025-02-14 10:27:06 +0000
commita59fd0c1d34cd392266a77a5ac3dc432885da964 (patch)
treeeec54a92c7c439baa2e26e0d2df830cf7b4c1167
parentcc245ac89a440014186a47e0cf975a78310f3266 (diff)
[5/n] Fix top rounded corners in freeform
If activity bounds match parent app bounds height, don't apply rounded corners. Freeform activities will not have visible letterboxing except if eligible for camera compat treatment. Pillarboxing for camera compat will not have rounded corners to ensure consistency between apps. Round up aspect ratio calculations in desktop mode to match activity aspect ratio calculations in core. Flag: com.android.window.flags.exclude_caption_from_app_bounds Bug: 388014743 Test: atest AppCompatLetterboxPolicyTest Change-Id: I5fbc8852c00771ffa228a5a635057eee201a4269
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt9
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt2
-rw-r--r--services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java38
-rw-r--r--services/core/java/com/android/server/wm/AppCompatRoundedCorners.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java60
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();