From 443f9acda206bd7ed7e903e1ba548d6c2acb1529 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 18 Oct 2021 15:03:36 +0800 Subject: [PATCH] Compute surface position of scaled child window This replaces the way commit df46fd5 did. The frames of child window are still calculated with scaling, but only the surface scale is ignored. So if the app calls getLocationOnScreen for a scaled child window, the coordinate base can be consistent with parent. Bug: 182362657 Test: atest WindowStateTests#testCompatOverrideScale Change-Id: I6d4f7dab4949feb488fbcb42ff687a520fe4ca70 --- .../com/android/server/wm/WindowState.java | 60 ++++++------------- .../server/wm/utils/CoordinateTransforms.java | 6 -- .../android/server/wm/WindowStateTests.java | 28 +++++---- 3 files changed, 36 insertions(+), 58 deletions(-) diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index f77b6f2a11de1..068ff5f58aa8b 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -259,7 +259,6 @@ 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; @@ -1177,14 +1176,13 @@ 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. This method always returns {@code false} on child window because it - * should follow parent's scale. + * scaling override set. * @see CompatModePackages#getCompatScale * @see android.content.res.CompatibilityInfo#supportsScreen * @see ActivityRecord#hasSizeCompatBounds() */ boolean hasCompatScale() { - return (mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord)) && !mIsChildWindow; + return mOverrideScale != 1f || hasCompatScale(mAttrs, mActivityRecord); } /** @@ -4478,22 +4476,6 @@ 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(attrs.gravity, w, h, containingFrame, (int) (x + attrs.horizontalMargin * pw), @@ -5124,19 +5106,6 @@ class WindowState extends WindowContainer implements WindowManagerP } } - /** - * Expand the given rectangle by this windows surface insets. This - * takes you from the 'window size' to the 'surface size'. - * The surface insets are positive in each direction, so we inset by - * the inverse. - */ - void expandForSurfaceInsets(Rect r) { - r.inset(-mAttrs.surfaceInsets.left, - -mAttrs.surfaceInsets.top, - -mAttrs.surfaceInsets.right, - -mAttrs.surfaceInsets.bottom); - } - boolean surfaceInsetsChanging() { return !mLastSurfaceInsets.equals(mAttrs.surfaceInsets); } @@ -5454,6 +5423,10 @@ class WindowState extends WindowContainer implements WindowManagerP } private void updateScaleIfNeeded() { + if (mIsChildWindow) { + // Child window follows parent's scale. + return; + } float newHScale = mHScale * mGlobalScale * mWallpaperScale; float newVScale = mVScale * mGlobalScale * mWallpaperScale; if (mLastHScale != newHScale || @@ -5537,15 +5510,18 @@ class WindowState extends WindowContainer implements WindowManagerP // If changed, also adjust getTransformationMatrix final WindowContainer parentWindowContainer = getParent(); if (isChildWindow()) { - // TODO: This probably falls apart at some point and we should - // actually compute relative coordinates. - + final WindowState parent = getParentWindow(); + outPoint.offset(-parent.mWindowFrames.mFrame.left, -parent.mWindowFrames.mFrame.top); + // Undo the scale of window position because the relative coordinates for child are + // based on the scaled parent. + if (mInvGlobalScale != 1f) { + outPoint.x = (int) (outPoint.x * mInvGlobalScale + 0.5f); + outPoint.y = (int) (outPoint.y * mInvGlobalScale + 0.5f); + } // Since the parent was outset by its surface insets, we need to undo the outsetting // with insetting by the same amount. - final WindowState parent = getParentWindow(); transformSurfaceInsetsPosition(mTmpPoint, parent.mAttrs.surfaceInsets); - outPoint.offset(-parent.mWindowFrames.mFrame.left + mTmpPoint.x, - -parent.mWindowFrames.mFrame.top + mTmpPoint.y); + outPoint.offset(mTmpPoint.x, mTmpPoint.y); } else if (parentWindowContainer != null) { final Rect parentBounds = isStartingWindowAssociatedToTask() ? mStartingData.mAssociatedTask.getBounds() @@ -5564,7 +5540,7 @@ class WindowState extends WindowContainer implements WindowManagerP outPoint.offset(outset, outset); } - // Expand for surface insets. See WindowState.expandForSurfaceInsets. + // The surface size is larger than the window if the window has positive surface insets. transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets); outPoint.offset(-mTmpPoint.x, -mTmpPoint.y); @@ -5576,7 +5552,9 @@ class WindowState extends WindowContainer implements WindowManagerP * scaled, the insets also need to be scaled for surface position in global coordinate. */ private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) { - if (!hasCompatScale()) { + // Ignore the scale for child window because its insets have been scaled with the + // parent surface. + if (mGlobalScale == 1f || mIsChildWindow) { outPos.x = surfaceInsets.left; outPos.y = surfaceInsets.top; return; 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 6d8e07a919ccd..a2f37a56598dd 100644 --- a/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java +++ b/services/core/java/com/android/server/wm/utils/CoordinateTransforms.java @@ -152,10 +152,4 @@ 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 a8a9188a04246..ca2b4aebc736e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -78,6 +78,7 @@ import static org.mockito.Mockito.when; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Matrix; +import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; @@ -563,7 +564,7 @@ public class WindowStateTests extends WindowTestsBase { final WindowState child = createWindow(w, TYPE_APPLICATION_PANEL, "child"); assertTrue(w.hasCompatScale()); - assertFalse(child.hasCompatScale()); + assertTrue(child.hasCompatScale()); makeWindowVisible(w, child); w.setRequestedSize(100, 200); @@ -574,21 +575,26 @@ public class WindowStateTests extends WindowTestsBase { w.mAttrs.gravity = Gravity.TOP | Gravity.LEFT; child.mAttrs.gravity = Gravity.CENTER; DisplayContentTests.performLayout(mDisplayContent); + final Rect parentFrame = w.getFrame(); + final Rect childFrame = child.getFrame(); // 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); + assertEquals(parentFrame, 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); + // Frame on screen = 100x200 (250, 300 - 350, 500). Compat frame on client = 50x100. + unscaledCompatFrame.set(child.getWindowFrames().mCompatFrame); + unscaledCompatFrame.scale(overrideScale); + assertEquals(childFrame, unscaledCompatFrame); + + // The position of child is relative to parent. So the local coordinates should be scaled. + final Point expectedChildPos = new Point( + (int) ((childFrame.left - parentFrame.left) / overrideScale), + (int) ((childFrame.top - parentFrame.top) / overrideScale)); + final Point childPos = new Point(); + child.transformFrameToSurfacePosition(childFrame.left, childFrame.top, childPos); + assertEquals(expectedChildPos, childPos); // Surface should apply the scale. w.prepareSurfaces();