From c77eaf873d271082d8aa0c602c3e3f015b5db06a Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Fri, 1 Jul 2022 16:58:21 +0800 Subject: [PATCH] Send size-compat scale to the client The client computes the window frame on its own in ViewRootImpl#setView. However, the bounds obtained from WindowConfiguration is not size- compatible, which makes legacy apps produce wrong frames. The frame is larger than expected, so when computing WindowInsets with size- compatible InsetsState, the window cannot receive insets. Although the client will receive the correct window frame from relayout, but the first WindowInsets has been dispatched before that. This CL sends the size-compat scale to the client, so the client can use the correct WindowConfiguration to compute frames. This is also a step to enable the client to perform local window layout. Bug: 237749017 Bug: 161810301 Bug: 175861127 Test: atest StartingSurfaceDrawerTests WindowAddRemovePerfTest ActivityRecordTests WindowManagerServiceTests Change-Id: I6b23901f4b1f009444c04da7e078ea971a386ad7 --- .../android/wm/WindowAddRemovePerfTest.java | 3 +- .../java/android/app/WindowConfiguration.java | 9 ++++ .../content/res/CompatibilityInfo.java | 7 +-- .../service/wallpaper/WallpaperService.java | 2 +- core/java/android/view/IWindowSession.aidl | 7 +-- core/java/android/view/ViewRootImpl.java | 31 ++++++++++-- .../android/view/WindowlessWindowManager.java | 13 +++-- .../android/window/ClientWindowFrames.java | 8 ++- .../startingsurface/TaskSnapshotWindow.java | 3 +- .../StartingSurfaceDrawerTests.java | 2 +- .../java/com/android/server/wm/Session.java | 15 +++--- .../server/wm/WindowManagerService.java | 9 +++- .../com/android/server/wm/WindowState.java | 50 ++++++++++--------- .../server/wm/ActivityRecordTests.java | 2 +- .../server/wm/WindowManagerServiceTests.java | 2 +- 15 files changed, 106 insertions(+), 57 deletions(-) diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java index 06207215b7be5..f844ba3bb0a9d 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java @@ -88,6 +88,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase final InsetsState mOutInsetsState = new InsetsState(); final InsetsSourceControl[] mOutControls = new InsetsSourceControl[0]; final Rect mOutAttachedFrame = new Rect(); + final float[] mOutSizeCompatScale = { 1f }; TestWindow() { mLayoutParams.setTitle(TestWindow.class.getName()); @@ -106,7 +107,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase long startTime = SystemClock.elapsedRealtimeNanos(); session.addToDisplay(this, mLayoutParams, View.VISIBLE, Display.DEFAULT_DISPLAY, mRequestedVisibilities, inputChannel, - mOutInsetsState, mOutControls, mOutAttachedFrame); + mOutInsetsState, mOutControls, mOutAttachedFrame, mOutSizeCompatScale); final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime; state.addExtraResult("add", elapsedTimeNsOfAdd); diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index d0ea8d41d65c1..397c8e010bad3 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -460,6 +460,15 @@ public class WindowConfiguration implements Parcelable, Comparable 0) { mSyncSeqId = maybeSyncSeqId; } + mInvSizeCompatScale = 1f / mTmpFrames.sizeCompatScale; final int transformHint = SurfaceControl.rotationToBufferTransform( (mDisplayInstallOrientation + mDisplay.getRotation()) % 4); - final WindowConfiguration winConfig = getConfiguration().windowConfiguration; + final WindowConfiguration winConfig = getCompatWindowConfiguration(); WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth, requestedHeight, mTmpFrames.frame, mPendingDragResizing, mSurfaceSize); @@ -8170,7 +8191,7 @@ public final class ViewRootImpl implements ViewParent, private void setFrame(Rect frame) { mWinFrame.set(frame); - final WindowConfiguration winConfig = getConfiguration().windowConfiguration; + final WindowConfiguration winConfig = getCompatWindowConfiguration(); mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() ? winConfig.getMaxBounds() : frame); diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 94da2741f71a7..d55c838c3e533 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -149,7 +149,8 @@ public class WindowlessWindowManager implements IWindowSession { public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, - InsetsSourceControl[] outActiveControls, Rect outAttachedFrame) { + InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, + float[] outSizeCompatScale) { final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession) .setFormat(attrs.format) .setBLASTLayer() @@ -182,6 +183,7 @@ public class WindowlessWindowManager implements IWindowSession { mStateForWindow.put(window.asBinder(), state); } outAttachedFrame.set(0, 0, -1, -1); + outSizeCompatScale[0] = 1f; final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE | WindowManagerGlobal.ADD_FLAG_USE_BLAST; @@ -197,15 +199,18 @@ public class WindowlessWindowManager implements IWindowSession { public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, - InsetsSourceControl[] outActiveControls, Rect outAttachedFrame) { + InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, + float[] outSizeCompatScale) { return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibilities, - outInputChannel, outInsetsState, outActiveControls, outAttachedFrame); + outInputChannel, outInsetsState, outActiveControls, outAttachedFrame, + outSizeCompatScale); } @Override public int addToDisplayWithoutInputChannel(android.view.IWindow window, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, - android.view.InsetsState insetsState, Rect outAttachedFrame) { + android.view.InsetsState insetsState, Rect outAttachedFrame, + float[] outSizeCompatScale) { return 0; } diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java index 929e81ed90441..f274d1a15ba55 100644 --- a/core/java/android/window/ClientWindowFrames.java +++ b/core/java/android/window/ClientWindowFrames.java @@ -49,6 +49,8 @@ public class ClientWindowFrames implements Parcelable { public boolean isParentFrameClippedByDisplayCutout; + public float sizeCompatScale = 1f; + public ClientWindowFrames() { } @@ -60,6 +62,7 @@ public class ClientWindowFrames implements Parcelable { attachedFrame = new Rect(other.attachedFrame); } isParentFrameClippedByDisplayCutout = other.isParentFrameClippedByDisplayCutout; + sizeCompatScale = other.sizeCompatScale; } private ClientWindowFrames(Parcel in) { @@ -73,6 +76,7 @@ public class ClientWindowFrames implements Parcelable { parentFrame.readFromParcel(in); attachedFrame = in.readTypedObject(Rect.CREATOR); isParentFrameClippedByDisplayCutout = in.readBoolean(); + sizeCompatScale = in.readFloat(); } @Override @@ -82,6 +86,7 @@ public class ClientWindowFrames implements Parcelable { parentFrame.writeToParcel(dest, flags); dest.writeTypedObject(attachedFrame, flags); dest.writeBoolean(isParentFrameClippedByDisplayCutout); + dest.writeFloat(sizeCompatScale); } @Override @@ -91,7 +96,8 @@ public class ClientWindowFrames implements Parcelable { + " display=" + displayFrame.toShortString(sb) + " parentFrame=" + parentFrame.toShortString(sb) + (attachedFrame != null ? " attachedFrame=" + attachedFrame.toShortString() : "") - + " parentClippedByDisplayCutout=" + isParentFrameClippedByDisplayCutout + "}"; + + (isParentFrameClippedByDisplayCutout ? " parentClippedByDisplayCutout" : "") + + (sizeCompatScale != 1f ? " sizeCompatScale=" + sizeCompatScale : "") + "}"; } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index 19d3acbf28d41..b70bde3a64ee5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -228,12 +228,13 @@ public class TaskSnapshotWindow { final InsetsState tmpInsetsState = new InsetsState(); final InputChannel tmpInputChannel = new InputChannel(); + final float[] sizeCompatScale = { 1f }; try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#addToDisplay"); final int res = session.addToDisplay(window, layoutParams, View.GONE, displayId, info.requestedVisibilities, tmpInputChannel, tmpInsetsState, tmpControls, - new Rect()); + new Rect(), sizeCompatScale); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (res < 0) { Slog.w(TAG, "Failed to add snapshot starting window res=" + res); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index 46b040fd43257..e5ae2962e6e4a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -251,7 +251,7 @@ public class StartingSurfaceDrawerTests extends ShellTestCase { anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* requestedVisibility */, any() /* outInputChannel */, any() /* outInsetsState */, any() /* outActiveControls */, - any() /* outAttachedFrame */); + any() /* outAttachedFrame */, any() /* outSizeCompatScale */); TaskSnapshotWindow mockSnapshotWindow = TaskSnapshotWindow.create(windowInfo, mBinder, snapshot, mTestExecutor, () -> { diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 3577545088e00..0128c187bbddc 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -198,28 +198,31 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, - InsetsSourceControl[] outActiveControls, Rect outAttachedFrame) { + InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, + float[] outSizeCompatScale) { return mService.addWindow(this, window, attrs, viewVisibility, displayId, UserHandle.getUserId(mUid), requestedVisibilities, outInputChannel, outInsetsState, - outActiveControls, outAttachedFrame); + outActiveControls, outAttachedFrame, outSizeCompatScale); } @Override public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, - InsetsSourceControl[] outActiveControls, Rect outAttachedFrame) { + InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, + float[] outSizeCompatScale) { return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, requestedVisibilities, outInputChannel, outInsetsState, outActiveControls, - outAttachedFrame); + outAttachedFrame, outSizeCompatScale); } @Override public int addToDisplayWithoutInputChannel(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, InsetsState outInsetsState, Rect outAttachedFrame) { + int viewVisibility, int displayId, InsetsState outInsetsState, Rect outAttachedFrame, + float[] outSizeCompatScale) { return mService.addWindow(this, window, attrs, viewVisibility, displayId, UserHandle.getUserId(mUid), mDummyRequestedVisibilities, null /* outInputChannel */, - outInsetsState, mDummyControls, outAttachedFrame); + outInsetsState, mDummyControls, outAttachedFrame, outSizeCompatScale); } @Override diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9d6e250e8a47e..4aa96ba7eda19 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1448,7 +1448,8 @@ public class WindowManagerService extends IWindowManager.Stub public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsVisibilities requestedVisibilities, InputChannel outInputChannel, InsetsState outInsetsState, - InsetsSourceControl[] outActiveControls, Rect outAttachedFrame) { + InsetsSourceControl[] outActiveControls, Rect outAttachedFrame, + float[] outSizeCompatScale) { Arrays.fill(outActiveControls, null); int[] appOp = new int[1]; final boolean isRoundedCornerOverlay = (attrs.privateFlags @@ -1865,11 +1866,15 @@ public class WindowManagerService extends IWindowManager.Stub getInsetsSourceControls(win, outActiveControls); if (win.mLayoutAttached) { - outAttachedFrame.set(win.getParentWindow().getCompatFrame()); + outAttachedFrame.set(win.getParentWindow().getFrame()); + if (win.mInvGlobalScale != 1f) { + outAttachedFrame.scale(win.mInvGlobalScale); + } } else { // Make this invalid which indicates a null attached frame. outAttachedFrame.set(0, 0, -1, -1); } + outSizeCompatScale[0] = win.getSizeCompatScale(); } Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index af8c4c8e93701..04fa30a9a684f 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -473,11 +473,12 @@ class WindowState extends WindowContainer implements WindowManagerP int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; // Current transformation being applied. - float mGlobalScale=1; - float mInvGlobalScale=1; + float mGlobalScale = 1f; + float mInvGlobalScale = 1f; + float mSizeCompatScale = 1f; final float mOverrideScale; - float mHScale=1, mVScale=1; - float mLastHScale=1, mLastVScale=1; + float mHScale = 1f, mVScale = 1f; + float mLastHScale = 1f, mLastVScale = 1f; // An offset in pixel of the surface contents from the window position. Used for Wallpaper // to provide the effect of scrolling within a large surface. We just use these values as @@ -1253,18 +1254,19 @@ class WindowState extends WindowContainer implements WindowManagerP void updateGlobalScale() { if (hasCompatScale()) { - if (mOverrideScale != 1f) { - mGlobalScale = mToken.hasSizeCompatBounds() - ? mToken.getSizeCompatScale() * mOverrideScale - : mOverrideScale; - } else { - mGlobalScale = mToken.getSizeCompatScale(); - } + mSizeCompatScale = (mOverrideScale == 1f || mToken.hasSizeCompatBounds()) + ? mToken.getSizeCompatScale() + : 1f; + mGlobalScale = mSizeCompatScale * mOverrideScale; mInvGlobalScale = 1f / mGlobalScale; return; } - mGlobalScale = mInvGlobalScale = 1f; + mGlobalScale = mInvGlobalScale = mSizeCompatScale = 1f; + } + + float getSizeCompatScale() { + return mSizeCompatScale; } /** @@ -1355,7 +1357,7 @@ class WindowState extends WindowContainer implements WindowManagerP windowFrames.mFrame.set(clientWindowFrames.frame); windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame); windowFrames.mParentFrame.set(clientWindowFrames.parentFrame); - if (hasCompatScale()) { + if (mGlobalScale != 1f) { // The frames sent from the client need to be adjusted to the real coordinate space. windowFrames.mFrame.scale(mGlobalScale); windowFrames.mDisplayFrame.scale(mGlobalScale); @@ -1367,7 +1369,7 @@ class WindowState extends WindowContainer implements WindowManagerP windowFrames.mFrame.set(clientWindowFrames.frame); windowFrames.mCompatFrame.set(windowFrames.mFrame); - if (hasCompatScale()) { + if (mInvGlobalScale != 1f) { // Also, the scaled frame that we report to the app needs to be adjusted to be in // its coordinate space. windowFrames.mCompatFrame.scale(mInvGlobalScale); @@ -1472,10 +1474,6 @@ class WindowState extends WindowContainer implements WindowManagerP return mWindowFrames.mParentFrame; } - Rect getCompatFrame() { - return mWindowFrames.mCompatFrame; - } - WindowManager.LayoutParams getAttrs() { return mAttrs; } @@ -1729,7 +1727,7 @@ class WindowState extends WindowContainer implements WindowManagerP */ InsetsState getCompatInsetsState() { InsetsState state = getInsetsState(); - if (hasCompatScale()) { + if (mInvGlobalScale != 1f) { state = new InsetsState(state, true); state.scale(mInvGlobalScale); } @@ -3837,15 +3835,19 @@ class WindowState extends WindowContainer implements WindowManagerP boolean relayoutVisible) { outFrames.frame.set(mWindowFrames.mCompatFrame); outFrames.displayFrame.set(mWindowFrames.mDisplayFrame); - if (mInvGlobalScale != 1.0f && hasCompatScale()) { + if (mInvGlobalScale != 1f) { outFrames.displayFrame.scale(mInvGlobalScale); } if (mLayoutAttached) { if (outFrames.attachedFrame == null) { outFrames.attachedFrame = new Rect(); } - outFrames.attachedFrame.set(getParentWindow().getCompatFrame()); + outFrames.attachedFrame.set(getParentWindow().getFrame()); + if (mInvGlobalScale != 1f) { + outFrames.attachedFrame.scale(mInvGlobalScale); + } } + outFrames.sizeCompatScale = mSizeCompatScale; // Note: in the cases where the window is tied to an activity, we should not send a // configuration update when the window has requested to be hidden. Doing so can lead to @@ -4345,7 +4347,7 @@ class WindowState extends WindowContainer implements WindowManagerP pw.println(prefix + "mHasSurface=" + mHasSurface + " isReadyForDisplay()=" + isReadyForDisplay() + " mWindowRemovalAllowed=" + mWindowRemovalAllowed); - if (hasCompatScale()) { + if (mInvGlobalScale != 1f) { pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB)); } if (dumpAll) { @@ -4557,7 +4559,7 @@ class WindowState extends WindowContainer implements WindowManagerP float translateToWindowX(float x) { float winX = x - mWindowFrames.mFrame.left; - if (hasCompatScale()) { + if (mGlobalScale != 1f) { winX *= mGlobalScale; } return winX; @@ -4565,7 +4567,7 @@ class WindowState extends WindowContainer implements WindowManagerP float translateToWindowY(float y) { float winY = y - mWindowFrames.mFrame.top; - if (hasCompatScale()) { + if (mGlobalScale != 1f) { winY *= mGlobalScale; } return winY; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 3f3d01a14f801..83b218226f421 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2002,7 +2002,7 @@ public class ActivityRecordTests extends WindowTestsBase { anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* requestedVisibilities */, any() /* outInputChannel */, any() /* outInsetsState */, any() /* outActiveControls */, - any() /* outAttachedFrame */); + any() /* outAttachedFrame */, any() /* outSizeCompatScale */); mAtm.mWindowManager.mStartingSurfaceController .createTaskSnapshotSurface(activity, snapshot); } catch (RemoteException ignored) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index 1a64f5e3a356b..bd575246bf149 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -283,7 +283,7 @@ public class WindowManagerServiceTests extends WindowTestsBase { mWm.addWindow(session, new TestIWindow(), params, View.VISIBLE, DEFAULT_DISPLAY, UserHandle.USER_SYSTEM, new InsetsVisibilities(), null, new InsetsState(), - new InsetsSourceControl[0], new Rect()); + new InsetsSourceControl[0], new Rect(), new float[1]); verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(), any(), anyInt(), anyInt(), any());