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

Commit 9d6123ae authored by wilsonshih's avatar wilsonshih
Browse files

Correct the pair-to-pair transition animation

...by cache live tile tasks while enter recents.

For normal pair-to-pair switch, evict live tile tasks in finish
transaction, so the task won't suddely become fullscreen task, which
break the recents animation. This also fix an issue that previous task
will occluding the live tile task after doing pair-to-pair switch, which
was because there didn't evict task after start new task, and the
pending enter transition was consumed in StageCoordinator.

For mixed transition case(pair-to-pair + display change), the live tile
tasks will be evict when process pending enter animation.

Bug: 275349333
Bug: 280742823
Test: atest SwitchBetweenSplitPairs
Test: atest SplitTransitionTests
Test: atest TaplTestsTaskbar
Test: compose a split pair then enter recents, cancel recents, verify
nothing change.
Test: Compose 2 split pair, do pair-to-pair switch several times,
verify both pair won't be dismissed as standalone task in recents.
Test: compose 2 split pair, enter recents, rotate device, do
pair-to-pair switch, verify the result after mixed animation is
correct, and each pair won't be dismissed.

Change-Id: Iea415a29a8ed9573c7852a9f42b1c07fbe120df9
parent af4534f6
Loading
Loading
Loading
Loading
+59 −2
Original line number Diff line number Diff line
@@ -192,6 +192,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    private final SplitScreenTransitions mSplitTransitions;
    private final SplitscreenEventLogger mLogger;
    private final ShellExecutor mMainExecutor;
    // Cache live tile tasks while entering recents, evict them from stages in finish transaction
    // if user is opening another task(s).
    private final ArrayList<Integer> mPausingTasks = new ArrayList<>();
    private final Optional<RecentTasksController> mRecentTasks;

    private final Rect mTempRect1 = new Rect();
@@ -658,6 +661,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        // Add task launch requests
        wct.startTask(mainTaskId, mainOptions);

        // leave recents animation by re-start pausing tasks
        if (mPausingTasks.contains(mainTaskId)) {
            mPausingTasks.clear();
        }
        mSplitTransitions.startEnterTransition(
                TRANSIT_TO_FRONT, wct, remoteTransition, this, null, null,
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
@@ -1630,7 +1637,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    }

    private void updateRecentTasksSplitPair() {
        if (!mShouldUpdateRecents) {
        // Preventing from single task update while processing recents.
        if (!mShouldUpdateRecents || !mPausingTasks.isEmpty()) {
            return;
        }
        mRecentTasks.ifPresent(recentTasks -> {
@@ -2582,6 +2590,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            final TransitionInfo.Change change = info.getChanges().get(iC);
            final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
            if (taskInfo == null || !taskInfo.hasParentTask()) continue;
            if (mPausingTasks.contains(taskInfo.taskId)) {
                continue;
            }
            final @StageType int stageType = getStageType(getStageOfTask(taskInfo));
            if (stageType == STAGE_TYPE_MAIN
                    && (isOpeningType(change.getMode()) || change.getMode() == TRANSIT_CHANGE)) {
@@ -2654,6 +2665,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                mShowDecorImmediately = true;
                mSplitLayout.flingDividerToCenter();
            }
            mPausingTasks.clear();
        });

        finishEnterSplitScreen(finishT);
@@ -2811,12 +2823,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

    /** Call this when starting the open-recents animation while split-screen is active. */
    public void onRecentsInSplitAnimationStart(TransitionInfo info) {
        if (isSplitScreenVisible()) {
            // Cache tasks on live tile.
            for (int i = 0; i < info.getChanges().size(); ++i) {
                final TransitionInfo.Change change = info.getChanges().get(i);
                if (TransitionUtil.isClosingType(change.getMode())
                        && change.getTaskInfo() != null) {
                    final int taskId = change.getTaskInfo().taskId;
                    if (mMainStage.getTopVisibleChildTaskId() == taskId
                            || mSideStage.getTopVisibleChildTaskId() == taskId) {
                        mPausingTasks.add(taskId);
                    }
                }
            }
        }

        addDividerBarToTransition(info, false /* show */);
    }

    /** Call this when the recents animation canceled during split-screen. */
    public void onRecentsInSplitAnimationCanceled() {
        mPausingTasks.clear();
    }

    /** Call this when the recents animation during split-screen finishes. */
    public void onRecentsInSplitAnimationFinish(WindowContainerTransaction finishWct,
            SurfaceControl.Transaction finishT, TransitionInfo info) {
            SurfaceControl.Transaction finishT) {
        mPausingTasks.clear();
        // Check if the recent transition is finished by returning to the current
        // split, so we can restore the divider bar.
        for (int i = 0; i < finishWct.getHierarchyOps().size(); ++i) {
@@ -2840,6 +2873,27 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        logExit(EXIT_REASON_UNKNOWN);
    }

    /** Call this when the recents animation finishes by doing pair-to-pair switch. */
    public void onRecentsPairToPairAnimationFinish(WindowContainerTransaction finishWct) {
        // Pair-to-pair switch happened so here should evict the live tile from its stage.
        // Otherwise, the task will remain in stage, and occluding the new task when next time
        // user entering recents.
        for (int i = mPausingTasks.size() - 1; i >= 0; --i) {
            final int taskId = mPausingTasks.get(i);
            if (mMainStage.containsTask(taskId)) {
                mMainStage.evictChildren(finishWct, taskId);
            } else if (mSideStage.containsTask(taskId)) {
                mSideStage.evictChildren(finishWct, taskId);
            }
        }
        // If pending enter hasn't consumed, the mix handler will invoke start pending
        // animation within following transition.
        if (mSplitTransitions.mPendingEnter == null) {
            mPausingTasks.clear();
            updateRecentTasksSplitPair();
        }
    }

    private void addDividerBarToTransition(@NonNull TransitionInfo info, boolean show) {
        final SurfaceControl leash = mSplitLayout.getDividerLeash();
        if (leash == null || !leash.isValid()) {
@@ -2892,6 +2946,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            pw.println(innerPrefix + "SplitLayout");
            mSplitLayout.dump(pw, childPrefix);
        }
        if (!mPausingTasks.isEmpty()) {
            pw.println(childPrefix + "mPausingTasks=" + mPausingTasks);
        }
    }

    /**
+7 −0
Original line number Diff line number Diff line
@@ -377,6 +377,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
        }
    }

    void evictChildren(WindowContainerTransaction wct, int taskId) {
        final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId);
        if (taskInfo != null) {
            wct.reparent(taskInfo.token, null /* parent */, false /* onTop */);
        }
    }

    void reparentTopTask(WindowContainerTransaction wct) {
        wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token,
                CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES,
+6 −2
Original line number Diff line number Diff line
@@ -540,9 +540,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
            mixed.mInFlightSubAnimations = 0;
            mActiveTransitions.remove(mixed);
            // If pair-to-pair switching, the post-recents clean-up isn't needed.
            if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) {
            wct = wct != null ? wct : new WindowContainerTransaction();
                mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction, info);
            if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) {
                mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction);
            } else {
                // notify pair-to-pair recents animation finish
                mSplitHandler.onRecentsPairToPairAnimationFinish(wct);
            }
            mSplitHandler.onTransitionAnimationComplete();
            finishCallback.onTransitionFinished(wct, wctCB);
@@ -552,6 +555,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
        final boolean handled = mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info,
                startTransaction, finishTransaction, finishCB);
        if (!handled) {
            mSplitHandler.onRecentsInSplitAnimationCanceled();
            mActiveTransitions.remove(mixed);
        }
        return handled;
+2 −2
Original line number Diff line number Diff line
@@ -283,7 +283,7 @@ public class SplitTransitionTests extends ShellTestCase {
        // Make sure it cleans-up if recents doesn't restore
        WindowContainerTransaction commitWCT = new WindowContainerTransaction();
        mStageCoordinator.onRecentsInSplitAnimationFinish(commitWCT,
                mock(SurfaceControl.Transaction.class), mock(TransitionInfo.class));
                mock(SurfaceControl.Transaction.class));
        assertFalse(mStageCoordinator.isSplitScreenVisible());
    }

@@ -322,7 +322,7 @@ public class SplitTransitionTests extends ShellTestCase {
        mMainStage.onTaskAppeared(mMainChild, mock(SurfaceControl.class));
        mSideStage.onTaskAppeared(mSideChild, mock(SurfaceControl.class));
        mStageCoordinator.onRecentsInSplitAnimationFinish(restoreWCT,
                mock(SurfaceControl.Transaction.class), mock(TransitionInfo.class));
                mock(SurfaceControl.Transaction.class));
        assertTrue(mStageCoordinator.isSplitScreenVisible());
    }