Loading services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +45 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.wm; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.LaunchParamsModifierUtils.applyLayoutGravity; import static com.android.server.wm.LaunchParamsModifierUtils.calculateLayoutBounds; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -26,7 +28,9 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.SystemProperties; import android.util.Size; import android.util.Slog; import android.view.Gravity; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -119,10 +123,37 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } // Use stable frame instead of raw frame to avoid launching freeform windows on top of // stable insets, which usually are system widgets such as sysbar & navbar. final Rect stableBounds = new Rect(); task.getDisplayArea().getStableRect(stableBounds); final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); if (options != null && options.getLaunchBounds() != null) { outParams.mBounds.set(options.getLaunchBounds()); appendLog("inherit-from-options=" + outParams.mBounds); } else if (layout != null) { final int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK; final int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (layout.hasSpecifiedSize()) { calculateLayoutBounds(stableBounds, layout, outParams.mBounds, new Size(desiredWidth, desiredHeight)); applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds, stableBounds); appendLog("layout specifies sizes, inheriting size and applying gravity"); } else if (verticalGravity > 0 || horizontalGravity > 0) { calculateAndCentreInitialBounds(task, outParams); applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds, stableBounds); appendLog("layout specifies gravity, applying desired bounds and gravity"); } } else { calculateAndCentreInitialBounds(task, outParams); appendLog("layout not specified, applying desired bounds"); } appendLog("setting desktop mode task bounds to %s", outParams.mBounds); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); return RESULT_CONTINUE; } Loading @@ -133,13 +164,17 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { private void calculateAndCentreInitialBounds(Task task, LaunchParamsController.LaunchParams outParams) { // TODO(b/319819547): Account for app constraints so apps do not become letterboxed final Rect windowBounds = task.getDisplayArea().getBounds(); final int width = (int) (windowBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int height = (int) (windowBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); outParams.mBounds.right = width; outParams.mBounds.bottom = height; outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(), windowBounds.centerY() - outParams.mBounds.centerY()); final Rect stableBounds = new Rect(); task.getDisplayArea().getStableRect(stableBounds); // The desired dimensions that a fully resizable window should take when initially entering // desktop mode. Calculated as a percentage of the available display area as defined by the // DESKTOP_MODE_INITIAL_BOUNDS_SCALE. final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); outParams.mBounds.right = desiredWidth; outParams.mBounds.bottom = desiredHeight; outParams.mBounds.offset(stableBounds.centerX() - outParams.mBounds.centerX(), stableBounds.centerY() - outParams.mBounds.centerY()); } private void initLogBuilder(Task task, ActivityRecord activity) { Loading services/core/java/com/android/server/wm/LaunchParamsModifierUtils.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.util.Size; import android.view.Gravity; class LaunchParamsModifierUtils { /** * Calculates bounds based on window layout size manifest values. These can include width, * height, width fraction and height fraction. In the event only one dimension of values are * specified in the manifest (e.g. width but no height value), the corresponding display area * dimension will be used as the default value unless some desired sizes have been specified. */ static void calculateLayoutBounds(@NonNull Rect stableBounds, @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect inOutBounds, @Nullable Size desiredSize) { final int defaultWidth = stableBounds.width(); final int defaultHeight = stableBounds.height(); int width; int height; if (desiredSize == null) { // If desired bounds have not been specified, use the exiting default bounds as the // desired. desiredSize = new Size(stableBounds.width(), stableBounds.height()); } width = desiredSize.getWidth(); if (windowLayout.width > 0 && windowLayout.width < defaultWidth) { width = windowLayout.width; } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) { width = (int) (defaultWidth * windowLayout.widthFraction); } height = desiredSize.getHeight(); if (windowLayout.height > 0 && windowLayout.height < defaultHeight) { height = windowLayout.height; } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) { height = (int) (defaultHeight * windowLayout.heightFraction); } inOutBounds.set(0, 0, width, height); } /** * Applies a vertical and horizontal gravity on the inOutBounds in relation to the stableBounds. */ static void applyLayoutGravity(int verticalGravity, int horizontalGravity, @NonNull Rect inOutBounds, @NonNull Rect stableBounds) { final int width = inOutBounds.width(); final int height = inOutBounds.height(); final float fractionOfHorizontalOffset; switch (horizontalGravity) { case Gravity.LEFT: fractionOfHorizontalOffset = 0f; break; case Gravity.RIGHT: fractionOfHorizontalOffset = 1f; break; default: fractionOfHorizontalOffset = 0.5f; } final float fractionOfVerticalOffset; switch (verticalGravity) { case Gravity.TOP: fractionOfVerticalOffset = 0f; break; case Gravity.BOTTOM: fractionOfVerticalOffset = 1f; break; default: fractionOfVerticalOffset = 0.5f; } inOutBounds.offsetTo(stableBounds.left, stableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (stableBounds.width() - width)); final int yOffset = (int) (fractionOfVerticalOffset * (stableBounds.height() - height)); inOutBounds.offset(xOffset, yOffset); } } services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +10 −60 Original line number Diff line number Diff line Loading @@ -40,6 +40,8 @@ import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import static com.android.server.wm.ActivityStarter.Request; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.LaunchParamsModifierUtils.applyLayoutGravity; import static com.android.server.wm.LaunchParamsModifierUtils.calculateLayoutBounds; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -640,68 +642,16 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // stable insets, which usually are system widgets such as sysbar & navbar. final Rect stableBounds = mTmpStableBounds; displayArea.getStableRect(stableBounds); final int defaultWidth = stableBounds.width(); final int defaultHeight = stableBounds.height(); int width; int height; if (!windowLayout.hasSpecifiedSize()) { if (!inOutBounds.isEmpty()) { // If the bounds is resolved already and WindowLayout doesn't have any opinion on // its size, use the already resolved size and apply the gravity to it. width = inOutBounds.width(); height = inOutBounds.height(); } else { if (windowLayout.hasSpecifiedSize()) { calculateLayoutBounds(stableBounds, windowLayout, inOutBounds, /* desiredBounds */ null); } else if (inOutBounds.isEmpty()) { getTaskBounds(root, displayArea, windowLayout, WINDOWING_MODE_FREEFORM, /* hasInitialBounds */ false, inOutBounds); width = inOutBounds.width(); height = inOutBounds.height(); } } else { width = defaultWidth; if (windowLayout.width > 0 && windowLayout.width < defaultWidth) { width = windowLayout.width; } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) { width = (int) (width * windowLayout.widthFraction); } height = defaultHeight; if (windowLayout.height > 0 && windowLayout.height < defaultHeight) { height = windowLayout.height; } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) { height = (int) (height * windowLayout.heightFraction); } } final float fractionOfHorizontalOffset; switch (horizontalGravity) { case Gravity.LEFT: fractionOfHorizontalOffset = 0f; break; case Gravity.RIGHT: fractionOfHorizontalOffset = 1f; break; default: fractionOfHorizontalOffset = 0.5f; } final float fractionOfVerticalOffset; switch (verticalGravity) { case Gravity.TOP: fractionOfVerticalOffset = 0f; break; case Gravity.BOTTOM: fractionOfVerticalOffset = 1f; break; default: fractionOfVerticalOffset = 0.5f; } inOutBounds.set(0, 0, width, height); inOutBounds.offset(stableBounds.left, stableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width)); final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height)); inOutBounds.offset(xOffset, yOffset); applyLayoutGravity(verticalGravity, horizontalGravity, inOutBounds, stableBounds); } private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity, Loading services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java +245 −46 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/wmtests/src/com/android/server/wm/LaunchParamsModifierTestsBase.java 0 → 100644 +206 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import android.app.ActivityOptions; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.view.Gravity; import android.view.InsetsSource; import android.view.InsetsState; import android.view.WindowInsets; import com.android.server.wm.LaunchParamsController.LaunchParams; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; /** Common base class for launch param modifier unit test classes. */ public class LaunchParamsModifierTestsBase extends WindowTestsBase{ static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080); static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100, /* top */ 200, /* right */ 1620, /* bottom */ 680); ActivityRecord mActivity; LaunchParamsModifier mTarget; LaunchParams mCurrent; LaunchParams mResult; TestDisplayContent createNewDisplayContent(int windowingMode) { return createNewDisplayContent(windowingMode, DISPLAY_BOUNDS, DISPLAY_STABLE_BOUNDS); } TestDisplayContent createNewDisplayContent(int windowingMode, Rect displayBounds, Rect displayStableBounds) { final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); display.getDefaultTaskDisplayArea().setWindowingMode(windowingMode); display.setBounds(displayBounds); display.getConfiguration().densityDpi = DENSITY_DEFAULT; display.getConfiguration().orientation = ORIENTATION_LANDSCAPE; configInsetsState(display.getInsetsStateController().getRawInsetsState(), display, displayStableBounds); return display; } /** * Creates insets sources so that we can get the expected stable frame. */ static void configInsetsState(InsetsState state, DisplayContent display, Rect stableFrame) { final Rect displayFrame = display.getBounds(); final int dl = displayFrame.left; final int dt = displayFrame.top; final int dr = displayFrame.right; final int db = displayFrame.bottom; final int sl = stableFrame.left; final int st = stableFrame.top; final int sr = stableFrame.right; final int sb = stableFrame.bottom; final @WindowInsets.Type.InsetsType int statusBarType = WindowInsets.Type.statusBars(); final @WindowInsets.Type.InsetsType int navBarType = WindowInsets.Type.navigationBars(); state.setDisplayFrame(displayFrame); if (sl > dl) { state.getOrCreateSource(InsetsSource.createId(null, 0, statusBarType), statusBarType) .setFrame(dl, dt, sl, db); } if (st > dt) { state.getOrCreateSource(InsetsSource.createId(null, 1, statusBarType), statusBarType) .setFrame(dl, dt, dr, st); } if (sr < dr) { state.getOrCreateSource(InsetsSource.createId(null, 0, navBarType), navBarType) .setFrame(sr, dt, dr, db); } if (sb < db) { state.getOrCreateSource(InsetsSource.createId(null, 1, navBarType), navBarType) .setFrame(dl, sb, dr, db); } // Recompute config and push to children. display.onRequestedOverrideConfigurationChanged(display.getConfiguration()); } class CalculateRequestBuilder { private Task mTask; private ActivityInfo.WindowLayout mLayout; private ActivityRecord mActivity = LaunchParamsModifierTestsBase.this.mActivity; private ActivityRecord mSource; private ActivityOptions mOptions; private ActivityStarter.Request mRequest; private int mPhase = PHASE_BOUNDS; private LaunchParams mCurrentParams = mCurrent; private LaunchParams mOutParams = mResult; CalculateRequestBuilder setTask(Task task) { mTask = task; return this; } CalculateRequestBuilder setLayout(ActivityInfo.WindowLayout layout) { mLayout = layout; return this; } CalculateRequestBuilder setPhase(int phase) { mPhase = phase; return this; } CalculateRequestBuilder setActivity(ActivityRecord activity) { mActivity = activity; return this; } CalculateRequestBuilder setSource(ActivityRecord source) { mSource = source; return this; } CalculateRequestBuilder setOptions(ActivityOptions options) { mOptions = options; return this; } CalculateRequestBuilder setRequest(ActivityStarter.Request request) { mRequest = request; return this; } @LaunchParamsController.LaunchParamsModifier.Result int calculate() { return mTarget.onCalculate(mTask, mLayout, mActivity, mSource, mOptions, mRequest, mPhase, mCurrentParams, mOutParams); } } static class WindowLayoutBuilder { private int mWidth = -1; private int mHeight = -1; private float mWidthFraction = -1f; private float mHeightFraction = -1f; private int mGravity = Gravity.NO_GRAVITY; private int mMinWidth = -1; private int mMinHeight = -1; WindowLayoutBuilder setWidth(int width) { mWidth = width; return this; } WindowLayoutBuilder setHeight(int height) { mHeight = height; return this; } WindowLayoutBuilder setWidthFraction(float widthFraction) { mWidthFraction = widthFraction; return this; } WindowLayoutBuilder setHeightFraction(float heightFraction) { mHeightFraction = heightFraction; return this; } WindowLayoutBuilder setGravity(int gravity) { mGravity = gravity; return this; } WindowLayoutBuilder setMinWidth(int minWidth) { mMinWidth = minWidth; return this; } WindowLayoutBuilder setMinHeight(int minHeight) { mMinHeight = minHeight; return this; } ActivityInfo.WindowLayout build() { return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction, mGravity, mMinWidth, mMinHeight); } } } Loading
services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +45 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.wm; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.LaunchParamsModifierUtils.applyLayoutGravity; import static com.android.server.wm.LaunchParamsModifierUtils.calculateLayoutBounds; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -26,7 +28,9 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.os.SystemProperties; import android.util.Size; import android.util.Slog; import android.view.Gravity; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -119,10 +123,37 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } // Use stable frame instead of raw frame to avoid launching freeform windows on top of // stable insets, which usually are system widgets such as sysbar & navbar. final Rect stableBounds = new Rect(); task.getDisplayArea().getStableRect(stableBounds); final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); if (options != null && options.getLaunchBounds() != null) { outParams.mBounds.set(options.getLaunchBounds()); appendLog("inherit-from-options=" + outParams.mBounds); } else if (layout != null) { final int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK; final int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; if (layout.hasSpecifiedSize()) { calculateLayoutBounds(stableBounds, layout, outParams.mBounds, new Size(desiredWidth, desiredHeight)); applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds, stableBounds); appendLog("layout specifies sizes, inheriting size and applying gravity"); } else if (verticalGravity > 0 || horizontalGravity > 0) { calculateAndCentreInitialBounds(task, outParams); applyLayoutGravity(verticalGravity, horizontalGravity, outParams.mBounds, stableBounds); appendLog("layout specifies gravity, applying desired bounds and gravity"); } } else { calculateAndCentreInitialBounds(task, outParams); appendLog("layout not specified, applying desired bounds"); } appendLog("setting desktop mode task bounds to %s", outParams.mBounds); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); return RESULT_CONTINUE; } Loading @@ -133,13 +164,17 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { private void calculateAndCentreInitialBounds(Task task, LaunchParamsController.LaunchParams outParams) { // TODO(b/319819547): Account for app constraints so apps do not become letterboxed final Rect windowBounds = task.getDisplayArea().getBounds(); final int width = (int) (windowBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int height = (int) (windowBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); outParams.mBounds.right = width; outParams.mBounds.bottom = height; outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(), windowBounds.centerY() - outParams.mBounds.centerY()); final Rect stableBounds = new Rect(); task.getDisplayArea().getStableRect(stableBounds); // The desired dimensions that a fully resizable window should take when initially entering // desktop mode. Calculated as a percentage of the available display area as defined by the // DESKTOP_MODE_INITIAL_BOUNDS_SCALE. final int desiredWidth = (int) (stableBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); final int desiredHeight = (int) (stableBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); outParams.mBounds.right = desiredWidth; outParams.mBounds.bottom = desiredHeight; outParams.mBounds.offset(stableBounds.centerX() - outParams.mBounds.centerX(), stableBounds.centerY() - outParams.mBounds.centerY()); } private void initLogBuilder(Task task, ActivityRecord activity) { Loading
services/core/java/com/android/server/wm/LaunchParamsModifierUtils.java 0 → 100644 +102 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.util.Size; import android.view.Gravity; class LaunchParamsModifierUtils { /** * Calculates bounds based on window layout size manifest values. These can include width, * height, width fraction and height fraction. In the event only one dimension of values are * specified in the manifest (e.g. width but no height value), the corresponding display area * dimension will be used as the default value unless some desired sizes have been specified. */ static void calculateLayoutBounds(@NonNull Rect stableBounds, @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect inOutBounds, @Nullable Size desiredSize) { final int defaultWidth = stableBounds.width(); final int defaultHeight = stableBounds.height(); int width; int height; if (desiredSize == null) { // If desired bounds have not been specified, use the exiting default bounds as the // desired. desiredSize = new Size(stableBounds.width(), stableBounds.height()); } width = desiredSize.getWidth(); if (windowLayout.width > 0 && windowLayout.width < defaultWidth) { width = windowLayout.width; } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) { width = (int) (defaultWidth * windowLayout.widthFraction); } height = desiredSize.getHeight(); if (windowLayout.height > 0 && windowLayout.height < defaultHeight) { height = windowLayout.height; } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) { height = (int) (defaultHeight * windowLayout.heightFraction); } inOutBounds.set(0, 0, width, height); } /** * Applies a vertical and horizontal gravity on the inOutBounds in relation to the stableBounds. */ static void applyLayoutGravity(int verticalGravity, int horizontalGravity, @NonNull Rect inOutBounds, @NonNull Rect stableBounds) { final int width = inOutBounds.width(); final int height = inOutBounds.height(); final float fractionOfHorizontalOffset; switch (horizontalGravity) { case Gravity.LEFT: fractionOfHorizontalOffset = 0f; break; case Gravity.RIGHT: fractionOfHorizontalOffset = 1f; break; default: fractionOfHorizontalOffset = 0.5f; } final float fractionOfVerticalOffset; switch (verticalGravity) { case Gravity.TOP: fractionOfVerticalOffset = 0f; break; case Gravity.BOTTOM: fractionOfVerticalOffset = 1f; break; default: fractionOfVerticalOffset = 0.5f; } inOutBounds.offsetTo(stableBounds.left, stableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (stableBounds.width() - width)); final int yOffset = (int) (fractionOfVerticalOffset * (stableBounds.height() - height)); inOutBounds.offset(xOffset, yOffset); } }
services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +10 −60 Original line number Diff line number Diff line Loading @@ -40,6 +40,8 @@ import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import static com.android.server.wm.ActivityStarter.Request; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.LaunchParamsModifierUtils.applyLayoutGravity; import static com.android.server.wm.LaunchParamsModifierUtils.calculateLayoutBounds; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -640,68 +642,16 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // stable insets, which usually are system widgets such as sysbar & navbar. final Rect stableBounds = mTmpStableBounds; displayArea.getStableRect(stableBounds); final int defaultWidth = stableBounds.width(); final int defaultHeight = stableBounds.height(); int width; int height; if (!windowLayout.hasSpecifiedSize()) { if (!inOutBounds.isEmpty()) { // If the bounds is resolved already and WindowLayout doesn't have any opinion on // its size, use the already resolved size and apply the gravity to it. width = inOutBounds.width(); height = inOutBounds.height(); } else { if (windowLayout.hasSpecifiedSize()) { calculateLayoutBounds(stableBounds, windowLayout, inOutBounds, /* desiredBounds */ null); } else if (inOutBounds.isEmpty()) { getTaskBounds(root, displayArea, windowLayout, WINDOWING_MODE_FREEFORM, /* hasInitialBounds */ false, inOutBounds); width = inOutBounds.width(); height = inOutBounds.height(); } } else { width = defaultWidth; if (windowLayout.width > 0 && windowLayout.width < defaultWidth) { width = windowLayout.width; } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) { width = (int) (width * windowLayout.widthFraction); } height = defaultHeight; if (windowLayout.height > 0 && windowLayout.height < defaultHeight) { height = windowLayout.height; } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) { height = (int) (height * windowLayout.heightFraction); } } final float fractionOfHorizontalOffset; switch (horizontalGravity) { case Gravity.LEFT: fractionOfHorizontalOffset = 0f; break; case Gravity.RIGHT: fractionOfHorizontalOffset = 1f; break; default: fractionOfHorizontalOffset = 0.5f; } final float fractionOfVerticalOffset; switch (verticalGravity) { case Gravity.TOP: fractionOfVerticalOffset = 0f; break; case Gravity.BOTTOM: fractionOfVerticalOffset = 1f; break; default: fractionOfVerticalOffset = 0.5f; } inOutBounds.set(0, 0, width, height); inOutBounds.offset(stableBounds.left, stableBounds.top); final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width)); final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height)); inOutBounds.offset(xOffset, yOffset); applyLayoutGravity(verticalGravity, horizontalGravity, inOutBounds, stableBounds); } private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity, Loading
services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java +245 −46 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/wmtests/src/com/android/server/wm/LaunchParamsModifierTestsBase.java 0 → 100644 +206 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wm; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.util.DisplayMetrics.DENSITY_DEFAULT; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import android.app.ActivityOptions; import android.content.pm.ActivityInfo; import android.graphics.Rect; import android.view.Gravity; import android.view.InsetsSource; import android.view.InsetsState; import android.view.WindowInsets; import com.android.server.wm.LaunchParamsController.LaunchParams; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; /** Common base class for launch param modifier unit test classes. */ public class LaunchParamsModifierTestsBase extends WindowTestsBase{ static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080); static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100, /* top */ 200, /* right */ 1620, /* bottom */ 680); ActivityRecord mActivity; LaunchParamsModifier mTarget; LaunchParams mCurrent; LaunchParams mResult; TestDisplayContent createNewDisplayContent(int windowingMode) { return createNewDisplayContent(windowingMode, DISPLAY_BOUNDS, DISPLAY_STABLE_BOUNDS); } TestDisplayContent createNewDisplayContent(int windowingMode, Rect displayBounds, Rect displayStableBounds) { final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); display.getDefaultTaskDisplayArea().setWindowingMode(windowingMode); display.setBounds(displayBounds); display.getConfiguration().densityDpi = DENSITY_DEFAULT; display.getConfiguration().orientation = ORIENTATION_LANDSCAPE; configInsetsState(display.getInsetsStateController().getRawInsetsState(), display, displayStableBounds); return display; } /** * Creates insets sources so that we can get the expected stable frame. */ static void configInsetsState(InsetsState state, DisplayContent display, Rect stableFrame) { final Rect displayFrame = display.getBounds(); final int dl = displayFrame.left; final int dt = displayFrame.top; final int dr = displayFrame.right; final int db = displayFrame.bottom; final int sl = stableFrame.left; final int st = stableFrame.top; final int sr = stableFrame.right; final int sb = stableFrame.bottom; final @WindowInsets.Type.InsetsType int statusBarType = WindowInsets.Type.statusBars(); final @WindowInsets.Type.InsetsType int navBarType = WindowInsets.Type.navigationBars(); state.setDisplayFrame(displayFrame); if (sl > dl) { state.getOrCreateSource(InsetsSource.createId(null, 0, statusBarType), statusBarType) .setFrame(dl, dt, sl, db); } if (st > dt) { state.getOrCreateSource(InsetsSource.createId(null, 1, statusBarType), statusBarType) .setFrame(dl, dt, dr, st); } if (sr < dr) { state.getOrCreateSource(InsetsSource.createId(null, 0, navBarType), navBarType) .setFrame(sr, dt, dr, db); } if (sb < db) { state.getOrCreateSource(InsetsSource.createId(null, 1, navBarType), navBarType) .setFrame(dl, sb, dr, db); } // Recompute config and push to children. display.onRequestedOverrideConfigurationChanged(display.getConfiguration()); } class CalculateRequestBuilder { private Task mTask; private ActivityInfo.WindowLayout mLayout; private ActivityRecord mActivity = LaunchParamsModifierTestsBase.this.mActivity; private ActivityRecord mSource; private ActivityOptions mOptions; private ActivityStarter.Request mRequest; private int mPhase = PHASE_BOUNDS; private LaunchParams mCurrentParams = mCurrent; private LaunchParams mOutParams = mResult; CalculateRequestBuilder setTask(Task task) { mTask = task; return this; } CalculateRequestBuilder setLayout(ActivityInfo.WindowLayout layout) { mLayout = layout; return this; } CalculateRequestBuilder setPhase(int phase) { mPhase = phase; return this; } CalculateRequestBuilder setActivity(ActivityRecord activity) { mActivity = activity; return this; } CalculateRequestBuilder setSource(ActivityRecord source) { mSource = source; return this; } CalculateRequestBuilder setOptions(ActivityOptions options) { mOptions = options; return this; } CalculateRequestBuilder setRequest(ActivityStarter.Request request) { mRequest = request; return this; } @LaunchParamsController.LaunchParamsModifier.Result int calculate() { return mTarget.onCalculate(mTask, mLayout, mActivity, mSource, mOptions, mRequest, mPhase, mCurrentParams, mOutParams); } } static class WindowLayoutBuilder { private int mWidth = -1; private int mHeight = -1; private float mWidthFraction = -1f; private float mHeightFraction = -1f; private int mGravity = Gravity.NO_GRAVITY; private int mMinWidth = -1; private int mMinHeight = -1; WindowLayoutBuilder setWidth(int width) { mWidth = width; return this; } WindowLayoutBuilder setHeight(int height) { mHeight = height; return this; } WindowLayoutBuilder setWidthFraction(float widthFraction) { mWidthFraction = widthFraction; return this; } WindowLayoutBuilder setHeightFraction(float heightFraction) { mHeightFraction = heightFraction; return this; } WindowLayoutBuilder setGravity(int gravity) { mGravity = gravity; return this; } WindowLayoutBuilder setMinWidth(int minWidth) { mMinWidth = minWidth; return this; } WindowLayoutBuilder setMinHeight(int minHeight) { mMinHeight = minHeight; return this; } ActivityInfo.WindowLayout build() { return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction, mGravity, mMinWidth, mMinHeight); } } }