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

Commit 5af1f670 authored by Tony Huang's avatar Tony Huang
Browse files

Support back to split

Handle split screen enter while it still running background case.

Bug: 236317871
Fix: 235515745
Test: manual
Test: pass existing tests
Change-Id: Id75611afc446f74864e016cbaa51e501dcd55612
parent 76ce5869
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -240,7 +240,7 @@ public class DragAndDropPolicy {
            // Update launch options for the split side we are targeting.
            position = leftOrTop ? SPLIT_POSITION_TOP_OR_LEFT : SPLIT_POSITION_BOTTOM_OR_RIGHT;
            // Add some data for logging splitscreen once it is invoked
            mSplitScreen.logOnDroppedToSplit(position, mLoggerSessionId);
            mSplitScreen.onDroppedToSplit(position, mLoggerSessionId);
        }

        final ClipDescription description = data.getDescription();
+1 −13
Original line number Diff line number Diff line
@@ -16,9 +16,6 @@

package com.android.wm.shell.splitscreen;

import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;

import android.content.Context;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
@@ -34,8 +31,6 @@ import com.android.wm.shell.common.SyncTransactionQueue;
 * @see StageCoordinator
 */
class MainStage extends StageTaskListener {
    private static final String TAG = MainStage.class.getSimpleName();

    private boolean mIsActive = false;

    MainStage(Context context, ShellTaskOrganizer taskOrganizer, int displayId,
@@ -52,15 +47,8 @@ class MainStage extends StageTaskListener {
    void activate(WindowContainerTransaction wct, boolean includingTopTask) {
        if (mIsActive) return;

        final WindowContainerToken rootToken = mRootTaskInfo.token;
        if (includingTopTask) {
            wct.reparentTasks(
                    null /* currentParent */,
                    rootToken,
                    CONTROLLED_WINDOWING_MODES,
                    CONTROLLED_ACTIVITY_TYPES,
                    true /* onTop */,
                    true /* reparentTopOnly */);
            reparentTopTask(wct);
        }

        mIsActive = true;
+10 −6
Original line number Diff line number Diff line
@@ -121,7 +121,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
    public static final int EXIT_REASON_SCREEN_LOCKED = 7;
    public static final int EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP = 8;
    public static final int EXIT_REASON_CHILD_TASK_ENTER_PIP = 9;
    public static final int EXIT_REASON_FULLSCREEN_SHORTCUT = 10;
    public static final int EXIT_REASON_RECREATE_SPLIT = 10;
    public static final int EXIT_REASON_FULLSCREEN_SHORTCUT = 11;
    @IntDef(value = {
            EXIT_REASON_UNKNOWN,
            EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW,
@@ -133,6 +134,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
            EXIT_REASON_SCREEN_LOCKED,
            EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP,
            EXIT_REASON_CHILD_TASK_ENTER_PIP,
            EXIT_REASON_RECREATE_SPLIT,
            EXIT_REASON_FULLSCREEN_SHORTCUT,
    })
    @Retention(RetentionPolicy.SOURCE)
@@ -470,7 +472,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
     */
    public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
            @Nullable Bundle options, UserHandle user, @NonNull InstanceId instanceId) {
        mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
        mStageCoordinator.onRequestToSplit(instanceId, ENTER_REASON_LAUNCHER);
        startShortcut(packageName, shortcutId, position, options, user);
    }

@@ -518,7 +520,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
     */
    public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent,
            @SplitPosition int position, @Nullable Bundle options, @NonNull InstanceId instanceId) {
        mStageCoordinator.getLogger().enterRequested(instanceId, ENTER_REASON_LAUNCHER);
        mStageCoordinator.onRequestToSplit(instanceId, ENTER_REASON_LAUNCHER);
        startIntent(intent, fillInIntent, position, options);
    }

@@ -784,10 +786,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
        return splitTasksLayer;
    }
    /**
     * Sets drag info to be logged when splitscreen is entered.
     * Drop callback when splitscreen is entered.
     */
    public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
        mStageCoordinator.logOnDroppedToSplit(position, dragSessionId);
    public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
        mStageCoordinator.onDroppedToSplit(position, dragSessionId);
    }

    /**
@@ -815,6 +817,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
                return "APP_DOES_NOT_SUPPORT_MULTIWINDOW";
            case EXIT_REASON_CHILD_TASK_ENTER_PIP:
                return "CHILD_TASK_ENTER_PIP";
            case EXIT_REASON_RECREATE_SPLIT:
                return "RECREATE_SPLIT";
            default:
                return "unknown reason, reason int = " + exitReason;
        }
+8 −0
Original line number Diff line number Diff line
@@ -21,9 +21,11 @@ import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED_
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__ENTER_REASON__UNKNOWN_ENTER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__APP_FINISHED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__CHILD_TASK_ENTER_PIP;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DEVICE_FOLDED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__DRAG_DIVIDER;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__FULLSCREEN_SHORTCUT;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RECREATE_SPLIT;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__ROOT_TASK_VANISHED;
import static com.android.internal.util.FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
@@ -37,9 +39,11 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASO
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_UNKNOWN;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RECREATE_SPLIT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ROOT_TASK_VANISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED;
@@ -182,6 +186,10 @@ public class SplitscreenEventLogger {
                return SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED;
            case EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP:
                return SPLITSCREEN_UICHANGED__EXIT_REASON__SCREEN_LOCKED_SHOW_ON_TOP;
            case EXIT_REASON_CHILD_TASK_ENTER_PIP:
                return SPLITSCREEN_UICHANGED__EXIT_REASON__CHILD_TASK_ENTER_PIP;
            case EXIT_REASON_RECREATE_SPLIT:
                return SPLITSCREEN_UICHANGED__EXIT_REASON__RECREATE_SPLIT;
            case EXIT_REASON_FULLSCREEN_SHORTCUT:
                return SPLITSCREEN_UICHANGED__EXIT_REASON__FULLSCREEN_SHORTCUT;
            case EXIT_REASON_UNKNOWN:
+102 −39
Original line number Diff line number Diff line
@@ -49,10 +49,11 @@ import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASO
import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DEVICE_FOLDED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_DRAG_DIVIDER;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_FULLSCREEN_SHORTCUT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RECREATE_SPLIT;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_RETURN_HOME;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_ROOT_TASK_VANISHED;
import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP;
@@ -199,7 +200,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    // and exit, since exit itself can trigger a number of changes that update the stages.
    private boolean mShouldUpdateRecents;
    private boolean mExitSplitScreenOnHide;
    private boolean mIsDividerRemoteAnimating;
    private boolean mIsSplitEntering;
    private boolean mIsDropEntering;
    private boolean mIsExiting;

    /** The target stage to dismiss to when unlock after folded. */
@@ -347,10 +349,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        return mSplitTransitions;
    }

    boolean isSplitScreenVisible() {
    public boolean isSplitScreenVisible() {
        return mSideStageListener.mVisible && mMainStageListener.mVisible;
    }

    public boolean isSplitActive() {
        return mMainStage.isActive();
    }

    boolean isSplitScreenRunningBackground() {
        return !isSplitScreenVisible() && mMainStageListener.mHasChildren
                && mSideStageListener.mHasChildren;
    }

    @StageType
    int getStageOfTask(int taskId) {
        if (mMainStage.containsTask(taskId)) {
@@ -373,11 +384,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            targetStage = mSideStage;
            sideStagePosition = stagePosition;
        } else {
            if (mMainStage.isActive()) {
            if (isSplitScreenVisible()) {
                // If the split screen is activated, retrieves target stage based on position.
                targetStage = stagePosition == mSideStagePosition ? mSideStage : mMainStage;
                sideStagePosition = mSideStagePosition;
            } else {
                exitSplitIfBackground();
                targetStage = mSideStage;
                sideStagePosition = stagePosition;
            }
@@ -673,6 +685,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            @Nullable PendingIntent mainPendingIntent, @Nullable Intent mainFillInIntent,
            @Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio,
            RemoteAnimationAdapter adapter, InstanceId instanceId) {
        exitSplitIfBackground();
        // Init divider first to make divider leash for remote animation target.
        mSplitLayout.init();
        mSplitLayout.setDivideRatio(splitRatio);
@@ -685,11 +698,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

        // Set false to avoid record new bounds with old task still on top;
        mShouldUpdateRecents = false;
        mIsDividerRemoteAnimating = true;
        mIsSplitEntering = true;

        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
        prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
        if (isSplitScreenVisible()) {
            mMainStage.evictAllChildren(evictWct);
            mSideStage.evictAllChildren(evictWct);
        }

        IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
            @Override
@@ -769,7 +784,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

    private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
            WindowContainerTransaction evictWct) {
        mIsDividerRemoteAnimating = false;
        mIsSplitEntering = false;
        mShouldUpdateRecents = true;
        // If any stage has no child after animation finished, it means that split will display
        // nothing, such status will happen if task and intent is same app but not support
@@ -781,6 +796,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            mSplitUnsupportedToast.show();
        } else {
            mSyncQueue.queue(evictWct);
            mSyncQueue.runInSync(t -> {
                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
            });
        }
    }

@@ -815,7 +833,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        switch (stage) {
            case STAGE_TYPE_UNDEFINED: {
                if (position != SPLIT_POSITION_UNDEFINED) {
                    if (mMainStage.isActive()) {
                    if (isSplitScreenVisible()) {
                        // Use the stage of the specified position
                        options = resolveStartStage(
                                position == mSideStagePosition ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN,
@@ -1045,7 +1063,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            }
        });
        mShouldUpdateRecents = false;
        mIsDividerRemoteAnimating = false;
        mIsSplitEntering = false;

        mSplitLayout.getInvisibleBounds(mTempRect1);
        if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
@@ -1104,6 +1122,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
    }

    /** Exit split screen if it still running background */
    public void exitSplitIfBackground() {
        if (!isSplitScreenRunningBackground()) return;

        exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
    }

    /**
     * Overridden by child classes.
     */
@@ -1376,7 +1401,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                && !ENABLE_SHELL_TRANSITIONS) {
            // Clear the divider remote animating flag as the divider will be re-rendered to apply
            // the new rotation config.
            mIsDividerRemoteAnimating = false;
            mIsSplitEntering = false;
            mSplitLayout.update(null /* t */);
            onLayoutSizeChanged(mSplitLayout);
        }
@@ -1425,6 +1450,33 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        });
    }

    void onChildTaskAppeared(StageListenerImpl stageListener, int taskId) {
        if (stageListener == mSideStageListener && isSplitScreenRunningBackground()) {
            // Handle entring split case here if split already running background.
            if (mIsDropEntering) {
                mSplitLayout.resetDividerPosition();
            } else {
                mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
            }
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            mMainStage.evictAllChildren(wct);
            mSideStage.evictOtherChildren(wct, taskId);
            mMainStage.reparentTopTask(wct);
            updateWindowBounds(mSplitLayout, wct);
            wct.reorder(mRootTaskInfo.token, true);

            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
                if (mIsDropEntering) {
                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
                    mIsDropEntering = false;
                } else {
                    mSplitLayout.flingDividerToCenter();
                }
            });
        }
    }

    private void onRootTaskVanished() {
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        if (mRootTaskInfo != null) {
@@ -1456,10 +1508,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    false /* setReparentLeafTaskIfRelaunch */);
        }
        mSyncQueue.queue(wct);

        mSyncQueue.runInSync(t -> {
            t.setVisibility(mSideStage.mRootLeash, sideStageVisible)
                    .setVisibility(mMainStage.mRootLeash, mainStageVisible);
            setDividerVisibility(mainStageVisible, t);
        });
    }
@@ -1484,7 +1533,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mDividerVisible = visible;
        sendSplitVisibilityChanged();

        if (mIsDividerRemoteAnimating) {
        if (mIsSplitEntering) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                    "   Skip animating divider bar due to it's remote animating.");
            return;
@@ -1504,7 +1553,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    "   Skip animating divider bar due to divider leash not ready.");
            return;
        }
        if (mIsDividerRemoteAnimating) {
        if (mIsSplitEntering) {
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
                    "   Skip animating divider bar due to it's remote animating.");
            return;
@@ -1560,28 +1609,22 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        if (!hasChildren && !mIsExiting && mMainStage.isActive()) {
            if (isSideStage && mMainStageListener.mVisible) {
                // Exit to main stage if side stage no longer has children.
                if (ENABLE_SHELL_TRANSITIONS) {
                    exitSplitScreen(mMainStage, EXIT_REASON_APP_FINISHED);
                } else {
                mSplitLayout.flingDividerToDismiss(
                        mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT,
                        EXIT_REASON_APP_FINISHED);
                }
            } else if (!isSideStage && mSideStageListener.mVisible) {
                // Exit to side stage if main stage no longer has children.
                if (ENABLE_SHELL_TRANSITIONS) {
                    exitSplitScreen(mSideStage, EXIT_REASON_APP_FINISHED);
                } else {
                mSplitLayout.flingDividerToDismiss(
                        mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT,
                        EXIT_REASON_APP_FINISHED);
                }
            } else {
                exitSplitScreen(null /* childrenToTop */, EXIT_REASON_UNKNOWN);
            } else if (isSplitScreenRunningBackground()) {
                // Do not exit to any stage due to running background.
                exitSplitScreen(null /* childrenToTop */, EXIT_REASON_APP_FINISHED);
            }
        } else if (isSideStage && hasChildren && !mMainStage.isActive()) {
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            mSplitLayout.init();

            final WindowContainerTransaction wct = new WindowContainerTransaction();
            if (mLogger.isEnterRequestedByDrag()) {
                prepareEnterSplitScreen(wct);
            } else {
@@ -1596,8 +1639,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,

            mSyncQueue.queue(wct);
            mSyncQueue.runInSync(t -> {
                if (mLogger.isEnterRequestedByDrag()) {
                if (mIsDropEntering) {
                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
                    mIsDropEntering = false;
                } else {
                    mShowDecorImmediately = true;
                    mSplitLayout.flingDividerToCenter();
@@ -1952,10 +1996,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
    }

    public boolean isSplitActive() {
        return mMainStage.isActive();
    }

    @Override
    public void mergeAnimation(IBinder transition, TransitionInfo info,
            SurfaceControl.Transaction t, IBinder mergeTarget,
@@ -2311,10 +2351,28 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    /**
     * Sets drag info to be logged when splitscreen is next entered.
     */
    public void logOnDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
    public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
        if (!isSplitScreenVisible()) {
            mIsDropEntering = true;
        }
        if (isSplitScreenRunningBackground()) {
            // Split running background, log exit first and start new enter request.
            logExit(EXIT_REASON_RECREATE_SPLIT);
        }
        mLogger.enterRequestedByDrag(position, dragSessionId);
    }

    /**
     * Sets info to be logged when splitscreen is next entered.
     */
    public void onRequestToSplit(InstanceId sessionId, int enterReason) {
        if (isSplitScreenRunningBackground()) {
            // Split running background, log exit first and start new enter request.
            logExit(EXIT_REASON_RECREATE_SPLIT);
        }
        mLogger.enterRequested(sessionId, enterReason);
    }

    /**
     * Logs the exit of splitscreen.
     */
@@ -2349,6 +2407,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            StageCoordinator.this.onRootTaskAppeared();
        }

        @Override
        public void onChildTaskAppeared(int taskId) {
            StageCoordinator.this.onChildTaskAppeared(this, taskId);
        }

        @Override
        public void onStatusChanged(boolean visible, boolean hasChildren) {
            if (!mHasRootTask) return;
Loading