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

Commit 932814a0 authored by Robert Carr's avatar Robert Carr Committed by Tiger Huang
Browse files

WindowState: Introduce applyWithNextDraw, port Seamless Rotation

While BLASTSyncEngine is a good primitive for syncing changes to
multiple window containers, it's complexity introduces constraints,
namely that only one BLASTSyncEngine sync may be active at a time (for
a given window container). As more and more parts of the WM wish to rely
on BLASTSync, this can create a difficult coordination problem. In this
CL we expose a per WindowState sync mechanism (applyWithNextDraw) which
can compose with BLASTSyncEngine transactions, and can be used by
multiple features simultaneously on a given WindowState.

This system works by maintaining a list of "DrawHandlers"
(Consumer<Transaction>), in each WindowState. At a high level, when
adding a draw handler we request the client to redraw, and when
we receive the Transaction containing the frame in finishDrawing
we invoke the handler, giving it a chance to append to the transaction
before it is applied or merged in to a higher level BLASTSyncEngine
transaction.

Next we port seamless rotation to this system. The concept is relatively
easy, the setup proceeds as before: In the same transaction we rotate
the display projection we create a SeamlessRotator to unrotate the apps
original orientation buffer. Seamless rotation requires us to remove
this transform when the app redraws, and this is trivially accomplished
with the applyWithNextDraw primitive.

Bug: 168505645
Bug: 181424834
Test: Existing tests pass
Change-Id: Ie84d99e58b8d0efedbedab0ea48a441826e3a7bf
parent 9a2ae3ed
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -131,7 +131,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
@@ -1811,11 +1810,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            w.mReportOrientationChanged = true;
        }, true /* traverseTopToBottom */);

        if (rotateSeamlessly) {
            mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
                    this, SEAMLESS_ROTATION_TIMEOUT_DURATION);
        }

        for (int i = mWmService.mRotationWatchers.size() - 1; i >= 0; i--) {
            final WindowManagerService.RotationWatcher rotationWatcher
                    = mWmService.mRotationWatchers.get(i);
+1 −19
Original line number Diff line number Diff line
@@ -567,7 +567,7 @@ public class DisplayRotation {
        }
        mDisplayContent.forAllWindows(w -> {
            if (w.mSeamlesslyRotated) {
                w.finishSeamlessRotation(false /* timeout */);
                w.cancelSeamlessRotation();
                w.mSeamlesslyRotated = false;
            }
        }, true /* traverseTopToBottom */);
@@ -670,24 +670,6 @@ public class DisplayRotation {
        }
    }

    void onSeamlessRotationTimeout() {
        final boolean[] isLayoutNeeded = { false };

        mDisplayContent.forAllWindows(w -> {
            if (!w.mSeamlesslyRotated) {
                return;
            }
            isLayoutNeeded[0] = true;
            w.setDisplayLayoutNeeded();
            w.finishSeamlessRotation(true /* timeout */);
            markForSeamlessRotation(w, false /* seamlesslyRotated */);
        }, true /* traverseTopToBottom */);

        if (isLayoutNeeded[0]) {
            mService.mWindowPlacerLocked.performSurfacePlacement();
        }
    }

    /**
     * Returns the animation to run for a rotation transition based on the top fullscreen windows
     * {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently
+6 −22
Original line number Diff line number Diff line
@@ -93,7 +93,6 @@ class InsetsSourceProvider {
    private boolean mServerVisible;

    private boolean mSeamlessRotating;
    private long mFinishSeamlessRotateFrameNumber = -1;

    private final boolean mControllable;

@@ -342,15 +341,6 @@ class InsetsSourceProvider {
        mIsLeashReadyForDispatching = false;

        final SurfaceControl leash = mAdapter.mCapturedLeash;
        final long frameNumber = mFinishSeamlessRotateFrameNumber;
        mFinishSeamlessRotateFrameNumber = -1;
        if (mWin.mHasSurface && leash != null) {
            // 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
            // 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.
            deferTransactionUntil(t, leash, frameNumber);
        }
        mControlTarget = target;
        updateVisibility();
        mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition);
@@ -361,17 +351,12 @@ class InsetsSourceProvider {
    void startSeamlessRotation() {
      if (!mSeamlessRotating) {
          mSeamlessRotating = true;

            // This will revoke the leash and clear the control target.
          mWin.cancelAnimation();
      }
    }

    void finishSeamlessRotation(boolean timeout) {
        if (mSeamlessRotating) {
    void finishSeamlessRotation() {
        mSeamlessRotating = false;
            mFinishSeamlessRotateFrameNumber = timeout ? -1 : mWin.getFrameNumber();
        }
    }

    boolean updateClientVisibility(InsetsControlTarget caller) {
@@ -529,7 +514,6 @@ class InsetsSourceProvider {
        proto.write(CLIENT_VISIBLE, mClientVisible);
        proto.write(SERVER_VISIBLE, mServerVisible);
        proto.write(SEAMLESS_ROTATING, mSeamlessRotating);
        proto.write(FINISH_SEAMLESS_ROTATE_FRAME_NUMBER, mFinishSeamlessRotateFrameNumber);
        proto.write(CONTROLLABLE, mControllable);
        proto.end(token);
    }
+0 −18
Original line number Diff line number Diff line
@@ -35,9 +35,6 @@ import java.io.StringWriter;
 * Helper class for seamless rotation.
 *
 * Works by transforming the {@link WindowState} back into the old display rotation.
 *
 * Uses {@link Transaction#deferTransactionUntil(SurfaceControl, IBinder, long)} instead of
 * latching on the buffer size to allow for seamless 180 degree rotations.
 */
public class SeamlessRotator {

@@ -103,22 +100,7 @@ public class SeamlessRotator {
     * Removing the transform and the result of the {@link WindowState} layout are both tied to the
     * {@link WindowState} next frame, such that they apply at the same time the client draws the
     * window in the new orientation.
     *
     * In the case of a rotation timeout, we want to remove the transform immediately and not defer
     * it.
     */
    public void finish(WindowState win, boolean timeout) {
        final Transaction t = win.getPendingTransaction();
        finish(t, win);
        if (win.mWinAnimator.mSurfaceController != null && !timeout) {
            t.deferTransactionUntil(win.mSurfaceControl,
                    win.getClientViewRootSurface(), win.getFrameNumber());
            t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
                    win.getClientViewRootSurface(), win.getFrameNumber());
        }
    }

    /** Removes the transform and restore to the original last position. */
    void finish(Transaction t, WindowContainer win) {
        mTransform.reset();
        t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
+1 −14
Original line number Diff line number Diff line
@@ -367,9 +367,6 @@ public class WindowManagerService extends IWindowManager.Stub
    /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
    static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;

    /** Amount of time (in milliseconds) to delay before declaring a seamless rotation timeout. */
    static final int SEAMLESS_ROTATION_TIMEOUT_DURATION = 2000;

    /** Amount of time (in milliseconds) to delay before declaring a window replacement timeout. */
    static final int WINDOW_REPLACEMENT_TIMEOUT_DURATION = 2000;

@@ -2245,9 +2242,6 @@ public class WindowManagerService extends IWindowManager.Stub
            win.setFrameNumber(frameNumber);

            final DisplayContent dc = win.getDisplayContent();
            if (!dc.mWaitingForConfig) {
                win.finishSeamlessRotation(false /* timeout */);
            }

            if (win.mPendingPositionChanged != null) {
                win.mPendingPositionChanged.updateLeashPosition(frameNumber);
@@ -2255,6 +2249,7 @@ public class WindowManagerService extends IWindowManager.Stub
            }

            if (mUseBLASTSync && win.useBLASTSync() && viewVisibility != View.GONE) {
                win.prepareDrawHandlers();
                result |= RELAYOUT_RES_BLAST_SYNC;
            }

@@ -5080,7 +5075,6 @@ public class WindowManagerService extends IWindowManager.Stub

        public static final int UPDATE_ANIMATION_SCALE = 51;
        public static final int WINDOW_HIDE_TIMEOUT = 52;
        public static final int SEAMLESS_ROTATION_TIMEOUT = 54;
        public static final int RESTORE_POINTER_ICON = 55;
        public static final int SET_HAS_OVERLAY_UI = 58;
        public static final int ANIMATION_FAILSAFE = 60;
@@ -5363,13 +5357,6 @@ public class WindowManagerService extends IWindowManager.Stub
                    }
                    break;
                }
                case SEAMLESS_ROTATION_TIMEOUT: {
                    final DisplayContent displayContent = (DisplayContent) msg.obj;
                    synchronized (mGlobalLock) {
                        displayContent.getDisplayRotation().onSeamlessRotationTimeout();
                    }
                    break;
                }
                case SET_HAS_OVERLAY_UI: {
                    mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1);
                    break;
Loading