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

Commit 57c6a311 authored by Jerry Chang's avatar Jerry Chang
Browse files

Consolidate drag to split gesture with shell transition

Refine SplitScreenTransitions with TransitionCallback to consolidate
transition handling logic.

1. Support to replace previous pairing app with drag-to-split gesture.
2. Support to switch split position by drag and drop a single-instance
   app to another side of the split.

Fix: 236814427
Fix: 236814471
Test: atest WMShellUnitTests
Test: enable shell transition, enter split screen, verified
      1. drag and drop gesture can replace apps in split
      2. drag and drop single-instance app to another side switch
	 split position
      3. quick switch and overview switch works as expected

Change-Id: Icde96369b79947e93a53ac589e64201aa32cf337
parent 6a6b2bb5
Loading
Loading
Loading
Loading
+19 −41
Original line number Original line Diff line number Diff line
@@ -352,15 +352,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,


    public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
    public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
            @SplitPosition int position, @Nullable Bundle options) {
            @SplitPosition int position, @Nullable Bundle options) {
        if (!ENABLE_SHELL_TRANSITIONS) {
            startIntentLegacy(intent, fillInIntent, position, options);
            return;
        }

        try {
            options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
                    null /* wct */);

        if (fillInIntent == null) {
        if (fillInIntent == null) {
            fillInIntent = new Intent();
            fillInIntent = new Intent();
        }
        }
@@ -376,17 +367,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
        }
        }


            intent.send(mContext, 0, fillInIntent, null /* onFinished */, null /* handler */,
        if (!ENABLE_SHELL_TRANSITIONS) {
                    null /* requiredPermission */, options);
            startIntentLegacy(intent, fillInIntent, position, options);
        } catch (PendingIntent.CanceledException e) {
            return;
            Slog.e(TAG, "Failed to launch task", e);
        }
        }

        mStageCoordinator.startIntent(intent, fillInIntent, position, options);
    }
    }


    private void startIntentLegacy(PendingIntent intent, @Nullable Intent fillInIntent,
    private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
            @SplitPosition int position, @Nullable Bundle options) {
            @SplitPosition int position, @Nullable Bundle options) {
        boolean startSameActivityAdjacently = isLaunchingAdjacently(intent.getIntent(), position);

        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        mStageCoordinator.prepareEvictChildTasks(position, evictWct);
        mStageCoordinator.prepareEvictChildTasks(position, evictWct);


@@ -397,8 +387,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
                    IRemoteAnimationFinishedCallback finishedCallback,
                    IRemoteAnimationFinishedCallback finishedCallback,
                    SurfaceControl.Transaction t) {
                    SurfaceControl.Transaction t) {
                if (apps == null || apps.length == 0) {
                if (apps == null || apps.length == 0) {
                    if (startSameActivityAdjacently) {
                    // Switch the split position if launching as MULTIPLE_TASK failed.
                        // Switch split position if dragging the same activity to another side.
                    if ((fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                        setSideStagePosition(SplitLayout.reversePosition(
                        setSideStagePosition(SplitLayout.reversePosition(
                                mStageCoordinator.getSideStagePosition()));
                                mStageCoordinator.getSideStagePosition()));
                    }
                    }
@@ -432,18 +422,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
        options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);


        // Flag this as a no-user-action launch to prevent sending user leaving event to the current
        // top activity since it's going to be put into another side of the split. This prevents the
        // current top activity from going into pip mode due to user leaving event.
        if (fillInIntent == null) {
            fillInIntent = new Intent();
        }
        fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
        if (startSameActivityAdjacently) {
            fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
        }

        wct.sendPendingIntent(intent, fillInIntent, options);
        wct.sendPendingIntent(intent, fillInIntent, options);
        mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
        mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
    }
    }
+108 −33
Original line number Original line Diff line number Diff line
@@ -62,13 +62,12 @@ class SplitScreenTransitions {
    private final Runnable mOnFinish;
    private final Runnable mOnFinish;


    DismissTransition mPendingDismiss = null;
    DismissTransition mPendingDismiss = null;
    IBinder mPendingEnter = null;
    TransitSession mPendingEnter = null;
    IBinder mPendingRecent = null;
    TransitSession mPendingRecent = null;


    private IBinder mAnimatingTransition = null;
    private IBinder mAnimatingTransition = null;
    OneShotRemoteHandler mPendingRemoteHandler = null;
    OneShotRemoteHandler mPendingRemoteHandler = null;
    private OneShotRemoteHandler mActiveRemoteHandler = null;
    private OneShotRemoteHandler mActiveRemoteHandler = null;
    private boolean mEnterTransitionMerged;


    private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
    private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;


@@ -145,7 +144,7 @@ class SplitScreenTransitions {
                continue;
                continue;
            }
            }


            if (transition == mPendingEnter && (mainRoot.equals(change.getContainer())
            if (isPendingEnter(transition) && (mainRoot.equals(change.getContainer())
                    || sideRoot.equals(change.getContainer()))) {
                    || sideRoot.equals(change.getContainer()))) {
                t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
                t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
                t.setWindowCrop(leash, change.getEndAbsBounds().width(),
                t.setWindowCrop(leash, change.getEndAbsBounds().width(),
@@ -171,12 +170,40 @@ class SplitScreenTransitions {
        onFinish(null /* wct */, null /* wctCB */);
        onFinish(null /* wct */, null /* wctCB */);
    }
    }


    boolean isPendingTransition(IBinder transition) {
        return isPendingEnter(transition)
                || isPendingDismiss(transition)
                || isPendingRecent(transition);
    }

    boolean isPendingEnter(IBinder transition) {
        return mPendingEnter != null && mPendingEnter.mTransition == transition;
    }

    boolean isPendingRecent(IBinder transition) {
        return mPendingRecent != null && mPendingRecent.mTransition == transition;
    }

    boolean isPendingDismiss(IBinder transition) {
        return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
    }

    /** Starts a transition to enter split with a remote transition animator. */
    /** Starts a transition to enter split with a remote transition animator. */
    IBinder startEnterTransition(@WindowManager.TransitionType int transitType,
    IBinder startEnterTransition(
            @NonNull WindowContainerTransaction wct, @Nullable RemoteTransition remoteTransition,
            @WindowManager.TransitionType int transitType,
            @NonNull Transitions.TransitionHandler handler) {
            WindowContainerTransaction wct,
            @Nullable RemoteTransition remoteTransition,
            Transitions.TransitionHandler handler,
            @Nullable TransitionCallback callback) {
        final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
        final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
        mPendingEnter = transition;
        setEnterTransition(transition, remoteTransition, callback);
        return transition;
    }

    /** Sets a transition to enter split. */
    void setEnterTransition(@NonNull IBinder transition,
            @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) {
        mPendingEnter = new TransitSession(transition, callback);


        if (remoteTransition != null) {
        if (remoteTransition != null) {
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -184,7 +211,9 @@ class SplitScreenTransitions {
                    mTransitions.getMainExecutor(), remoteTransition);
                    mTransitions.getMainExecutor(), remoteTransition);
            mPendingRemoteHandler.setTransition(transition);
            mPendingRemoteHandler.setTransition(transition);
        }
        }
        return transition;

        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "  splitTransition "
                + " deduced Enter split screen");
    }
    }


    /** Starts a transition to dismiss split. */
    /** Starts a transition to dismiss split. */
@@ -209,8 +238,8 @@ class SplitScreenTransitions {
    }
    }


    void setRecentTransition(@NonNull IBinder transition,
    void setRecentTransition(@NonNull IBinder transition,
            @Nullable RemoteTransition remoteTransition) {
            @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) {
        mPendingRecent = transition;
        mPendingRecent = new TransitSession(transition, callback);


        if (remoteTransition != null) {
        if (remoteTransition != null) {
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -226,6 +255,18 @@ class SplitScreenTransitions {
    void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
    void mergeAnimation(IBinder transition, TransitionInfo info, SurfaceControl.Transaction t,
            IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
            IBinder mergeTarget, Transitions.TransitionFinishCallback finishCallback) {
        if (mergeTarget != mAnimatingTransition) return;
        if (mergeTarget != mAnimatingTransition) return;

        if (isPendingEnter(transition) && isPendingRecent(mergeTarget)) {
            mPendingRecent.mCallback = new TransitionCallback() {
                @Override
                public void onTransitionFinished(WindowContainerTransaction finishWct,
                        SurfaceControl.Transaction finishT) {
                    // Since there's an entering transition merged, recent transition no longer
                    // need to handle entering split screen after the transition finished.
                }
            };
        }

        if (mActiveRemoteHandler != null) {
        if (mActiveRemoteHandler != null) {
            mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
            mActiveRemoteHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
        } else {
        } else {
@@ -247,38 +288,55 @@ class SplitScreenTransitions {
    }
    }


    void onTransitionConsumed(@NonNull IBinder transition, boolean aborted) {
    void onTransitionConsumed(@NonNull IBinder transition, boolean aborted) {
        if (aborted) return;
        if (isPendingEnter(transition)) {

            if (!aborted) {
        // Once a pending enter transition got merged, make sure to append the reset of finishing
                // An enter transition got merged, appends the rest operations to finish entering
        // operations to the finish transition.
                // split screen.
        if (transition == mPendingEnter) {
                // TODO (b/238856352): Passed-in the proper finish transition to merge instead.
                if (mFinishTransaction == null) {
                    mFinishTransaction = mTransactionPool.acquire();
                    mFinishTransaction = mTransactionPool.acquire();
                }
                mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
                mStageCoordinator.finishEnterSplitScreen(mFinishTransaction);
            }

            mPendingEnter.mCallback.onTransitionConsumed(aborted);
            mPendingEnter = null;
            mPendingEnter = null;
            mPendingRemoteHandler = null;
            mPendingRemoteHandler = null;
            mEnterTransitionMerged = true;
        } else if (isPendingDismiss(transition)) {
            mPendingDismiss.mCallback.onTransitionConsumed(aborted);
            mPendingDismiss = null;
        } else if (isPendingRecent(transition)) {
            mPendingRecent.mCallback.onTransitionConsumed(aborted);
            mPendingRecent = null;
            mPendingRemoteHandler = null;
        }
        }
    }
    }


    void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
    void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
        if (!mAnimations.isEmpty()) return;
        if (!mAnimations.isEmpty()) return;
        if (mAnimatingTransition == mPendingEnter) {

        TransitionCallback callback = null;
        if (isPendingEnter(mAnimatingTransition)) {
            callback = mPendingEnter.mCallback;
            mPendingEnter = null;
            mPendingEnter = null;
        }
        }
        if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
        if (isPendingDismiss(mAnimatingTransition)) {
            callback = mPendingDismiss.mCallback;
            mPendingDismiss = null;
            mPendingDismiss = null;
        }
        }
        if (mAnimatingTransition == mPendingRecent) {
        if (isPendingRecent(mAnimatingTransition)) {
            if (!mEnterTransitionMerged) {
            callback = mPendingRecent.mCallback;
                if (wct == null) wct = new WindowContainerTransaction();
                mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction);
            }
            mPendingRecent = null;
            mPendingRecent = null;
        }
        }

        if (callback != null) {
            if (wct == null) wct = new WindowContainerTransaction();
            callback.onTransitionFinished(wct, mFinishTransaction);
        }

        mPendingRemoteHandler = null;
        mPendingRemoteHandler = null;
        mActiveRemoteHandler = null;
        mActiveRemoteHandler = null;
        mAnimatingTransition = null;
        mAnimatingTransition = null;
        mEnterTransitionMerged = false;


        mOnFinish.run();
        mOnFinish.run();
        if (mFinishTransaction != null) {
        if (mFinishTransaction != null) {
@@ -382,17 +440,34 @@ class SplitScreenTransitions {
                || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
                || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
    }
    }


    /** Bundled information of dismiss transition. */
    /** Clean-up callbacks for transition. */
    static class DismissTransition {
    interface TransitionCallback {
        IBinder mTransition;
        /** Calls when the transition got consumed. */
        default void onTransitionConsumed(boolean aborted) {}

        /** Calls when the transition finished. */
        default void onTransitionFinished(WindowContainerTransaction finishWct,
                SurfaceControl.Transaction finishT) {}
    }


        int mReason;
    /** Session for a transition and its clean-up callback. */
    static class TransitSession {
        final IBinder mTransition;
        TransitionCallback mCallback;


        @SplitScreen.StageType
        TransitSession(IBinder transition, @Nullable TransitionCallback callback) {
        int mDismissTop;
            mTransition = transition;
            mCallback = callback != null ? callback : new TransitionCallback() {};
        }
    }

    /** Bundled information of dismiss transition. */
    static class DismissTransition extends TransitSession {
        final int mReason;
        final @SplitScreen.StageType int mDismissTop;


        DismissTransition(IBinder transition, int reason, int dismissTop) {
        DismissTransition(IBinder transition, int reason, int dismissTop) {
            this.mTransition = transition;
            super(transition, null /* callback */);
            this.mReason = reason;
            this.mReason = reason;
            this.mDismissTop = dismissTop;
            this.mDismissTop = dismissTop;
        }
        }
+92 −45
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CHANGE;
@@ -214,6 +215,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                }
                }
            };
            };


    private final SplitScreenTransitions.TransitionCallback mRecentTransitionCallback =
            new SplitScreenTransitions.TransitionCallback() {
        @Override
        public void onTransitionFinished(WindowContainerTransaction finishWct,
                SurfaceControl.Transaction finishT) {
            // 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) {
                final WindowContainerTransaction.HierarchyOp op =
                        finishWct.getHierarchyOps().get(i);
                final IBinder container = op.getContainer();
                if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
                        && (mMainStage.containsContainer(container)
                        || mSideStage.containsContainer(container))) {
                    setDividerVisibility(true, finishT);
                    return;
                }
            }

            // Dismiss the split screen if it's not returning to split.
            prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, finishWct);
            setSplitsVisible(false);
            setDividerVisibility(false, finishT);
            logExit(EXIT_REASON_UNKNOWN);
        }
    };

    StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
    StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
            ShellTaskOrganizer taskOrganizer, DisplayController displayController,
            ShellTaskOrganizer taskOrganizer, DisplayController displayController,
            DisplayImeController displayImeController,
            DisplayImeController displayImeController,
@@ -337,15 +365,23 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        targetStage.evictAllChildren(evictWct);
        targetStage.evictAllChildren(evictWct);
        targetStage.addTask(task, wct);
        targetStage.addTask(task, wct);
        if (!evictWct.isEmpty()) {
            wct.merge(evictWct, true /* transfer */);
        }


        if (ENABLE_SHELL_TRANSITIONS) {
        if (ENABLE_SHELL_TRANSITIONS) {
            prepareEnterSplitScreen(wct);
            prepareEnterSplitScreen(wct);
            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE,
            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct,
                    wct, null, this);
                    null, this, new SplitScreenTransitions.TransitionCallback() {
                        @Override
                        public void onTransitionFinished(WindowContainerTransaction finishWct,
                                SurfaceControl.Transaction finishT) {
                            if (!evictWct.isEmpty()) {
                                finishWct.merge(evictWct, true);
                            }
                        }
                    });
        } else {
        } else {
            if (!evictWct.isEmpty()) {
                wct.merge(evictWct, true /* transfer */);
            }
            mTaskOrganizer.applyTransaction(wct);
            mTaskOrganizer.applyTransaction(wct);
        }
        }
        return true;
        return true;
@@ -365,6 +401,39 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        return result;
        return result;
    }
    }


    /** Launches an activity into split. */
    void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
            @Nullable Bundle options) {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        prepareEvictChildTasks(position, evictWct);

        options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, null /* wct */);
        wct.sendPendingIntent(intent, fillInIntent, options);
        prepareEnterSplitScreen(wct, null /* taskInfo */, position);

        mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct, null, this,
                new SplitScreenTransitions.TransitionCallback() {
                    @Override
                    public void onTransitionConsumed(boolean aborted) {
                        // Switch the split position if launching as MULTIPLE_TASK failed.
                        if (aborted
                                && (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                            setSideStagePositionAnimated(
                                    SplitLayout.reversePosition(mSideStagePosition));
                        }
                    }

                    @Override
                    public void onTransitionFinished(WindowContainerTransaction finishWct,
                            SurfaceControl.Transaction finishT) {
                        if (!evictWct.isEmpty()) {
                            finishWct.merge(evictWct, true);
                        }
                    }
                });
    }

    /** Starts 2 tasks in one transition. */
    /** Starts 2 tasks in one transition. */
    void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
    void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
            @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
            @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
@@ -395,7 +464,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        wct.startTask(sideTaskId, sideOptions);
        wct.startTask(sideTaskId, sideOptions);


        mSplitTransitions.startEnterTransition(
        mSplitTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this);
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null);
    }
    }


    /** Starts 2 tasks in one legacy transition. */
    /** Starts 2 tasks in one legacy transition. */
@@ -617,11 +686,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    }
    }


    int getTaskId(@SplitPosition int splitPosition) {
    int getTaskId(@SplitPosition int splitPosition) {
        if (mSideStagePosition == splitPosition) {
        if (splitPosition == SPLIT_POSITION_UNDEFINED) {
            return mSideStage.getTopVisibleChildTaskId();
            return INVALID_TASK_ID;
        } else {
            return mMainStage.getTopVisibleChildTaskId();
        }
        }

        return mSideStagePosition == splitPosition
                ? mSideStage.getTopVisibleChildTaskId()
                : mMainStage.getTopVisibleChildTaskId();
    }
    }


    void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) {
    void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) {
@@ -861,6 +932,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mSplitLayout.init();
        mSplitLayout.init();
        setDividerVisibility(true, t);
        setDividerVisibility(true, t);
        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
        t.show(mRootTaskLeash);
        setSplitsVisible(true);
        setSplitsVisible(true);
        mShouldUpdateRecents = true;
        mShouldUpdateRecents = true;
        updateRecentTasksSplitPair();
        updateRecentTasksSplitPair();
@@ -1543,14 +1615,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                } else if (activityType == ACTIVITY_TYPE_HOME
                } else if (activityType == ACTIVITY_TYPE_HOME
                        || activityType == ACTIVITY_TYPE_RECENTS) {
                        || activityType == ACTIVITY_TYPE_RECENTS) {
                    // Enter overview panel, so start recent transition.
                    // Enter overview panel, so start recent transition.
                    mSplitTransitions.setRecentTransition(transition,
                    mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(),
                            request.getRemoteTransition());
                            mRecentTransitionCallback);
                } else if (mSplitTransitions.mPendingRecent == null) {
                } else if (mSplitTransitions.mPendingRecent == null) {
                    // If split-task is not controlled by recents animation
                    // If split-task is not controlled by recents animation
                    // and occluded by the other fullscreen task, dismiss both.
                    // and occluded by the other fullscreen task, dismiss both.
                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
                    mSplitTransitions.setDismissTransition(transition,
                    mSplitTransitions.setDismissTransition(
                            STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
                            transition, STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
                }
                }
            }
            }
        } else {
        } else {
@@ -1558,7 +1630,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                // One task is appearing into split, prepare to enter split screen.
                // One task is appearing into split, prepare to enter split screen.
                out = new WindowContainerTransaction();
                out = new WindowContainerTransaction();
                prepareEnterSplitScreen(out);
                prepareEnterSplitScreen(out);
                mSplitTransitions.mPendingEnter = transition;
                mSplitTransitions.setEnterTransition(
                        transition, request.getRemoteTransition(), null /* callback */);
            }
            }
        }
        }
        return out;
        return out;
@@ -1614,10 +1687,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        if (transition != mSplitTransitions.mPendingEnter
        if (!mSplitTransitions.isPendingTransition(transition)) {
                && transition != mSplitTransitions.mPendingRecent
                && (mSplitTransitions.mPendingDismiss == null
                        || mSplitTransitions.mPendingDismiss.mTransition != transition)) {
            // Not entering or exiting, so just do some house-keeping and validation.
            // Not entering or exiting, so just do some house-keeping and validation.


            // If we're not in split-mode, just abort so something else can handle it.
            // If we're not in split-mode, just abort so something else can handle it.
@@ -1664,12 +1734,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
        }


        boolean shouldAnimate = true;
        boolean shouldAnimate = true;
        if (mSplitTransitions.mPendingEnter == transition) {
        if (mSplitTransitions.isPendingEnter(transition)) {
            shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
            shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
        } else if (mSplitTransitions.mPendingRecent == transition) {
        } else if (mSplitTransitions.isPendingRecent(transition)) {
            shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
            shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
        } else if (mSplitTransitions.mPendingDismiss != null
        } else if (mSplitTransitions.isPendingDismiss(transition)) {
                && mSplitTransitions.mPendingDismiss.mTransition == transition) {
            shouldAnimate = startPendingDismissAnimation(
            shouldAnimate = startPendingDismissAnimation(
                    mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
                    mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
        }
        }
@@ -1837,28 +1906,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        return true;
        return true;
    }
    }


    void onRecentTransitionFinished(WindowContainerTransaction wct,
            SurfaceControl.Transaction finishT) {
        // 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 < wct.getHierarchyOps().size(); ++i) {
            final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i);
            final IBinder container = op.getContainer();
            if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
                    && (mMainStage.containsContainer(container)
                    || mSideStage.containsContainer(container))) {
                setDividerVisibility(true, finishT);
                return;
            }
        }

        // Dismiss the split screen is it's not returning to split.
        prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
        setSplitsVisible(false);
        setDividerVisibility(false, finishT);
        logExit(EXIT_REASON_UNKNOWN);
    }

    private void addDividerBarToTransition(@NonNull TransitionInfo info,
    private void addDividerBarToTransition(@NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, boolean show) {
            @NonNull SurfaceControl.Transaction t, boolean show) {
        final SurfaceControl leash = mSplitLayout.getDividerLeash();
        final SurfaceControl leash = mSplitLayout.getDividerLeash();
+2 −2
Original line number Original line Diff line number Diff line
@@ -182,7 +182,7 @@ public class SplitTransitionTests extends ShellTestCase {


        IBinder transition = mSplitScreenTransitions.startEnterTransition(
        IBinder transition = mSplitScreenTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
                new RemoteTransition(testRemote), mStageCoordinator);
                new RemoteTransition(testRemote), mStageCoordinator, null);
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        boolean accepted = mStageCoordinator.startAnimation(transition, info,
        boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -422,7 +422,7 @@ public class SplitTransitionTests extends ShellTestCase {
        TransitionInfo enterInfo = createEnterPairInfo();
        TransitionInfo enterInfo = createEnterPairInfo();
        IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
        IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
                new RemoteTransition(new TestRemoteTransition()), mStageCoordinator);
                new RemoteTransition(new TestRemoteTransition()), mStageCoordinator, null);
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mMainStage.onTaskAppeared(mMainChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        mSideStage.onTaskAppeared(mSideChild, createMockSurface());
        mStageCoordinator.startAnimation(enterTransit, enterInfo,
        mStageCoordinator.startAnimation(enterTransit, enterInfo,