Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eefe559c authored by Tiger Huang's avatar Tiger Huang
Browse files

Make insets source window stable while resizing

When the size and the position of the insets source window are changed
at the same time, setPosition will be applied first, and the client will
draw on the new-size surface later, which makes the screen flicker.

This CL defers the setPosition transaction until the new frame is drawn,
which can make the window stable if the content is drawn at the same
location on the display.

This CL also fixes WindowState#mGivenInsetsPending. If the given insets
will be sent to window manager, the provided insets won't be changed
during relayoutWindow until the given insets are sent.

Bug: 171965103
Test: steps in the bug
Change-Id: I4684c03e8def6fa33980e6c10e444f7377c306f8
parent c6183933
Loading
Loading
Loading
Loading
+6 −12
Original line number Original line Diff line number Diff line
@@ -2643,18 +2643,12 @@ public final class ViewRootImpl implements ViewParent,
                || mForceNextWindowRelayout) {
                || mForceNextWindowRelayout) {
            mForceNextWindowRelayout = false;
            mForceNextWindowRelayout = false;


            if (isViewVisible) {
            // If this window is giving internal insets to the window manager, then we want to first
                // If this window is giving internal insets to the window
            // make the provided insets unchanged during layout. This avoids it briefly causing
                // manager, and it is being added or changing its visibility,
            // other windows to resize/move based on the raw frame of the window, waiting until we
                // then we want to first give the window manager "fake"
            // can finish laying out this window and get back to the window manager with the
                // insets to cause it to effectively ignore the content of
            // ultimately computed insets.
                // the window during layout.  This avoids it briefly causing
            insetsPending = computesInternalInsets;
                // other windows to resize/move based on the raw frame of the
                // window, waiting until we can finish laying out this window
                // and get back to the window manager with the ultimately
                // computed insets.
                insetsPending = computesInternalInsets && (mFirst || viewVisibilityChanged);
            }


            if (mSurfaceHolder != null) {
            if (mSurfaceHolder != null) {
                mSurfaceHolder.mSurfaceLock.lock();
                mSurfaceHolder.mSurfaceLock.lock();
+36 −9
Original line number Original line Diff line number Diff line
@@ -151,6 +151,7 @@ class InsetsSourceProvider {
            // TODO: Ideally, we should wait for the animation to finish so previous window can
            // TODO: Ideally, we should wait for the animation to finish so previous window can
            // animate-out as new one animates-in.
            // animate-out as new one animates-in.
            mWin.cancelAnimation();
            mWin.cancelAnimation();
            mWin.mPendingPositionChanged = null;
        }
        }
        ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
        ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
        mWin = win;
        mWin = win;
@@ -181,7 +182,9 @@ class InsetsSourceProvider {
     * window gets laid out.
     * window gets laid out.
     */
     */
    void updateSourceFrame() {
    void updateSourceFrame() {
        if (mWin == null) {
        if (mWin == null || mWin.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;
            return;
        }
        }


@@ -238,19 +241,45 @@ class InsetsSourceProvider {
            return;
            return;
        }
        }


        setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy()
        setServerVisible(mWin.wouldBeVisibleIfPolicyIgnored() && mWin.isVisibleByPolicy());
                && !mWin.mGivenInsetsPending);
        updateSourceFrame();
        updateSourceFrame();
        if (mControl != null) {
        if (mControl != null) {
            final Rect frame = mWin.getWindowFrames().mFrame;
            final Rect frame = mWin.getWindowFrames().mFrame;
            if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
            if (mControl.setSurfacePosition(frame.left, frame.top) && mControlTarget != null) {
                // The leash has been stale, we need to create a new one for the client.
                if (!mWin.getWindowFrames().didFrameSizeChange()) {
                updateControlForTarget(mControlTarget, true /* force */);
                    updateLeashPosition(frame, -1 /* frameNumber */);
                } else if (mWin.mInRelayout) {
                    updateLeashPosition(frame, mWin.getFrameNumber());
                } else {
                    mWin.mPendingPositionChanged = this;
                }
                mStateController.notifyControlChanged(mControlTarget);
                mStateController.notifyControlChanged(mControlTarget);
            }
            }
        }
        }
    }
    }


    void updateLeashPosition(Rect frame, long frameNumber) {
        if (mControl == null) {
            return;
        }
        final SurfaceControl leash = mControl.getLeash();
        if (leash != null) {
            final Transaction t = mDisplayContent.getPendingTransaction();
            Point position = new Point();
            mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
            t.setPosition(leash, position.x, position.y);
            deferTransactionUntil(t, leash, frameNumber);
        }
    }

    private void deferTransactionUntil(Transaction t, SurfaceControl leash, long frameNumber) {
        if (frameNumber >= 0) {
            final SurfaceControl barrier = mWin.getClientViewRootSurface();
            t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
            t.deferTransactionUntil(leash, barrier, frameNumber);
        }
    }

    /**
    /**
     * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
     * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
     */
     */
@@ -305,14 +334,12 @@ class InsetsSourceProvider {
        final SurfaceControl leash = mAdapter.mCapturedLeash;
        final SurfaceControl leash = mAdapter.mCapturedLeash;
        final long frameNumber = mFinishSeamlessRotateFrameNumber;
        final long frameNumber = mFinishSeamlessRotateFrameNumber;
        mFinishSeamlessRotateFrameNumber = -1;
        mFinishSeamlessRotateFrameNumber = -1;
        if (frameNumber >= 0 && mWin.mHasSurface && leash != null) {
        if (mWin.mHasSurface && leash != null) {
            // We just finished the seamless rotation. We don't want to change the position or the
            // We just finished the seamless rotation. We don't want to change the position or the
            // window crop of the surface controls (including the leash) until the client finishes
            // window crop of the surface controls (including the leash) until the client finishes
            // drawing the new frame of the new orientation. Although we cannot defer the reparent
            // drawing the new frame of the new orientation. Although we cannot defer the reparent
            // operation, it is fine, because reparent won't cause any visual effect.
            // operation, it is fine, because reparent won't cause any visual effect.
            final SurfaceControl barrier = mWin.getClientViewRootSurface();
            deferTransactionUntil(t, leash, frameNumber);
            t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
            t.deferTransactionUntil(leash, barrier, frameNumber);
        }
        }
        mControlTarget = target;
        mControlTarget = target;
        updateVisibility();
        updateVisibility();
+2 −0
Original line number Original line Diff line number Diff line
@@ -193,6 +193,8 @@ class InsetsStateController {
                state.removeSource(ITYPE_STATUS_BAR);
                state.removeSource(ITYPE_STATUS_BAR);
                state.removeSource(ITYPE_CLIMATE_BAR);
                state.removeSource(ITYPE_CLIMATE_BAR);
                state.removeSource(ITYPE_CAPTION_BAR);
                state.removeSource(ITYPE_CAPTION_BAR);
                state.removeSource(ITYPE_NAVIGATION_BAR);
                state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
            }
            }


            // Status bar doesn't get influenced by caption bar
            // Status bar doesn't get influenced by caption bar
+1 −1
Original line number Original line Diff line number Diff line
@@ -203,7 +203,7 @@ public class WindowFrames {
    /**
    /**
     * @return true if the width or height has changed since last reported to the client.
     * @return true if the width or height has changed since last reported to the client.
     */
     */
    private boolean didFrameSizeChange() {
    boolean didFrameSizeChange() {
        return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
        return (mLastFrame.width() != mFrame.width()) || (mLastFrame.height() != mFrame.height());
    }
    }


+5 −0
Original line number Original line Diff line number Diff line
@@ -2191,6 +2191,11 @@ public class WindowManagerService extends IWindowManager.Stub
                win.finishSeamlessRotation(false /* timeout */);
                win.finishSeamlessRotation(false /* timeout */);
            }
            }


            if (win.mPendingPositionChanged != null) {
                win.mPendingPositionChanged.updateLeashPosition(win.getFrame(), frameNumber);
                win.mPendingPositionChanged = null;
            }

            if (mUseBLASTSync && win.useBLASTSync()) {
            if (mUseBLASTSync && win.useBLASTSync()) {
                result |= RELAYOUT_RES_BLAST_SYNC;
                result |= RELAYOUT_RES_BLAST_SYNC;
            }
            }
Loading