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

Commit 9d44a22b authored by Jiaming Liu's avatar Jiaming Liu
Browse files

[Divider] Fix flicker when finishing dragging

This change ensures that the decor surface change happens after the
transition is finished. Before this change, the decor surface was moved
before the transition was sent to Shell, which caused a flicker when
finishing dragging because the decor surface was unboosted but the
TaskFragments bounds were not updated and the snapshots were still
displayed.

Bug: 327067596
Test: atest TransitionTests

Change-Id: I3286023767992ec762bc9459d3f6b2a746209930
parent df5244aa
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6879,7 +6879,7 @@ class Task extends TaskFragment {

        private void assignLayer(@NonNull SurfaceControl.Transaction t, int layer) {
            t.setLayer(mContainerSurface, layer);
            t.setVisibility(mContainerSurface, mOwnerTaskFragment.isVisible());
            t.setVisibility(mContainerSurface, mOwnerTaskFragment.isVisible() || mIsBoosted);
            for (int i = 0; i < mPendingClientTransactions.size(); i++) {
                t.merge(mPendingClientTransactions.get(i));
            }
+29 −0
Original line number Diff line number Diff line
@@ -236,6 +236,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
    @VisibleForTesting
    ArrayList<Runnable> mTransactionCompletedListeners = null;

    private ArrayList<Runnable> mTransitionEndedListeners = null;

    /** Custom activity-level animation options and callbacks. */
    private TransitionInfo.AnimationOptions mOverrideOptions;
    private IRemoteCallback mClientAnimationStartCallback = null;
@@ -1473,6 +1475,18 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        mController.mSnapshotController.onTransitionFinish(mType, mTargets);
        // Resume snapshot persist thread after snapshot controller analysis this transition.
        mController.updateAnimatingState();

        invokeTransitionEndedListeners();
    }

    private void invokeTransitionEndedListeners() {
        if (mTransitionEndedListeners == null) {
            return;
        }
        for (int i = 0; i < mTransitionEndedListeners.size(); i++) {
            mTransitionEndedListeners.get(i).run();
        }
        mTransitionEndedListeners = null;
    }

    private void commitConfigAtEndActivities() {
@@ -1584,6 +1598,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        // Syncengine abort will call through to onTransactionReady()
        mSyncEngine.abort(mSyncId);
        mController.dispatchLegacyAppTransitionCancelled();
        invokeTransitionEndedListeners();
    }

    /** Immediately moves this to playing even if it isn't started yet. */
@@ -1901,6 +1916,20 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener {
        mTransactionCompletedListeners.add(listener);
    }

    /**
     * Adds a listener that will be executed after the transition is finished or aborted.
     */
    void addTransitionEndedListener(Runnable listener) {
        if (mState != STATE_COLLECTING && mState != STATE_STARTED) {
            throw new IllegalStateException(
                    "Can't register listeners if the transition isn't collecting. state=" + mState);
        }
        if (mTransitionEndedListeners == null) {
            mTransitionEndedListeners = new ArrayList<>();
        }
        mTransitionEndedListeners.add(listener);
    }

    /**
     * Checks if the transition contains order changes.
     *
+20 −4
Original line number Diff line number Diff line
@@ -1613,6 +1613,10 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
            }
            case OP_TYPE_SET_DECOR_SURFACE_BOOSTED: {
                if (Flags.activityEmbeddingInteractiveDividerFlag()) {
                    final Task task = taskFragment.getTask();
                    if (task == null) {
                        break;
                    }
                    final SurfaceControl.Transaction clientTransaction =
                            operation.getSurfaceTransaction();
                    if (clientTransaction != null) {
@@ -1621,11 +1625,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
                        // any invalid operations.
                        clientTransaction.sanitize(caller.mPid, caller.mUid);
                    }
                    taskFragment.getTask().setDecorSurfaceBoosted(

                    if (transition != null) {
                        // The decor surface boost/unboost must happen after the transition is
                        // completed. Otherwise, the decor surface could be moved before Shell
                        // completes the transition, causing flicker.
                        transition.addTransitionEndedListener(() ->
                                task.setDecorSurfaceBoosted(
                                        taskFragment,
                                        operation.getBooleanValue() /* isBoosted */,
                                        clientTransaction));
                    } else {
                        task.setDecorSurfaceBoosted(
                                taskFragment,
                                operation.getBooleanValue() /* isBoosted */,
                                clientTransaction);
                    }
                }
                break;
            }
            case OP_TYPE_SET_PINNED: {
+27 −0
Original line number Diff line number Diff line
@@ -1445,6 +1445,33 @@ public class TransitionTests extends WindowTestsBase {
        assertTrue(activity1.mLaunchTaskBehind);
    }

    @Test
    public void testTransitionEndedListeners() {
        final TransitionController controller = new TestTransitionController(mAtm);
        controller.setSyncEngine(mWm.mSyncEngine);
        final ITransitionPlayer player = new ITransitionPlayer.Default();
        controller.registerTransitionPlayer(player, null /* playerProc */);
        final Runnable transitionEndedListener = mock(Runnable.class);

        final Transition transition1 = controller.createTransition(TRANSIT_OPEN);
        transition1.addTransitionEndedListener(transitionEndedListener);

        // Using abort to force-finish the sync (since we can't wait for drawing in unit test).
        // We didn't call abort on the transition itself, so it will still run onTransactionReady
        // normally.
        mWm.mSyncEngine.abort(transition1.getSyncId());
        transition1.finishTransition();

        verify(transitionEndedListener).run();

        clearInvocations(transitionEndedListener);

        final Transition transition2 = controller.createTransition(TRANSIT_OPEN);
        transition2.addTransitionEndedListener(transitionEndedListener);
        transition2.abort();
        verify(transitionEndedListener).run();
    }

    @Test
    public void testTransientLaunch() {
        spyOn(mWm.mSnapshotController.mTaskSnapshotController);