From 07d9444ed8d1ea8ace02d5411c281366b4b380f9 Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Fri, 18 Mar 2022 15:00:23 +0800 Subject: [PATCH] Push the frame to InsetsSourceProvider This CL stops InsetsSourceProvider from reading the frame from the window. Instead, the caller sets the frame via #updateSourceFrame. When the window layout is moved to the client side, when the rotation is changed, we need to dispatch the InsetsState computed from the new rotation to all the clients. At this moment, the window frames of insets source windows are not up-to-date yet, and we cannot use them to generate insets sources. Instead, we pre-compute the window frames based on the new rotation at the server side, and use them to update InsetsState. In this way, the first InsetsState dispatched to the client after rotation will be correct. This CL also - unbundles the calling order of setServerVisible and updateSourceFrame. The calling order won't affect the result. - moves logic from DisplayPolicy#layoutWindowLw to WindowState#setFrames because we plan to remove layoutWindowLw in the future. - removes redundant logs about layout. The log in WindowLayout#computeFrames can cover them all. Bug: 161810301 Test: Perform fixed rotation, seamless rotation, and regular rotation and see if the layout of each window is expected. Change-Id: Ie7845de2830cdbdfd0049b8eef5a5f0704f796e8 --- .../com/android/server/wm/DisplayPolicy.java | 50 ++++++++--------- .../server/wm/ImeInsetsSourceProvider.java | 5 +- .../server/wm/InsetsSourceProvider.java | 54 +++++++++---------- .../server/wm/InsetsStateController.java | 18 ------- .../server/wm/WindowManagerService.java | 1 + .../com/android/server/wm/WindowState.java | 33 ++++++------ .../server/wm/DisplayPolicyLayoutTests.java | 2 + .../server/wm/InsetsStateControllerTest.java | 1 + ...ndowContainerInsetsSourceProviderTest.java | 9 +++- 9 files changed, 84 insertions(+), 89 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index bb5dacc89bc2a..88d7dff4ff1ac 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -114,6 +114,7 @@ import android.os.UserHandle; import android.util.ArraySet; import android.util.PrintWriterPrinter; import android.util.Slog; +import android.util.SparseArray; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Gravity; @@ -1151,9 +1152,8 @@ public class DisplayPolicy { } }, - // For IME we use regular frame. (displayFrames, windowContainer, inOutFrame) -> { - inOutFrame.set(win.getFrame()); + // For IME, we don't modify the frame. }); mDisplayContent.setInsetProvider(ITYPE_BOTTOM_MANDATORY_GESTURES, win, @@ -1488,9 +1488,30 @@ public class DisplayPolicy { displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe, displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH, win.getRequestedVisibilities(), - null /* attachedWindowFrame */, win.mGlobalScale, - sTmpClientFrames); - controller.computeSimulatedState(win, displayFrames, sTmpClientFrames.frame); + null /* attachedWindowFrame */, win.mGlobalScale, sTmpClientFrames); + final SparseArray sources = win.getProvidedInsetsSources(); + final InsetsState state = displayFrames.mInsetsState; + for (int index = sources.size() - 1; index >= 0; index--) { + final int type = sources.keyAt(index); + state.addSource(controller.getSourceProvider(type).createSimulatedSource( + displayFrames, sTmpClientFrames.frame)); + } + } + } + + // TODO(b/161810301): No one is calling this since we haven't moved window layout to the client. + // When that happens, this should be called when the display rotation is + // changed, so that we can dispatch the correct insets to all the clients + // before the insets source windows report their frames to the server. + void updateInsetsSourceFramesExceptIme(DisplayFrames displayFrames) { + for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) { + final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i); + mWindowLayout.computeFrames(win.getLayoutingAttrs(displayFrames.mRotation), + displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe, + displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH, + UNSPECIFIED_LENGTH, win.getRequestedVisibilities(), + null /* attachedWindowFrame */, win.mGlobalScale, sTmpClientFrames); + win.updateSourceFrame(sTmpClientFrames.frame); } } @@ -1519,10 +1540,6 @@ public class DisplayPolicy { displayFrames = win.getDisplayFrames(displayFrames); final WindowManager.LayoutParams attrs = win.getLayoutingAttrs(displayFrames.mRotation); - final WindowFrames windowFrames = win.getWindowFrames(); - final Rect pf = windowFrames.mParentFrame; - final Rect df = windowFrames.mDisplayFrame; - final Rect f = windowFrames.mFrame; final Rect attachedWindowFrame = attached != null ? attached.getFrame() : null; // If this window has different LayoutParams for rotations, we cannot trust its requested @@ -1531,25 +1548,10 @@ public class DisplayPolicy { final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH; final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH; - sTmpLastParentFrame.set(pf); - mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe, win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight, win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale, sTmpClientFrames); - windowFrames.setParentFrameWasClippedByDisplayCutout( - sTmpClientFrames.isParentFrameClippedByDisplayCutout); - - if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() - + ": sim=#" + Integer.toHexString(attrs.softInputMode) - + " attach=" + attached + " type=" + attrs.type - + " flags=" + ViewDebug.flagsToString(LayoutParams.class, "flags", attrs.flags) - + " pf=" + pf.toShortString() + " df=" + df.toShortString() - + " f=" + f.toShortString()); - - if (!sTmpLastParentFrame.equals(pf)) { - windowFrames.setContentChanged(true); - } win.setFrames(sTmpClientFrames); } diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 199517c441ad4..0d4cfa3a8128f 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -29,6 +29,7 @@ import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_S import android.annotation.NonNull; import android.annotation.Nullable; +import android.graphics.Rect; import android.os.Trace; import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; @@ -79,8 +80,8 @@ final class ImeInsetsSourceProvider extends WindowContainerInsetsSourceProvider } @Override - void updateSourceFrame() { - super.updateSourceFrame(); + void updateSourceFrame(Rect frame) { + super.updateSourceFrame(frame); onSourceChanged(); } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 047bf2f53b687..f3f08b202feda 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -84,6 +84,7 @@ abstract class InsetsSourceProvider { private TriConsumer mImeFrameProvider; private final Rect mImeOverrideFrame = new Rect(); private boolean mIsLeashReadyForDispatching; + private final Rect mSourceFrame = new Rect(); private final Rect mLastSourceFrame = new Rect(); private final Consumer mSetLeashPositionConsumer = t -> { @@ -183,8 +184,8 @@ abstract class InsetsSourceProvider { mImeFrameProvider = imeFrameProvider; if (windowContainer == null) { setServerVisible(false); - mSource.setFrame(new Rect()); mSource.setVisibleFrame(null); + mSourceFrame.setEmpty(); } else { mWindowContainer.getProvidedInsetsSources().put(mSource.getType(), mSource); if (mControllable) { @@ -208,7 +209,7 @@ abstract class InsetsSourceProvider { * The source frame can affect the layout of other windows, so this should be called once the * window container gets laid out. */ - void updateSourceFrame() { + void updateSourceFrame(Rect frame) { if (mWindowContainer == null) { return; } @@ -230,39 +231,25 @@ abstract class InsetsSourceProvider { return; } - if (win.mGivenInsetsPending) { - // If the given insets are pending, they are not reliable for now. The source frame - // should be updated after the new given insets are sent to window manager. - return; - } - - // Make sure we set the valid source frame only when server visible is true, because the - // frame may not yet determined that server side doesn't think the window is ready to - // visible. (i.e. No surface, pending insets that were given during layout, etc..) - if (mServerVisible) { - mTmpRect.set(win.getFrame()); - if (mFrameProvider != null) { - mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames, - mWindowContainer, mTmpRect); - } else { - mTmpRect.inset(win.mGivenContentInsets); - } + mSourceFrame.set(frame); + if (mFrameProvider != null) { + mFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames, + mWindowContainer, mSourceFrame); } else { - mTmpRect.setEmpty(); + mSourceFrame.inset(win.mGivenContentInsets); } - mSource.setFrame(mTmpRect); + updateSourceFrameForServerVisibility(); if (mImeFrameProvider != null) { - mImeOverrideFrame.set(win.getFrame()); + mImeOverrideFrame.set(frame); mImeFrameProvider.accept(mWindowContainer.getDisplayContent().mDisplayFrames, - mWindowContainer, - mImeOverrideFrame); + mWindowContainer, mImeOverrideFrame); } if (win.mGivenVisibleInsets.left != 0 || win.mGivenVisibleInsets.top != 0 || win.mGivenVisibleInsets.right != 0 || win.mGivenVisibleInsets.bottom != 0) { - mTmpRect.set(win.getFrame()); + mTmpRect.set(frame); mTmpRect.inset(win.mGivenVisibleInsets); mSource.setVisibleFrame(mTmpRect); } else { @@ -270,13 +257,24 @@ abstract class InsetsSourceProvider { } } + private void updateSourceFrameForServerVisibility() { + // Make sure we set the valid source frame only when server visible is true, because the + // frame may not yet determined that server side doesn't think the window is ready to + // visible. (i.e. No surface, pending insets that were given during layout, etc..) + if (mServerVisible) { + mSource.setFrame(mSourceFrame); + } else { + mSource.setFrame(0, 0, 0, 0); + } + } + /** @return A new source computed by the specified window frame in the given display frames. */ - InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect winFrame) { + InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect frame) { // Don't copy visible frame because it might not be calculated in the provided display // frames and it is not significant for this usage. final InsetsSource source = new InsetsSource(mSource.getType()); source.setVisible(mSource.isVisible()); - mTmpRect.set(winFrame); + mTmpRect.set(frame); if (mFrameProvider != null) { mFrameProvider.accept(displayFrames, mWindowContainer, mTmpRect); } @@ -296,7 +294,6 @@ abstract class InsetsSourceProvider { ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy() : mWindowContainer.isVisibleRequested(); setServerVisible(isServerVisible); - updateSourceFrame(); if (mControl != null) { boolean changed = false; final Point position = getWindowFrameSurfacePosition(); @@ -496,6 +493,7 @@ abstract class InsetsSourceProvider { @VisibleForTesting void setServerVisible(boolean serverVisible) { mServerVisible = serverVisible; + updateSourceFrameForServerVisibility(); updateVisibility(); } diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 78608e2bf2037..a19d72e37124a 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -30,7 +30,6 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import android.annotation.NonNull; import android.annotation.Nullable; -import android.graphics.Rect; import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; @@ -204,23 +203,6 @@ class InsetsStateController { } } - /** - * Computes insets state of the insets provider window in the display frames. - * - * @param win The owner window of insets provider. - * @param displayFrames The display frames to create insets source. - * @param winFrame The frame of the insets source window. - */ - void computeSimulatedState(WindowState win, DisplayFrames displayFrames, Rect winFrame) { - final InsetsState state = displayFrames.mInsetsState; - for (int i = mProviders.size() - 1; i >= 0; i--) { - final WindowContainerInsetsSourceProvider provider = mProviders.valueAt(i); - if (provider.mWindowContainer == win) { - state.addSource(provider.createSimulatedSource(displayFrames, winFrame)); - } - } - } - boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) { return mTypeFakeControlTargetMap.get(type) == target; } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c50888b5a1724..087eef13d8137 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2157,6 +2157,7 @@ public class WindowManagerService extends IWindowManager.Stub w.mGivenTouchableRegion.scale(w.mGlobalScale); } w.setDisplayLayoutNeeded(); + w.updateSourceFrame(w.getFrame()); mWindowPlacerLocked.performSurfacePlacement(); w.getDisplayContent().getInputMonitor().updateInputWindowsLw(true); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 60e196c584653..2e9eb3118d117 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -142,7 +142,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; @@ -1398,11 +1397,15 @@ class WindowState extends WindowContainer implements WindowManagerP mHaveFrame = true; final WindowFrames windowFrames = mWindowFrames; + mTmpRect.set(windowFrames.mParentFrame); windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame); windowFrames.mParentFrame.set(clientWindowFrames.parentFrame); windowFrames.mFrame.set(clientWindowFrames.frame); + windowFrames.setParentFrameWasClippedByDisplayCutout( + clientWindowFrames.isParentFrameClippedByDisplayCutout); - if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { + if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight + || !mTmpRect.equals(windowFrames.mParentFrame)) { mLastRequestedWidth = mRequestedWidth; mLastRequestedHeight = mRequestedHeight; windowFrames.setContentChanged(true); @@ -1431,16 +1434,6 @@ class WindowState extends WindowContainer implements WindowManagerP windowFrames.mRelFrame.offsetTo(windowFrames.mFrame.left - parentLeft, windowFrames.mFrame.top - parentTop); - if (DEBUG_LAYOUT || DEBUG) { - final int pw = windowFrames.mParentFrame.width(); - final int ph = windowFrames.mParentFrame.height(); - Slog.v(TAG, "Resolving (mRequestedWidth=" - + mRequestedWidth + ", mRequestedheight=" - + mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph - + "): frame=" + windowFrames.mFrame.toShortString() - + " " + mAttrs.getTitle()); - } - if (mAttrs.type == TYPE_DOCK_DIVIDER) { if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) { mMovedByResize = true; @@ -1455,9 +1448,19 @@ class WindowState extends WindowContainer implements WindowManagerP } } - // Update the source frame to provide insets to other windows during layout. - if (mControllableInsetProvider != null) { - mControllableInsetProvider.updateSourceFrame(); + updateSourceFrame(windowFrames.mFrame); + } + + void updateSourceFrame(Rect winFrame) { + if (mGivenInsetsPending) { + // The given insets are pending, and they are not reliable for now. The source frame + // should be updated after the new given insets are sent to window manager. + return; + } + final SparseArray providedSources = getProvidedInsetsSources(); + final InsetsStateController controller = getDisplayContent().getInsetsStateController(); + for (int i = providedSources.size() - 1; i >= 0; i--) { + controller.getSourceProvider(providedSources.keyAt(i)).updateSourceFrame(winFrame); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index db22757cc4feb..45ae81a71c440 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -157,6 +157,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { win.getFrame().set(0, 0, 500, 100); addWindow(win); + win.updateSourceFrame(win.getFrame()); InsetsStateController controller = mDisplayContent.getInsetsStateController(); controller.onPostLayout(); @@ -185,6 +186,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { win.getFrame().set(0, 0, 500, 100); addWindow(win); + win.updateSourceFrame(win.getFrame()); mDisplayContent.getInsetsStateController().onPostLayout(); InsetsSourceProvider provider = diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 90a6918644faf..6d022262b7200 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -280,6 +280,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { rect.set(0, 1, 2, 3))); getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null); statusBar.setControllableInsetProvider(statusBarProvider); + statusBar.updateSourceFrame(statusBar.getFrame()); statusBarProvider.onPostLayout(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java index 10e429250c192..e824f3d2916d0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java @@ -64,6 +64,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { statusBar.getFrame().set(0, 0, 500, 100); statusBar.mHasSurface = true; mProvider.setWindowContainer(statusBar, null, null); + mProvider.updateSourceFrame(statusBar.getFrame()); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame()); assertEquals(Insets.of(0, 100, 0, 0), @@ -81,6 +82,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { ime.mGivenVisibleInsets.set(0, 0, 0, 75); ime.mHasSurface = true; mProvider.setWindowContainer(ime, null, null); + mProvider.updateSourceFrame(ime.getFrame()); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 40), mProvider.getSource().getFrame()); assertEquals(new Rect(0, 0, 500, 25), mProvider.getSource().getVisibleFrame()); @@ -96,6 +98,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); statusBar.getFrame().set(0, 0, 500, 100); mProvider.setWindowContainer(statusBar, null, null); + mProvider.updateSourceFrame(statusBar.getFrame()); mProvider.onPostLayout(); assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500), false /* ignoreVisibility */)); @@ -110,6 +113,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { (displayFrames, windowState, rect) -> { rect.set(10, 10, 20, 20); }, null); + mProvider.updateSourceFrame(statusBar.getFrame()); mProvider.onPostLayout(); assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame()); } @@ -181,7 +185,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { mImeProvider.setWindowContainer(inputMethod, null, null); mImeProvider.setServerVisible(false); mImeSource.setVisible(true); - mImeProvider.updateSourceFrame(); + mImeProvider.updateSourceFrame(inputMethod.getFrame()); assertEquals(new Rect(0, 0, 0, 0), mImeSource.getFrame()); Insets insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500), false /* ignoreVisibility */); @@ -189,7 +193,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { mImeProvider.setServerVisible(true); mImeSource.setVisible(true); - mImeProvider.updateSourceFrame(); + mImeProvider.updateSourceFrame(inputMethod.getFrame()); assertEquals(inputMethod.getFrame(), mImeSource.getFrame()); insets = mImeSource.calculateInsets(new Rect(0, 0, 500, 500), false /* ignoreVisibility */); @@ -229,6 +233,7 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase { statusBar.getFrame().set(0, 0, 500, 100); statusBar.mHasSurface = true; mProvider.setWindowContainer(statusBar, null, null); + mProvider.updateSourceFrame(statusBar.getFrame()); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame()); // Still apply top insets if window overlaps even if it's top doesn't exactly match