From f36089e8fc02e1f743da0ea3e9f27f43b7cd2f63 Mon Sep 17 00:00:00 2001 From: An An Yu Date: Tue, 16 Nov 2021 15:44:49 -0800 Subject: [PATCH] Allow DisplayContent to report per-Display minimal task size. Currently minimal task size is calculated from the default display in RootWindowContainer and used for all resizeable tasks; instead we should calculate this from per-Display context to extend for additional displays. Test: DisplayContentTests Bug: 191434136 Change-Id: Ib9397de5570c0b17651c4ccfcb30bee836f684e8 --- .../android/server/windowmanagerservice.proto | 4 +-- .../com/android/server/wm/DisplayContent.java | 24 ++++++++++++++- .../server/wm/RootWindowContainer.java | 21 -------------- .../core/java/com/android/server/wm/Task.java | 9 ++++-- .../server/wm/WindowManagerService.java | 3 +- .../server/wm/DisplayContentTests.java | 24 +++++++++++++++ .../android/server/wm/TestDisplayContent.java | 29 +++++++++++++++++++ .../android/server/wm/WindowTestsBase.java | 3 +- 8 files changed, 89 insertions(+), 28 deletions(-) diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 11560a5ccd1b3..5b2f7f0a5c327 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -69,7 +69,7 @@ message RootWindowContainerProto { // know what activity types to check for when invoking splitscreen multi-window. optional bool is_home_recents_component = 6; repeated IdentifierProto pending_activities = 7 [deprecated=true]; - optional int32 default_min_size_resizable_task = 8; + optional int32 default_min_size_resizable_task = 8 [deprecated=true]; } message BarControllerProto { @@ -226,7 +226,7 @@ message DisplayContentProto { optional bool is_sleeping = 36; repeated string sleep_tokens = 37; repeated .android.graphics.RectProto keep_clear_areas = 38; - + optional int32 min_size_of_resizeable_task_dp = 39; } /* represents DisplayArea object */ diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index e449dde15c67a..d73dfbcf66987 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -123,6 +123,7 @@ import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET; import static com.android.server.wm.DisplayContentProto.INSETS_SOURCE_PROVIDERS; import static com.android.server.wm.DisplayContentProto.IS_SLEEPING; import static com.android.server.wm.DisplayContentProto.KEEP_CLEAR_AREAS; +import static com.android.server.wm.DisplayContentProto.MIN_SIZE_OF_RESIZEABLE_TASK_DP; import static com.android.server.wm.DisplayContentProto.OPENING_APPS; import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY; import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA; @@ -323,6 +324,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ private Rect mLastMirroredDisplayAreaBounds = null; + /** + * The default per Display minimal size of tasks. Calculated at construction. + */ + int mMinSizeOfResizeableTaskDp = -1; + // Contains all IME window containers. Note that the z-ordering of the IME windows will depend // on the IME target. We mainly have this container grouping so we can keep track of all the IME // window containers together and move them in-sync if/when needed. We use a subclass of @@ -1098,7 +1104,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mInputMonitor = new InputMonitor(mWmService, this); mInsetsPolicy = new InsetsPolicy(mInsetsStateController, this); - + mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp(); if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display); mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this); @@ -1554,6 +1560,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return config; } + private int getMinimalTaskSizeDp() { + final Context displayConfigurationContext = + mAtmService.mContext.createConfigurationContext(getConfiguration()); + final float minimalSize = + displayConfigurationContext.getResources().getDimension( + com.android.internal.R.dimen.default_minimal_size_resizable_task); + if (Double.compare(mDisplayMetrics.density, 0.0) == 0) { + throw new IllegalArgumentException("Display with ID=" + getDisplayId() + "has invalid " + + "DisplayMetrics.density= 0.0"); + } + return (int) (minimalSize / mDisplayMetrics.density); + } + private boolean updateOrientation(boolean forceUpdate) { final int orientation = getOrientation(); // The last orientation source is valid only after getOrientation. @@ -2711,6 +2730,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // layout. mInsetsStateController.onDisplayInfoUpdated(false /* notifyInsetsChanged */); } + mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp(); mInputMonitor.layoutInputConsumers(info.logicalWidth, info.logicalHeight); mDisplayPolicy.onDisplayInfoChanged(info); } @@ -3272,6 +3292,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp screenRotationAnimation.dumpDebug(proto, SCREEN_ROTATION_ANIMATION); } mDisplayFrames.dumpDebug(proto, DISPLAY_FRAMES); + proto.write(MIN_SIZE_OF_RESIZEABLE_TASK_DP, mMinSizeOfResizeableTaskDp); if (mTransitionController.isShellTransitionsEnabled()) { mTransitionController.dumpDebugLegacy(proto, APP_TRANSITION); } else { @@ -3349,6 +3370,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x"); pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity); pw.print("dpi"); + pw.print(" mMinSizeOfResizeableTaskDp="); pw.print(mMinSizeOfResizeableTaskDp); if (mInitialDisplayWidth != mBaseDisplayWidth || mInitialDisplayHeight != mBaseDisplayHeight || mInitialDisplayDensity != mBaseDisplayDensity) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index d031bec5443fd..4c72d02b788aa 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -73,7 +73,6 @@ import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList; import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; import static com.android.server.wm.KeyguardController.KEYGUARD_SLEEP_TOKEN_TAG; -import static com.android.server.wm.RootWindowContainerProto.DEFAULT_MIN_SIZE_RESIZABLE_TASK; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; @@ -111,7 +110,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; @@ -134,7 +132,6 @@ import android.provider.Settings; import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.DisplayMetrics; import android.util.IntArray; import android.util.Pair; import android.util.Slog; @@ -1220,11 +1217,6 @@ class RootWindowContainer extends WindowContainer pw.println(mTopFocusedDisplayId); } - void dumpDefaultMinSizeOfResizableTask(PrintWriter pw) { - pw.print(" mDefaultMinSizeOfResizeableTaskDp="); - pw.println(mDefaultMinSizeOfResizeableTaskDp); - } - void dumpLayoutNeededDisplayIds(PrintWriter pw) { if (!isLayoutNeeded()) { return; @@ -1271,7 +1263,6 @@ class RootWindowContainer extends WindowContainer mTaskSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER); proto.write(IS_HOME_RECENTS_COMPONENT, mTaskSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); - proto.write(DEFAULT_MIN_SIZE_RESIZABLE_TASK, mDefaultMinSizeOfResizeableTaskDp); proto.end(token); } @@ -1359,7 +1350,6 @@ class RootWindowContainer extends WindowContainer mDefaultDisplay = displayContent; } } - calculateDefaultMinimalSizeOfResizeableTasks(); final TaskDisplayArea defaultTaskDisplayArea = getDefaultTaskDisplayArea(); defaultTaskDisplayArea.getOrCreateRootHomeTask(ON_TOP); @@ -3477,17 +3467,6 @@ class RootWindowContainer extends WindowContainer mService.startLaunchPowerMode(reason); } - // TODO(b/191434136): handle this properly when we add multi-window support on secondary - // display. - private void calculateDefaultMinimalSizeOfResizeableTasks() { - final Resources res = mService.mContext.getResources(); - final float minimalSize = res.getDimension( - com.android.internal.R.dimen.default_minimal_size_resizable_task); - final DisplayMetrics dm = res.getDisplayMetrics(); - - mDefaultMinSizeOfResizeableTaskDp = (int) (minimalSize / dm.density); - } - /** * Dumps the activities matching the given {@param name} in the either the focused root task * or all visible root tasks if {@param dumpVisibleRootTasksOnly} is true. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 2331dc4dff524..ff9d9f78a5c29 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -281,6 +281,8 @@ class Task extends TaskFragment { // code. static final int PERSIST_TASK_VERSION = 1; + private static final int DEFAULT_MIN_TASK_SIZE_DP = 220; + private float mShadowRadius = 0; /** @@ -2052,7 +2054,9 @@ class Task extends TaskFragment { // so that the user can not render the task fragment too small to manipulate. We don't need // to do this for the root pinned task as the bounds are controlled by the system. if (!inPinnedWindowingMode()) { - final int defaultMinSizeDp = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; + // Use Display specific min sizes when there is one associated with this Task. + final int defaultMinSizeDp = mDisplayContent == null + ? DEFAULT_MIN_TASK_SIZE_DP : mDisplayContent.mMinSizeOfResizeableTaskDp; final float density = (float) parentConfig.densityDpi / DisplayMetrics.DENSITY_DEFAULT; final int defaultMinSize = (int) (defaultMinSizeDp * density); @@ -3413,7 +3417,8 @@ class Task extends TaskFragment { info.isResizeable = isResizeable(); info.minWidth = mMinWidth; info.minHeight = mMinHeight; - info.defaultMinSize = mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp; + info.defaultMinSize = mDisplayContent == null + ? DEFAULT_MIN_TASK_SIZE_DP : mDisplayContent.mMinSizeOfResizeableTaskDp; info.positionInParent = getRelativePosition(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 026b9e1094d07..0ade9ec6bd377 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6420,7 +6420,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration()); pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad); mRoot.dumpTopFocusedDisplayId(pw); - mRoot.dumpDefaultMinSizeOfResizableTask(pw); mRoot.forAllDisplays(dc -> { final int displayId = dc.getDisplayId(); final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING); @@ -6438,6 +6437,8 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" imeControlTarget in display# "); pw.print(displayId); pw.print(' '); pw.println(imeControlTarget); } + pw.print(" Minimum task size of display#"); pw.print(displayId); + pw.print(' '); pw.print(dc.mMinSizeOfResizeableTaskDp); }); pw.print(" mInTouchMode="); pw.println(mInTouchMode); pw.print(" mBlurEnabled="); pw.println(mBlurController.getBlurEnabled()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 8d58ec00df962..d51527055af72 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1598,6 +1598,30 @@ public class DisplayContentTests extends WindowTestsBase { assertFalse(mDisplayContent.hasTopFixedRotationLaunchingApp()); } + /** + * Creates different types of displays, verifies that minimal task size doesn't change + * with density of display. + */ + @Test + public void testCalculatesDisplaySpecificMinTaskSizes() { + DisplayContent defaultTestDisplay = + new TestDisplayContent.Builder(mAtm, 1000, 2000).build(); + final int defaultMinTaskSize = defaultTestDisplay.mMinSizeOfResizeableTaskDp; + DisplayContent firstDisplay = new TestDisplayContent.Builder(mAtm, 1000, 2000) + .setDensityDpi(300) + .updateDisplayMetrics() + .setDefaultMinTaskSizeDp(defaultMinTaskSize + 10) + .build(); + assertEquals(defaultMinTaskSize + 10, firstDisplay.mMinSizeOfResizeableTaskDp); + + DisplayContent secondDisplay = new TestDisplayContent.Builder(mAtm, 200, 200) + .setDensityDpi(320) + .updateDisplayMetrics() + .setDefaultMinTaskSizeDp(defaultMinTaskSize + 20) + .build(); + assertEquals(defaultMinTaskSize + 20, secondDisplay.mMinSizeOfResizeableTaskDp); + } + @Test public void testRecentsNotRotatingWithFixedRotation() { unblockDisplayRotation(mDisplayContent); diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index 8b0716c699adf..1e64e469fe7f6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -29,18 +29,26 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; import android.annotation.Nullable; +import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Insets; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; +import android.util.DisplayMetrics; import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + class TestDisplayContent extends DisplayContent { public static final int DEFAULT_LOGICAL_DISPLAY_DENSITY = 300; @@ -85,6 +93,11 @@ class TestDisplayContent extends DisplayContent { private boolean mSystemDecorations = false; private int mStatusBarHeight = 0; private SettingsEntry mOverrideSettings; + private DisplayMetrics mDisplayMetrics; + @Mock + Context mMockContext; + @Mock + Resources mResources; Builder(ActivityTaskManagerService service, int width, int height) { mService = service; @@ -97,6 +110,8 @@ class TestDisplayContent extends DisplayContent { // Set unique ID so physical display overrides are not inheritted from // DisplayWindowSettings. mInfo.uniqueId = generateUniqueId(); + mDisplayMetrics = new DisplayMetrics(); + updateDisplayMetrics(); } Builder(ActivityTaskManagerService service, DisplayInfo info) { mService = service; @@ -153,6 +168,20 @@ class TestDisplayContent extends DisplayContent { mInfo.logicalDensityDpi = dpi; return this; } + Builder updateDisplayMetrics() { + mInfo.getAppMetrics(mDisplayMetrics); + return this; + } + Builder setDefaultMinTaskSizeDp(int valueDp) { + MockitoAnnotations.initMocks(this); + doReturn(mMockContext).when(mService.mContext).createConfigurationContext(any()); + doReturn(mResources).when(mMockContext).getResources(); + doReturn(valueDp * mDisplayMetrics.density) + .when(mResources) + .getDimension( + com.android.internal.R.dimen.default_minimal_size_resizable_task); + return this; + } TestDisplayContent createInternal(Display display) { return new TestDisplayContent(mService.mRootWindowContainer, display); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 62c1067ec707a..4095728476230 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -883,7 +883,8 @@ class WindowTestsBase extends SystemServiceTestsBase { /** Sets the default minimum task size to 1 so that tests can use small task sizes */ public void removeGlobalMinSizeRestriction() { - mAtm.mRootWindowContainer.mDefaultMinSizeOfResizeableTaskDp = 1; + mAtm.mRootWindowContainer.forAllDisplays( + displayContent -> displayContent.mMinSizeOfResizeableTaskDp = 1); } /** Mocks the behavior of taking a snapshot. */