From df46fd52f90e70e07a3bc16adda158381f339d50 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 24 Mar 2021 23:10:48 +0800 Subject: Make child window inherit the scale of parent The child window computes its layout in parent's frame. If parent frame is scaled, the position and size of child window is already based on parent. And the child surface also has the same scale from parent surface. This change makes mGlobalScale of child window to 1. And use the unscaled containing frame display frame of parent to apply gravity, so the child window can fit in the scaled content of parent window. Bug: 182362657 Test: atest WindowStateTests#testCompatOverrideScale Change-Id: Ie8b9fabcfbccb63f54d51bdd55b23f835151202d --- .../java/com/android/server/wm/WindowState.java | 26 ++++++++++++++++++--- .../server/wm/utils/CoordinateTransforms.java | 6 +++++ .../com/android/server/wm/WindowStateTests.java | 27 ++++++++++++++++++++-- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 48d4fc5464b0..5784342bb558 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -255,6 +255,7 @@ import com.android.internal.util.ToBooleanFunction; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.SurfaceAnimator.AnimationType; +import com.android.server.wm.utils.CoordinateTransforms; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -624,6 +625,7 @@ class WindowState extends WindowContainer implements WindowManagerP private PowerManager.WakeLock mDrawLock; private final Rect mTmpRect = new Rect(); + private final Rect mTmpRect2 = new Rect(); private final Point mTmpPoint = new Point(); private final Transaction mTmpTransaction; @@ -1136,13 +1138,14 @@ class WindowState extends WindowContainer implements WindowManagerP /** * @return {@code true} if the application runs in size compatibility mode or has an app level - * scaling override set. + * scaling override set. This method always returns {@code false} on child window because it + * should follow parent's scale. * @see CompatModePackages#getCompatScale * @see android.content.res.CompatibilityInfo#supportsScreen * @see ActivityRecord#hasSizeCompatBounds() */ boolean hasCompatScale() { - return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord); + return (mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord)) && !mIsChildWindow; } /** @@ -1314,7 +1317,8 @@ class WindowState extends WindowContainer implements WindowManagerP } } - layoutDisplayFrame = new Rect(windowFrames.mDisplayFrame); + layoutDisplayFrame = mTmpRect2; + layoutDisplayFrame.set(windowFrames.mDisplayFrame); windowFrames.mDisplayFrame.set(windowFrames.mContainingFrame); layoutXDiff = mInsetFrame.left - windowFrames.mContainingFrame.left; layoutYDiff = mInsetFrame.top - windowFrames.mContainingFrame.top; @@ -4361,6 +4365,22 @@ class WindowState extends WindowContainer implements WindowManagerP h = Math.min(h, ph); } + if (mIsChildWindow) { + final WindowState parent = getTopParentWindow(); + if (parent.hasCompatScale()) { + // Scale the containing and display frames because they are in screen coordinates. + // The position of frames are already relative to parent so only size is scaled. + mTmpRect.set(containingFrame); + containingFrame = mTmpRect; + CoordinateTransforms.scaleRectSize(containingFrame, parent.mInvGlobalScale); + if (fitToDisplay) { + mTmpRect2.set(displayFrame); + displayFrame = mTmpRect2; + CoordinateTransforms.scaleRectSize(displayFrame, parent.mInvGlobalScale); + } + } + } + // Set mFrame Gravity.apply(mAttrs.gravity, w, h, containingFrame, (int) (x + mAttrs.horizontalMargin * pw), diff --git a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java index a2f37a56598d..6d8e07a919cc 100644 --- a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java +++ b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java @@ -152,4 +152,10 @@ public class CoordinateTransforms { transform.mapRect(tmp); inOutRect.set((int) tmp.left, (int) tmp.top, (int) tmp.right, (int) tmp.bottom); } + + /** Scales the rect without changing its position. */ + public static void scaleRectSize(Rect inOutRect, float scale) { + inOutRect.right = inOutRect.left + (int) (inOutRect.width() * scale + .5f); + inOutRect.bottom = inOutRect.top + (int) (inOutRect.height() * scale + .5f); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index bfbe203fb65e..6e5cc0c17f78 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -32,6 +32,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -570,21 +571,43 @@ public class WindowStateTests extends WindowTestsBase { spyOn(cmp); doReturn(overrideScale).when(cmp).getCompatScale(anyString(), anyInt()); final WindowState w = createWindow(null, TYPE_APPLICATION_OVERLAY, "win"); - makeWindowVisible(w); + final WindowState child = createWindow(w, TYPE_APPLICATION_PANEL, "child"); + + assertTrue(w.hasCompatScale()); + assertFalse(child.hasCompatScale()); + + makeWindowVisible(w, child); w.setRequestedSize(100, 200); + child.setRequestedSize(50, 100); + child.mAttrs.width = child.mAttrs.height = 0; + w.mAttrs.x = w.mAttrs.y = 100; w.mAttrs.width = w.mAttrs.height = WindowManager.LayoutParams.WRAP_CONTENT; w.mAttrs.gravity = Gravity.TOP | Gravity.LEFT; + child.mAttrs.gravity = Gravity.CENTER; DisplayContentTests.performLayout(mDisplayContent); - // Frame on screen = 100x200. Compat frame on client = 50x100. + // Frame on screen = 200x400 (200, 200 - 400, 600). Compat frame on client = 100x200. final Rect unscaledCompatFrame = new Rect(w.getWindowFrames().mCompatFrame); unscaledCompatFrame.scale(overrideScale); + final Rect parentFrame = w.getFrame(); assertEquals(w.getWindowFrames().mFrame, unscaledCompatFrame); + final Rect childFrame = child.getFrame(); + assertEquals(childFrame, child.getWindowFrames().mCompatFrame); + // Child frame = 50x100 (225, 250 - 275, 350) according to Gravity.CENTER. + final int childX = parentFrame.left + child.mRequestedWidth / 2; + final int childY = parentFrame.top + child.mRequestedHeight / 2; + final Rect expectedChildFrame = new Rect(childX, childY, childX + child.mRequestedWidth, + childY + child.mRequestedHeight); + assertEquals(expectedChildFrame, childFrame); + // Surface should apply the scale. w.prepareSurfaces(); verify(w.getPendingTransaction()).setMatrix(w.getSurfaceControl(), overrideScale, 0, 0, overrideScale); + // Child surface inherits parent's scale, so it doesn't need to scale. + verify(child.getPendingTransaction(), never()).setMatrix(any(), anyInt(), anyInt(), + anyInt(), anyInt()); // According to "dp * density / 160 = px", density is scaled and the size in dp is the same. final CompatibilityInfo compatInfo = cmp.compatibilityInfoForPackageLocked( -- cgit v1.2.3-59-g8ed1b