diff options
| author | 2025-02-27 03:24:47 -0800 | |
|---|---|---|
| committer | 2025-02-27 03:24:47 -0800 | |
| commit | 40aa32b37c5db1e6f9e4f7277b7c39a02ede32a9 (patch) | |
| tree | 14164912d7eb721e5ef9b4832b1dafd1fc4021b7 | |
| parent | 71f32e71ab67b7a971bcd81a79c3655e2bbe61e9 (diff) | |
| parent | 3e4cf0cfef4b7b25e4d4ec36309cb93a9ae0a846 (diff) | |
Merge changes Ib0099b0f,I4c4de052 into main
* changes:
[1/n] Enforce Shell desktop cascading in Launch Params
[0/n] Create bug fix flag for Shell initial bounds regression
7 files changed, 246 insertions, 9 deletions
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index b8c20bd97264..cc3745675bc9 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -488,6 +488,8 @@ public class ActivityOptions extends ComponentOptions { private static final String KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE = "android.activity.allowPassThroughOnTouchOutside"; + private static final String KEY_FLEXIBLE_LAUNCH_SIZE = "android.activity.flexibleLaunchSize"; + /** * @see #setLaunchCookie * @hide @@ -588,6 +590,7 @@ public class ActivityOptions extends ComponentOptions { @BackgroundActivityStartMode private int mPendingIntentCreatorBackgroundActivityStartMode = MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; + private boolean mFlexibleLaunchSize = false; private boolean mDisableStartingWindow; private boolean mAllowPassThroughOnTouchOutside; @@ -1451,6 +1454,7 @@ public class ActivityOptions extends ComponentOptions { mPendingIntentCreatorBackgroundActivityStartMode = opts.getInt( KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED); + mFlexibleLaunchSize = opts.getBoolean(KEY_FLEXIBLE_LAUNCH_SIZE, /* defaultValue = */ false); mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW); mAllowPassThroughOnTouchOutside = opts.getBoolean(KEY_ALLOW_PASS_THROUGH_ON_TOUCH_OUTSIDE); mAnimationAbortListener = IRemoteCallback.Stub.asInterface( @@ -2346,6 +2350,24 @@ public class ActivityOptions extends ComponentOptions { } /** + * Sets whether the size of the launch bounds is flexible, meaning it can be overridden to a + * different size during the launch params calculation. + * @hide + */ + public ActivityOptions setFlexibleLaunchSize(boolean isFlexible) { + mFlexibleLaunchSize = isFlexible; + return this; + } + + /** + * Gets whether the size of the launch bounds is flexible. + * @hide + */ + public boolean getFlexibleLaunchSize() { + return mFlexibleLaunchSize; + } + + /** * Update the current values in this ActivityOptions from those supplied * in <var>otherOptions</var>. Any values * defined in <var>otherOptions</var> replace those in the base options. @@ -2601,6 +2623,9 @@ public class ActivityOptions extends ComponentOptions { b.putInt(KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE, mPendingIntentCreatorBackgroundActivityStartMode); } + if (mFlexibleLaunchSize) { + b.putBoolean(KEY_FLEXIBLE_LAUNCH_SIZE, mFlexibleLaunchSize); + } if (mDisableStartingWindow) { b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow); } diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index 3cdf29084a46..696b7b8bb965 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -114,6 +114,8 @@ public enum DesktopModeFlags { ENABLE_RESIZING_METRICS(Flags::enableResizingMetrics, true), ENABLE_RESTORE_TO_PREVIOUS_SIZE_FROM_DESKTOP_IMMERSIVE( Flags::enableRestoreToPreviousSizeFromDesktopImmersive, true), + ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX( + Flags::enableShellInitialBoundsRegressionBugFix, false), ENABLE_START_LAUNCH_TRANSITION_FROM_TASKBAR_BUGFIX( Flags::enableStartLaunchTransitionFromTaskbarBugfix, true), ENABLE_TASKBAR_OVERFLOW(Flags::enableTaskbarOverflow, false), diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 355a87d72203..09f458be9bfa 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -38,6 +38,18 @@ flag { } flag { + name: "enable_shell_initial_bounds_regression_bug_fix" + namespace: "lse_desktop_experience" + description: "Enables fix for Shell initial bounds regression, forcing core to calculate /n" + "initial bounds in desktop launch params while respecting cascading position /n" + "passed by Shell." + bug: "396075922" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_windowing_dynamic_initial_bounds" namespace: "lse_desktop_experience" description: "Enables new initial bounds for desktop windowing which adjust depending on app constraints" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 7e6325019ab1..5de3be4bbfc0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -1246,6 +1246,10 @@ class DesktopTasksController( pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS launchBounds = bounds + if (DesktopModeFlags.ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX.isTrue) { + // Sets launch bounds size as flexible so core can recalculate. + flexibleLaunchSize = true + } } wct.sendPendingIntent(pendingIntent, intent, ops.toBundle()) diff --git a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java index 0106a64660fe..7a959c14fbd2 100644 --- a/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java +++ b/services/core/java/com/android/server/wm/DesktopModeBoundsCalculator.java @@ -52,6 +52,13 @@ public final class DesktopModeBoundsCalculator { .getInt("persist.wm.debug.desktop_mode_landscape_app_padding", 25); /** + * Proportion of window height top offset with respect to bottom offset, used for central task + * positioning. Should be kept in sync with constant in + * {@link com.android.wm.shell.desktopmode.DesktopTaskPosition} + */ + public static final float WINDOW_HEIGHT_PROPORTION = 0.375f; + + /** * Updates launch bounds for an activity with respect to its activity options, window layout, * android manifest and task configuration. */ @@ -63,7 +70,16 @@ public final class DesktopModeBoundsCalculator { final Rect stableBounds = new Rect(); task.getDisplayArea().getStableRect(stableBounds); - if (options != null && options.getLaunchBounds() != null) { + // If the options bounds size is flexible, update size with calculated desired size. + final boolean updateOptionBoundsSize = options != null + && options.getFlexibleLaunchSize(); + // If cascading is also enabled, the position of the options bounds must be respected + // during the size update. + final boolean shouldRespectOptionPosition = + updateOptionBoundsSize && DesktopModeFlags.ENABLE_CASCADING_WINDOWS.isTrue(); + + if (options != null && options.getLaunchBounds() != null + && !updateOptionBoundsSize) { outBounds.set(options.getLaunchBounds()); logger.accept("inherit-from-options=" + outBounds); } else if (layout != null) { @@ -76,26 +92,34 @@ public final class DesktopModeBoundsCalculator { stableBounds); logger.accept("layout specifies sizes, inheriting size and applying gravity"); } else if (verticalGravity > 0 || horizontalGravity > 0) { - outBounds.set(calculateInitialBounds(task, activity, stableBounds)); + outBounds.set(calculateInitialBounds(task, activity, stableBounds, options, + shouldRespectOptionPosition)); applyLayoutGravity(verticalGravity, horizontalGravity, outBounds, stableBounds); logger.accept("layout specifies gravity, applying desired bounds and gravity"); + logger.accept("respecting option bounds cascaded position=" + + shouldRespectOptionPosition); } } else { - outBounds.set(calculateInitialBounds(task, activity, stableBounds)); + outBounds.set(calculateInitialBounds(task, activity, stableBounds, options, + shouldRespectOptionPosition)); logger.accept("layout not specified, applying desired bounds"); + logger.accept("respecting option bounds cascaded position=" + + shouldRespectOptionPosition); } } /** * Calculates the initial bounds required for an application to fill a scale of the display * bounds without any letterboxing. This is done by taking into account the applications - * fullscreen size, aspect ratio, orientation and resizability to calculate an area this is - * compatible with the applications previous configuration. + * fullscreen size, aspect ratio, orientation and resizability to calculate an area that is + * compatible with the applications previous configuration. These bounds are then cascaded to + * either the center or to a cascading position supplied by Shell via the option bounds. */ @NonNull private static Rect calculateInitialBounds(@NonNull Task task, - @NonNull ActivityRecord activity, @NonNull Rect stableBounds + @NonNull ActivityRecord activity, @NonNull Rect stableBounds, + @Nullable ActivityOptions options, boolean shouldRespectOptionPosition ) { // Display bounds not taking into account insets. final TaskDisplayArea displayArea = task.getDisplayArea(); @@ -172,6 +196,9 @@ public final class DesktopModeBoundsCalculator { } default -> idealSize; }; + if (shouldRespectOptionPosition) { + return respectShellCascading(initialSize, stableBounds, options.getLaunchBounds()); + } return centerInScreen(initialSize, screenBounds); } @@ -266,14 +293,65 @@ public final class DesktopModeBoundsCalculator { * Adjusts bounds to be positioned in the middle of the screen. */ @NonNull - private static Rect centerInScreen(@NonNull Size desiredSize, + static Rect centerInScreen(@NonNull Size desiredSize, @NonNull Rect screenBounds) { - // TODO(b/325240051): Position apps with bottom heavy offset - final int heightOffset = (screenBounds.height() - desiredSize.getHeight()) / 2; + final int heightOffset = (int) + ((screenBounds.height() - desiredSize.getHeight()) * WINDOW_HEIGHT_PROPORTION); final int widthOffset = (screenBounds.width() - desiredSize.getWidth()) / 2; final Rect resultBounds = new Rect(0, 0, desiredSize.getWidth(), desiredSize.getHeight()); resultBounds.offset(screenBounds.left + widthOffset, screenBounds.top + heightOffset); return resultBounds; } + + /** + * Calculates final initial bounds based on the task's desired size and the cascading anchor + * point extracted from the option bounds. Cascading behaviour should be kept in sync with + * logic in {@link com.android.wm.shell.desktopmode.DesktopTaskPosition}. + */ + @NonNull + private static Rect respectShellCascading(@NonNull Size desiredSize, @NonNull Rect stableBounds, + @NonNull Rect optionBounds) { + final boolean leftAligned = stableBounds.left == optionBounds.left; + final boolean rightAligned = stableBounds.right == optionBounds.right; + final boolean topAligned = stableBounds.top == optionBounds.top; + final boolean bottomAligned = stableBounds.bottom == optionBounds.bottom; + if (leftAligned && topAligned) { + // Bounds cascaded to top left, respect top left position anchor point. + return new Rect( + optionBounds.left, + optionBounds.top, + optionBounds.left + desiredSize.getWidth(), + optionBounds.top + desiredSize.getHeight() + ); + } + if (leftAligned && bottomAligned) { + // Bounds cascaded to bottom left, respect bottom left position anchor point. + return new Rect( + optionBounds.left, + optionBounds.bottom - desiredSize.getHeight(), + optionBounds.left + desiredSize.getWidth(), + optionBounds.bottom + ); + } + if (rightAligned && topAligned) { + // Bounds cascaded to top right, respect top right position anchor point. + return new Rect( + optionBounds.right - desiredSize.getWidth(), + optionBounds.top, + optionBounds.right, + optionBounds.top + desiredSize.getHeight() + ); + } + if (rightAligned && bottomAligned) { + // Bounds cascaded to bottom right, respect bottom right position anchor point. + return new Rect( + optionBounds.right - desiredSize.getWidth(), + optionBounds.bottom - desiredSize.getHeight(), + optionBounds.right, + optionBounds.bottom); + } + // Bounds not cascaded to any corner, default to center position. + return centerInScreen(desiredSize, stableBounds); + } } diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java index a4eeb688162c..d466a646c7dd 100644 --- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java @@ -42,6 +42,7 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { private static final String TAG = TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM; + private static final boolean DEBUG = false; private StringBuilder mLogBuilder; @@ -133,6 +134,14 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options, outParams.mBounds, this::appendLog); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); + if (options != null && options.getFlexibleLaunchSize()) { + // Return result done to prevent other modifiers from respecting option bounds and + // applying further cascading. Since other modifiers are being skipped in this case, + // this modifier is now also responsible to respecting the options launch windowing + // mode. + outParams.mWindowingMode = options.getLaunchWindowingMode(); + return RESULT_DONE; + } return RESULT_CONTINUE; } diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java index 3a06fff1d1a7..bc37496d14a7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java @@ -42,8 +42,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; import static com.android.server.wm.DesktopModeBoundsCalculator.DESKTOP_MODE_LANDSCAPE_APP_PADDING; +import static com.android.server.wm.DesktopModeBoundsCalculator.centerInScreen; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; import static org.junit.Assert.assertEquals; @@ -60,6 +62,7 @@ import android.graphics.Rect; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.util.Size; import android.view.Gravity; import androidx.test.filters.SmallTest; @@ -1099,6 +1102,110 @@ public class DesktopModeLaunchParamsModifierTests extends } @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSize_windowingModeSet() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.top, + /* right = */ 500, + /* bottom = */ 500)) + .setFlexibleLaunchSize(true); + options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSize_boundsSizeModified() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.top, + /* right = */ 500, + /* bottom = */ 500)) + .setFlexibleLaunchSize(true); + final int modifiedWidth = + (int) (DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int modifiedHeight = + (int) (DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(modifiedWidth, mResult.mBounds.width()); + assertEquals(modifiedHeight, mResult.mBounds.height()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSizeWithCascading_cornerCascadeRespected() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + // Set launch bounds with corner cascade. + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + DISPLAY_STABLE_BOUNDS.left, + DISPLAY_STABLE_BOUNDS.top, + /* right = */ 500, + /* bottom = */ 500)) + .setFlexibleLaunchSize(true); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left); + assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_SHELL_INITIAL_BOUNDS_REGRESSION_BUG_FIX}) + public void testOptionsBoundsSet_flexibleLaunchSize_centerCascadeRespected() { + setupDesktopModeLaunchParamsModifier(); + + final TestDisplayContent display = createNewDisplayContent(WINDOWING_MODE_FULLSCREEN); + final Task task = new TaskBuilder(mSupervisor).setActivityType( + ACTIVITY_TYPE_STANDARD).setDisplay(display).build(); + // Set launch bounds with center cascade. + final ActivityOptions options = ActivityOptions.makeBasic() + .setLaunchBounds(new Rect( + /* left = */ 320, + /* top = */ 100, + /* right = */ 640, + /* bottom = */ 200)) + .setFlexibleLaunchSize(true); + final int modifiedWidth = + (int) (DISPLAY_BOUNDS.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int modifiedHeight = + (int) (DISPLAY_BOUNDS.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final Rect centerCascadedBounds = centerInScreen( + new Size(modifiedWidth, modifiedHeight), DISPLAY_STABLE_BOUNDS); + + assertEquals(RESULT_DONE, + new CalculateRequestBuilder().setTask(task).setOptions(options).calculate()); + assertEquals(centerCascadedBounds, mResult.mBounds); + assertEquals(centerCascadedBounds.top, mResult.mBounds.top); + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testNonEmptyLayoutBounds_CenterToDisplay() { setupDesktopModeLaunchParamsModifier(); |