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

Commit e58898f2 authored by Jerry Chang's avatar Jerry Chang Committed by Automerger Merge Worker
Browse files

Merge "Add fallback logic to cancel entering split screen" into tm-qpr-dev am:...

Merge "Add fallback logic to cancel entering split screen" into tm-qpr-dev am: b8a27eb6 am: 79389263

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20185503



Change-Id: Iaf96b1399ee6990b6eeab504006d3d95a898834e
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 607ba2fb 79389263
Loading
Loading
Loading
Loading
+102 −55
Original line number Diff line number Diff line
@@ -108,6 +108,14 @@ class SplitScreenTransitions {
    private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
            @NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) {
        final TransitSession pendingTransition = getPendingTransition(transition);
        if (pendingTransition != null && pendingTransition.mCanceled) {
            // The pending transition was canceled, so skip playing animation.
            t.apply();
            onFinish(null /* wct */, null /* wctCB */);
            return;
        }

        // Play some place-holder fade animations
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
@@ -170,9 +178,7 @@ class SplitScreenTransitions {
    }

    boolean isPendingTransition(IBinder transition) {
        return isPendingEnter(transition)
                || isPendingDismiss(transition)
                || isPendingRecent(transition);
        return getPendingTransition(transition) != null;
    }

    boolean isPendingEnter(IBinder transition) {
@@ -187,22 +193,38 @@ class SplitScreenTransitions {
        return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
    }

    @Nullable
    private TransitSession getPendingTransition(IBinder transition) {
        if (isPendingEnter(transition)) {
            return mPendingEnter;
        } else if (isPendingRecent(transition)) {
            return mPendingRecent;
        } else if (isPendingDismiss(transition)) {
            return mPendingDismiss;
        }

        return null;
    }

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

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

        if (remoteTransition != null) {
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -237,8 +259,9 @@ class SplitScreenTransitions {
    }

    void setRecentTransition(@NonNull IBinder transition,
            @Nullable RemoteTransition remoteTransition, @Nullable TransitionCallback callback) {
        mPendingRecent = new TransitSession(transition, callback);
            @Nullable RemoteTransition remoteTransition,
            @Nullable TransitionFinishedCallback finishCallback) {
        mPendingRecent = new TransitSession(transition, null /* consumedCb */, finishCallback);

        if (remoteTransition != null) {
            // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
@@ -256,14 +279,9 @@ class SplitScreenTransitions {
        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.
                }
            };
            mPendingRecent.setFinishedCallback(null);
        }

        if (mActiveRemoteHandler != null) {
@@ -277,7 +295,7 @@ class SplitScreenTransitions {
    }

    boolean end() {
        // If its remote, there's nothing we can do right now.
        // If It's remote, there's nothing we can do right now.
        if (mActiveRemoteHandler != null) return false;
        for (int i = mAnimations.size() - 1; i >= 0; --i) {
            final Animator anim = mAnimations.get(i);
@@ -290,20 +308,20 @@ class SplitScreenTransitions {
            @Nullable SurfaceControl.Transaction finishT) {
        if (isPendingEnter(transition)) {
            if (!aborted) {
                // An enter transition got merged, appends the rest operations to finish entering
                // An entering transition got merged, appends the rest operations to finish entering
                // split screen.
                mStageCoordinator.finishEnterSplitScreen(finishT);
                mPendingRemoteHandler = null;
            }

            mPendingEnter.mCallback.onTransitionConsumed(aborted);
            mPendingEnter.onConsumed(aborted);
            mPendingEnter = null;
            mPendingRemoteHandler = null;
        } else if (isPendingDismiss(transition)) {
            mPendingDismiss.mCallback.onTransitionConsumed(aborted);
            mPendingDismiss.onConsumed(aborted);
            mPendingDismiss = null;
        } else if (isPendingRecent(transition)) {
            mPendingRecent.mCallback.onTransitionConsumed(aborted);
            mPendingRecent.onConsumed(aborted);
            mPendingRecent = null;
            mPendingRemoteHandler = null;
        }
@@ -312,23 +330,16 @@ class SplitScreenTransitions {
    void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
        if (!mAnimations.isEmpty()) return;

        TransitionCallback callback = null;
        if (wct == null) wct = new WindowContainerTransaction();
        if (isPendingEnter(mAnimatingTransition)) {
            callback = mPendingEnter.mCallback;
            mPendingEnter.onFinished(wct, mFinishTransaction);
            mPendingEnter = null;
        }
        if (isPendingDismiss(mAnimatingTransition)) {
            callback = mPendingDismiss.mCallback;
            mPendingDismiss = null;
        }
        if (isPendingRecent(mAnimatingTransition)) {
            callback = mPendingRecent.mCallback;
        } else if (isPendingRecent(mAnimatingTransition)) {
            mPendingRecent.onFinished(wct, mFinishTransaction);
            mPendingRecent = null;
        }

        if (callback != null) {
            if (wct == null) wct = new WindowContainerTransaction();
            callback.onTransitionFinished(wct, mFinishTransaction);
        } else if (isPendingDismiss(mAnimatingTransition)) {
            mPendingDismiss.onFinished(wct, mFinishTransaction);
            mPendingDismiss = null;
        }

        mPendingRemoteHandler = null;
@@ -363,10 +374,7 @@ class SplitScreenTransitions {
                onFinish(null /* wct */, null /* wctCB */);
            });
        };
        va.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) { }

        va.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                finisher.run();
@@ -376,9 +384,6 @@ class SplitScreenTransitions {
            public void onAnimationCancel(Animator animation) {
                finisher.run();
            }

            @Override
            public void onAnimationRepeat(Animator animation) { }
        });
        mAnimations.add(va);
        mTransitions.getAnimExecutor().execute(va::start);
@@ -432,24 +437,66 @@ class SplitScreenTransitions {
                || info.getType() == TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
    }

    /** Clean-up callbacks for transition. */
    interface TransitionCallback {
    /** Calls when the transition got consumed. */
        default void onTransitionConsumed(boolean aborted) {}
    interface TransitionConsumedCallback {
        void onConsumed(boolean aborted);
    }

    /** Calls when the transition finished. */
        default void onTransitionFinished(WindowContainerTransaction finishWct,
                SurfaceControl.Transaction finishT) {}
    interface TransitionFinishedCallback {
        void onFinished(WindowContainerTransaction wct, SurfaceControl.Transaction t);
    }

    /** Session for a transition and its clean-up callback. */
    static class TransitSession {
        final IBinder mTransition;
        TransitionCallback mCallback;
        TransitionConsumedCallback mConsumedCallback;
        TransitionFinishedCallback mFinishedCallback;

        /** Whether the transition was canceled. */
        boolean mCanceled;

        TransitSession(IBinder transition, @Nullable TransitionCallback callback) {
        TransitSession(IBinder transition,
                @Nullable TransitionConsumedCallback consumedCallback,
                @Nullable TransitionFinishedCallback finishedCallback) {
            mTransition = transition;
            mCallback = callback != null ? callback : new TransitionCallback() {};
            mConsumedCallback = consumedCallback;
            mFinishedCallback = finishedCallback;

        }

        /** Sets transition consumed callback. */
        void setConsumedCallback(@Nullable TransitionConsumedCallback callback) {
            mConsumedCallback = callback;
        }

        /** Sets transition finished callback. */
        void setFinishedCallback(@Nullable TransitionFinishedCallback callback) {
            mFinishedCallback = callback;
        }

        /**
         * Cancels the transition. This should be called before playing animation. A canceled
         * transition will skip playing animation.
         *
         * @param finishedCb new finish callback to override.
         */
        void cancel(@Nullable TransitionFinishedCallback finishedCb) {
            mCanceled = true;
            setFinishedCallback(finishedCb);
        }

        void onConsumed(boolean aborted) {
            if (mConsumedCallback != null) {
                mConsumedCallback.onConsumed(aborted);
            }
        }

        void onFinished(WindowContainerTransaction finishWct,
                SurfaceControl.Transaction finishT) {
            if (mFinishedCallback != null) {
                mFinishedCallback.onFinished(finishWct, finishT);
            }
        }
    }

@@ -459,7 +506,7 @@ class SplitScreenTransitions {
        final @SplitScreen.StageType int mDismissTop;

        DismissTransition(IBinder transition, int reason, int dismissTop) {
            super(transition, null /* callback */);
            super(transition, null /* consumedCallback */, null /* finishedCallback */);
            this.mReason = reason;
            this.mDismissTop = dismissTop;
        }
+71 −71
Original line number Diff line number Diff line
@@ -226,12 +226,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                }
            };

    private final SplitScreenTransitions.TransitionCallback mRecentTransitionCallback =
            new SplitScreenTransitions.TransitionCallback() {
    private final SplitScreenTransitions.TransitionFinishedCallback
            mRecentTransitionFinishedCallback =
            new SplitScreenTransitions.TransitionFinishedCallback() {
                @Override
        public void onTransitionFinished(WindowContainerTransaction finishWct,
                public void onFinished(WindowContainerTransaction finishWct,
                        SurfaceControl.Transaction finishT) {
            // Check if the recent transition is finished by returning to the current split, so we
                    // 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 =
@@ -240,7 +242,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                        if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop()
                                && (mMainStage.containsContainer(container)
                                || mSideStage.containsContainer(container))) {
                    updateSurfaceBounds(mSplitLayout, finishT, false /* applyResizingOffset */);
                            updateSurfaceBounds(mSplitLayout, finishT,
                                    false /* applyResizingOffset */);
                            setDividerVisibility(true, finishT);
                            return;
                        }
@@ -389,15 +392,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        if (ENABLE_SHELL_TRANSITIONS) {
            prepareEnterSplitScreen(wct);
            mSplitTransitions.startEnterTransition(TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, wct,
                    null, this, new SplitScreenTransitions.TransitionCallback() {
                        @Override
                        public void onTransitionFinished(WindowContainerTransaction finishWct,
                                SurfaceControl.Transaction finishT) {
                    null, this, null /* consumedCallback */, (finishWct, finishT) -> {
                        if (!evictWct.isEmpty()) {
                            finishWct.merge(evictWct, true);
                        }
                        }
                    });
                    } /* finishedCallback */);
        } else {
            if (!evictWct.isEmpty()) {
                wct.merge(evictWct, true /* transfer */);
@@ -434,28 +433,25 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

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

        // If split screen is not activated, we're expecting to open a pair of apps to split.
        final int transitType = mMainStage.isActive()
                ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
        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) {
        mSplitTransitions.startEnterTransition(transitType, wct, null, this,
                aborted -> {
                    // Switch the split position if launching as MULTIPLE_TASK failed.
                        if (aborted
                                && (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                    if (aborted && (fillInIntent.getFlags() & FLAG_ACTIVITY_MULTIPLE_TASK) != 0) {
                        setSideStagePositionAnimated(
                                SplitLayout.reversePosition(mSideStagePosition));
                    }
                    }

                    @Override
                    public void onTransitionFinished(WindowContainerTransaction finishWct,
                            SurfaceControl.Transaction finishT) {
                } /* consumedCallback */,
                (finishWct, finishT) -> {
                    if (!evictWct.isEmpty()) {
                        finishWct.merge(evictWct, true);
                    }
                    }
                });
                } /* finishedCallback */);
    }

    /** Launches an activity into split by legacy transition. */
@@ -592,7 +588,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        wct.startTask(mainTaskId, mainOptions);

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

@@ -1839,7 +1835,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                        || activityType == ACTIVITY_TYPE_RECENTS) {
                    // Enter overview panel, so start recent transition.
                    mSplitTransitions.setRecentTransition(transition, request.getRemoteTransition(),
                            mRecentTransitionCallback);
                            mRecentTransitionFinishedCallback);
                } else if (mSplitTransitions.mPendingRecent == null) {
                    // If split-task is not controlled by recents animation
                    // and occluded by the other fullscreen task, dismiss both.
@@ -1853,8 +1849,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                // One task is appearing into split, prepare to enter split screen.
                out = new WindowContainerTransaction();
                prepareEnterSplitScreen(out);
                mSplitTransitions.setEnterTransition(
                        transition, request.getRemoteTransition(), null /* callback */);
                mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
                        null /* consumedCallback */, null /* finishedCallback */);
            }
        }
        return out;
@@ -2031,17 +2027,21 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            }
        }

        // TODO(b/250853925): fallback logic. Probably start a new transition to exit split before
        //       applying anything here. Ideally consolidate with transition-merging.
        if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
            if (mainChild == null && sideChild == null) {
                throw new IllegalStateException("Launched a task in split, but didn't receive any"
                        + " task in transition.");
                Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
                mSplitTransitions.mPendingEnter.cancel(null /* finishedCb */);
                return true;
            }
        } else {
            if (mainChild == null || sideChild == null) {
                throw new IllegalStateException("Launched 2 tasks in split, but didn't receive"
                Log.w(TAG, "Launched 2 tasks in split, but didn't receive"
                        + " 2 tasks in transition. Possibly one of them failed to launch");
                final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
                        (sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
                mSplitTransitions.mPendingEnter.cancel(
                        (cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
                return true;
            }
        }

+2 −2
Original line number Diff line number Diff line
@@ -181,7 +181,7 @@ public class SplitTransitionTests extends ShellTestCase {

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