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

Commit 0a170d3d authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge "Always update layers when building a finish transaction" into main

parents c98ff04f e49011fb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4834,7 +4834,7 @@ class Task extends TaskFragment {
                        if (topActivity.mTransitionController.inFinishingTransition(topActivity)) {
                            final SurfaceControl.Transaction tx =
                                    taskDisplayArea.getPendingTransaction();
                            Transition.assignLayers(taskDisplayArea, tx);
                            Transition.assignLayersForStartTransaction(taskDisplayArea, tx);
                            final SurfaceControl leash = topActivity.getFixedRotationLeash();
                            if (leash != null) {
                                tx.setLayer(leash, topActivity.getLastLayer());
+18 −4
Original line number Diff line number Diff line
@@ -1190,7 +1190,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        // Need to update layers on involved displays since they were all paused while
        // the animation played. This puts the layers back into the correct order.
        for (int i = participantDisplays.length - 1; i >= 0; --i) {
            assignLayers(participantDisplays[i], t);
            assignLayersForFinishTransaction(participantDisplays[i], t);
        }

        for (int i = 0; i < info.getRootCount(); ++i) {
@@ -1198,13 +1198,27 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        }
    }

    /** Assigns the layers for the start or end state of transition. */
    static void assignLayers(WindowContainer<?> wc, SurfaceControl.Transaction t) {
    /** Assigns the layers for the start state of the transition. */
    static void assignLayersForStartTransaction(WindowContainer<?> wc,
            SurfaceControl.Transaction t) {
        wc.mTransitionController.mBuildingTransitionLayers = true;
        try {
            wc.assignChildLayers(t);
        } finally {
            wc.mTransitionController.mBuildingTransitionLayers = false;
        }
    }

    /** Assigns the layers for the end state of transition. */
    static void assignLayersForFinishTransaction(WindowContainer<?> wc,
            SurfaceControl.Transaction t) {
        wc.mTransitionController.mBuildingTransitionLayers = true;
        wc.mTransitionController.mBuildingFinishLayers = true;
        try {
            wc.assignChildLayers(t);
        } finally {
            wc.mTransitionController.mBuildingFinishLayers = false;
            wc.mTransitionController.mBuildingTransitionLayers = false;
        }
    }

@@ -2986,7 +3000,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
            rootLeash.setUnreleasedWarningCallSite("Transition.calculateTransitionRoots");
            // Update layers to start transaction because we prevent assignment during collect, so
            // the layer of transition root can be correct.
            assignLayers(dc, startT);
            assignLayersForStartTransaction(dc, startT);
            startT.setLayer(rootLeash, leashReference.getLastLayer());
            outInfo.addRootLeash(endDisplayId, rootLeash,
                    ancestor.getBounds().left, ancestor.getBounds().top);
+10 −4
Original line number Diff line number Diff line
@@ -213,10 +213,16 @@ class TransitionController {
    final SparseArray<ArrayList<Task>> mLatestOnTopTasksReported = new SparseArray<>();

    /**
     * `true` when building surface layer order for the finish transaction. We want to prevent
     * `true` when building surface layer order for the start/finish transaction. We want to prevent
     * wm from touching z-order of surfaces during transitions, but we still need to be able to
     * calculate the layers for the finishTransaction. So, when assigning layers into the finish
     * transaction, set this to true so that the {@link canAssignLayers} will allow it.
     * calculate the layers. So, when assigning layers into the start/finish transaction, set this
     * to true so that the {@link canAssignLayers} will allow it.
     */
    boolean mBuildingTransitionLayers = false;

    /**
     * `true` when building surface layer order for the finish transaction. We use this to
     * force-assign layers to the finish transaction {@link WindowContainer#assignLayer()}.
     */
    boolean mBuildingFinishLayers = false;

@@ -686,7 +692,7 @@ class TransitionController {
    boolean canAssignLayers(@NonNull WindowContainer wc) {
        // Don't build window state into finish transaction in case another window is added or
        // removed during transition playing.
        if (mBuildingFinishLayers) {
        if (mBuildingTransitionLayers) {
            return wc.asWindowState() == null;
        }
        // Always allow WindowState to assign layers since it won't affect transition.
+16 −5
Original line number Diff line number Diff line
@@ -2677,13 +2677,20 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        return true;
    }

    /**
     * Assigns the layer for this container in the given transaction.  The assignment only happens
     * if the current state allows assigning layers (ie. outside of a transition) and if the layers
     * have changed since they were last set, or if we are explicitly building the finish
     * transaction for a transition.
     */
    void assignLayer(Transaction t, int layer) {
        // Don't assign layers while a transition animation is playing
        // TODO(b/173528115): establish robust best-practices around z-order fighting.
        if (!mTransitionController.canAssignLayers(this)) return;
        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
        if (mSurfaceControl != null && changed) {
            if (mSyncState != SYNC_STATE_NONE) {
        final boolean layersChanged = layer != mLastLayer || mLastRelativeToLayer != null;
        final boolean forceUpdate = mTransitionController.mBuildingFinishLayers;
        if (mSurfaceControl != null && (layersChanged || forceUpdate)) {
            if (mSyncState != SYNC_STATE_NONE && !forceUpdate) {
                // When this container needs to be synced, assign layer with its own sync
                // transaction to avoid out of ordering when merge.
                // Still use the passed-in transaction for non-sync case, such as building finish
@@ -2696,10 +2703,14 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
        }
    }

    /**
     * Assigns the a relative layer for this container in the given transaction.  The assignment
     * only happens if the layers have changed since they were last set.
     */
    void assignRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer,
            boolean forceUpdate) {
        final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
        if (mSurfaceControl != null && (changed || forceUpdate)) {
        final boolean layersChanged = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
        if (mSurfaceControl != null && (layersChanged || forceUpdate)) {
            if (mSyncState != SYNC_STATE_NONE) {
                // When this container needs to be synced, assign layer with its own sync
                // transaction to avoid out of ordering when merge.
+51 −11
Original line number Diff line number Diff line
@@ -1141,29 +1141,69 @@ public class WindowContainerTests extends WindowTestsBase {
        verify(win).clearFrozenInsetsState();
    }

    @Test
    public void testAssignLayer() {
        final WindowContainer container = new WindowContainer(mWm);
        container.mSurfaceControl = mock(SurfaceControl.class);

        // Trigger layer call with a pending transaction, verify layer set
        container.assignLayer(mTransaction, 1 /* layer */);
        verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */);

        // Trigger layer call with a pending transaction, verify layer not set
        clearInvocations(mTransaction);
        container.assignLayer(mTransaction, 1 /* layer */);
        verify(mTransaction, never()).setLayer(container.mSurfaceControl, 1 /* layer */);

        // Trigger layer call while building a (non-finish) transition transaction, verify layer
        // not set
        container.mTransitionController.mBuildingTransitionLayers = true;
        clearInvocations(mTransaction);
        container.assignLayer(mTransaction, 1 /* layer */);
        verify(mTransaction, never()).setLayer(container.mSurfaceControl, 1 /* layer */);
        container.mTransitionController.mBuildingTransitionLayers = false;

        // Trigger layer call while building a finish transition transaction, verify layer set
        container.mTransitionController.mBuildingTransitionLayers = true;
        container.mTransitionController.mBuildingFinishLayers = true;
        clearInvocations(mTransaction);
        container.assignLayer(mTransaction, 1 /* layer */);
        verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */);
        container.mTransitionController.mBuildingTransitionLayers = false;
        container.mTransitionController.mBuildingFinishLayers = false;

        // Trigger another layer call while building a finish transition transaction, verify layer
        // set
        container.mTransitionController.mBuildingTransitionLayers = true;
        container.mTransitionController.mBuildingFinishLayers = true;
        clearInvocations(mTransaction);
        container.assignLayer(mTransaction, 1 /* layer */);
        verify(mTransaction).setLayer(container.mSurfaceControl, 1 /* layer */);
        container.mTransitionController.mBuildingTransitionLayers = false;
        container.mTransitionController.mBuildingFinishLayers = false;
    }

    @Test
    public void testAssignRelativeLayer() {
        final WindowContainer container = new WindowContainer(mWm);
        container.mSurfaceControl = mock(SurfaceControl.class);
        spyOn(container);
        doReturn(mTransaction).when(container).getPendingTransaction();
        doReturn(mTransaction).when(container).getSyncTransaction();
        final SurfaceAnimator surfaceAnimator = container.mSurfaceAnimator;
        final SurfaceControl relativeParent = mock(SurfaceControl.class);
        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
        spyOn(container);
        final SurfaceControl.Transaction otherTx = mock(SurfaceControl.Transaction.class);
        spyOn(surfaceAnimator);
        doReturn(t).when(container).getSyncTransaction();

        // Trigger for first relative layer call.
        container.assignRelativeLayer(t, relativeParent, 1 /* layer */);
        verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
        container.assignRelativeLayer(mTransaction, relativeParent, 1 /* layer */);
        verify(surfaceAnimator).setRelativeLayer(mTransaction, relativeParent, 1 /* layer */);

        // Not trigger for the same relative layer call.
        clearInvocations(surfaceAnimator);
        container.assignRelativeLayer(t, relativeParent, 1 /* layer */);
        verify(surfaceAnimator, never()).setRelativeLayer(t, relativeParent, 1 /* layer */);

        // Trigger for the same relative layer call if forceUpdate=true
        container.assignRelativeLayer(t, relativeParent, 1 /* layer */, true /* forceUpdate */);
        verify(surfaceAnimator).setRelativeLayer(t, relativeParent, 1 /* layer */);
        container.assignRelativeLayer(mTransaction, relativeParent, 1 /* layer */);
        verify(surfaceAnimator, never()).setRelativeLayer(mTransaction, relativeParent,
                1 /* layer */);
    }

    @Test