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
This commit is contained in:
Riddle Hsu
2021-10-18 15:03:36 +08:00
parent 9c6e07a76f
commit 443f9acda2
3 changed files with 36 additions and 58 deletions

View File

@@ -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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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<WindowState> 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;

View File

@@ -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);
}
}

View File

@@ -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();