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

Commit 8c980b54 authored by Toshiki Kikuchi's avatar Toshiki Kikuchi
Browse files

Ensure dismiss-splitscreen makes an app fullscreen

This CL ensures that the top app leaves splitscreen to be fullscreen if
the splitscreen is deactivated unless it’s explicitly moved to desktop windowing.
If the display windowing mode is freeform, the app windowing mode needs
to be set explicitly to be fullscreen.

Bug: 364927895
Bug: 384840232
Flag: EXEMPT bug fix
Test: StageCoodinatorTests
Change-Id: Ia8b6ee332baa486fc598b4b9cd120257aa11e009
parent 177b4e45
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -300,7 +300,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
                mTaskOrganizer, mDisplayController, mDisplayImeController,
                mDisplayInsetsController, mTransitions, mTransactionPool, mIconProvider,
                mMainExecutor, mMainHandler, mRecentTasksOptional, mLaunchAdjacentController,
                mWindowDecorViewModel, mSplitState, mDesktopTasksController);
                mWindowDecorViewModel, mSplitState, mDesktopTasksController, mRootTDAOrganizer);
    }

    @Override
@@ -441,7 +441,7 @@ public class SplitScreenController implements SplitDragPolicy.Starter,
     */
    public void prepareExitSplitScreen(WindowContainerTransaction wct,
            @StageType int stageToTop, @ExitReason int reason) {
        mStageCoordinator.prepareExitSplitScreen(stageToTop, wct);
        mStageCoordinator.prepareExitSplitScreen(stageToTop, wct, reason);
        mStageCoordinator.clearSplitPairedInRecents(reason);
    }

+45 −16
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ import com.android.internal.policy.FoldLockSettingsObserver;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.ComponentUtils;
import com.android.wm.shell.common.DisplayController;
@@ -167,6 +168,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -217,6 +219,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    private final SplitscreenEventLogger mLogger;
    private final ShellExecutor mMainExecutor;
    private final Handler mMainHandler;
    private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
    // 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<>();
@@ -353,7 +356,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            Handler mainHandler, Optional<RecentTasksController> recentTasks,
            LaunchAdjacentController launchAdjacentController,
            Optional<WindowDecorViewModel> windowDecorViewModel, SplitState splitState,
            Optional<DesktopTasksController> desktopTasksController) {
            Optional<DesktopTasksController> desktopTasksController,
            RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
        mContext = context;
        mDisplayId = displayId;
        mSyncQueue = syncQueue;
@@ -366,6 +370,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mWindowDecorViewModel = windowDecorViewModel;
        mSplitState = splitState;
        mDesktopTasksController = desktopTasksController;
        mRootTDAOrganizer = rootTDAOrganizer;

        taskOrganizer.createRootTask(displayId, WINDOWING_MODE_FULLSCREEN, this /* listener */);

@@ -424,7 +429,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
            Handler mainHandler, Optional<RecentTasksController> recentTasks,
            LaunchAdjacentController launchAdjacentController,
            Optional<WindowDecorViewModel> windowDecorViewModel, SplitState splitState,
            Optional<DesktopTasksController> desktopTasksController) {
            Optional<DesktopTasksController> desktopTasksController,
            RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
        mContext = context;
        mDisplayId = displayId;
        mSyncQueue = syncQueue;
@@ -446,6 +452,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        mWindowDecorViewModel = windowDecorViewModel;
        mSplitState = splitState;
        mDesktopTasksController = desktopTasksController;
        mRootTDAOrganizer = rootTDAOrganizer;

        mDisplayController.addDisplayWindowListener(this);
        transitions.addHandler(this);
@@ -872,7 +879,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
    private void startSingleTask(int taskId, Bundle options, WindowContainerTransaction wct,
            RemoteTransition remoteTransition) {
        if (mMainStage.containsTask(taskId) || mSideStage.containsTask(taskId)) {
            prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
            prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct, EXIT_REASON_FULLSCREEN_REQUEST);
        }
        if (mRecentTasks.isPresent()) {
            mRecentTasks.get().removeSplitPair(taskId);
@@ -1425,7 +1432,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        // on top and lead to no visible change.
        clearSplitPairedInRecents(reason);
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        prepareExitSplitScreen(mLastActiveStage, wct);
        prepareExitSplitScreen(mLastActiveStage, wct, reason);
        mSplitTransitions.startDismissTransition(wct, this, mLastActiveStage, reason);
        setSplitsVisible(false);
        mBreakOnNextWake = false;
@@ -1519,7 +1526,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        if (!isSplitActive()) return;
        final int stage = getStageOfTask(toTopTaskId);
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        prepareExitSplitScreen(stage, wct);
        prepareExitSplitScreen(stage, wct, exitReason);
        mSplitTransitions.startDismissTransition(wct, this, stage, exitReason);
        // reset stages to their default sides.
        setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null);
@@ -1638,7 +1645,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
     * to be used when exiting split might be bundled with other window operations.
     */
    void prepareExitSplitScreen(@StageType int stageToTop,
            @NonNull WindowContainerTransaction wct) {
            @NonNull WindowContainerTransaction wct, @ExitReason int exitReason) {
        if (!isSplitActive()) return;
        ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "prepareExitSplitScreen: stageToTop=%s",
                stageTypeToString(stageToTop));
@@ -1649,6 +1656,26 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        } else {
            mSideStage.removeAllTasks(wct, stageToTop == STAGE_TYPE_SIDE);
        }

        if (exitReason != EXIT_REASON_DESKTOP_MODE) {
            StageTaskListener toTopStage = stageToTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
            if (enableFlexibleSplit()) {
                toTopStage = mStageOrderOperator.getAllStages().stream()
                        .filter(stage -> stage.getId() == stageToTop)
                        .findFirst().orElse(null);
            }
            final DisplayAreaInfo tdaInfo = mRootTDAOrganizer.getDisplayAreaInfo(mDisplayId);
            Objects.requireNonNull(tdaInfo);
            final int displayWindowingMode =
                    tdaInfo.configuration.windowConfiguration.getWindowingMode();
            // In freeform-first env, we need to explicitly set the windowing mode when leaving
            // the split-screen to be fullscreen.
            final int targetWindowingMode = displayWindowingMode == WINDOWING_MODE_FREEFORM
                    ? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_UNDEFINED;
            toTopStage.doForAllChildTaskInfos(taskInfo -> {
                wct.setWindowingMode(taskInfo.token, targetWindowingMode);
            });
        }
        deactivateSplit(wct, stageToTop);
        mSplitState.exit();
    }
@@ -2323,7 +2350,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
            }
            final WindowContainerTransaction wct = new WindowContainerTransaction();
            prepareExitSplitScreen(stageType, wct);
            prepareExitSplitScreen(stageType, wct, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
            clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
            mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
                    EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
@@ -2355,10 +2382,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
        }
        final WindowContainerTransaction wct = new WindowContainerTransaction();
        toTopStage.resetBounds(wct);
        prepareExitSplitScreen(dismissTop, wct);
        prepareExitSplitScreen(dismissTop, wct, EXIT_REASON_DRAG_DIVIDER);
        if (mRootTaskInfo != null) {
            wct.setDoNotPip(mRootTaskInfo.token);
        }

        mSplitTransitions.startDismissTransition(wct, this, dismissTop, EXIT_REASON_DRAG_DIVIDER);
    }

@@ -2793,7 +2821,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    // The top should be the opposite side that is closing:
                    int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN
                            ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN;
                    prepareExitSplitScreen(dismissTop, out);
                    prepareExitSplitScreen(dismissTop, out, EXIT_REASON_APP_FINISHED);
                    mSplitTransitions.setDismissTransition(transition, dismissTop,
                            EXIT_REASON_APP_FINISHED);
                } else if (isOpening && !mPausingTasks.isEmpty()) {
@@ -2801,7 +2829,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    // recents, which means to dismiss the split pair to this task.
                    int dismissTop = getStageType(stage) == STAGE_TYPE_MAIN
                            ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
                    prepareExitSplitScreen(dismissTop, out);
                    prepareExitSplitScreen(dismissTop, out, EXIT_REASON_APP_FINISHED);
                    mSplitTransitions.setDismissTransition(transition, dismissTop,
                            EXIT_REASON_APP_FINISHED);
                } else if (!isSplitScreenVisible() && isOpening) {
@@ -2814,7 +2842,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    // If the trigger task is in fullscreen and in split, exit split and place
                    // task on top
                    final int stageType = getStageOfTask(triggerTask.taskId);
                    prepareExitSplitScreen(stageType, out);
                    prepareExitSplitScreen(stageType, out, EXIT_REASON_FULLSCREEN_REQUEST);
                    mSplitTransitions.setDismissTransition(transition, stageType,
                            EXIT_REASON_FULLSCREEN_REQUEST);
                }
@@ -2842,7 +2870,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                if (anyStageContainsSingleFullscreenTask) {
                    // A splitting task is opening to fullscreen causes one side of the split empty,
                    // so appends operations to exit split.
                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
                    prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out,
                            EXIT_REASON_FULLSCREEN_REQUEST);
                }
            } else if (type == TRANSIT_KEYGUARD_OCCLUDE && triggerTask.topActivity != null
                    && isSplitScreenVisible()) {
@@ -2850,7 +2879,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                // stage and move it to the top.
                int top = triggerTask.topActivity.equals(mMainStage.mRootTaskInfo.topActivity)
                        ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
                prepareExitSplitScreen(top, out);
                prepareExitSplitScreen(top, out, EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
                mSplitTransitions.setDismissTransition(transition, top,
                        EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
            }
@@ -2932,7 +2961,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                    topStage = STAGE_TYPE_SIDE;
                }
            }
            prepareExitSplitScreen(topStage, outWCT);
            prepareExitSplitScreen(topStage, outWCT, EXIT_REASON_UNKNOWN);
        }
    }

@@ -3119,7 +3148,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                // If there is a fullscreen opening change, we should not bring stage to top.
                prepareExitSplitScreen(
                        !record.mContainShowFullscreenChange && isSplitScreenVisible()
                        ? dismissTop : STAGE_TYPE_UNDEFINED, wct);
                        ? dismissTop : STAGE_TYPE_UNDEFINED, wct, EXIT_REASON_APP_FINISHED);
                mSplitTransitions.startDismissTransition(wct, this, dismissTop,
                        EXIT_REASON_APP_FINISHED);
                // This can happen in some pathological cases. For example:
@@ -3360,7 +3389,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
                        (sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
                pendingEnter.cancel(
                        (cancelWct, cancelT) -> {
                            prepareExitSplitScreen(dismissTop, cancelWct);
                            prepareExitSplitScreen(dismissTop, cancelWct, EXIT_REASON_UNKNOWN);
                            logExit(EXIT_REASON_UNKNOWN);
                        });
                Log.w(TAG, splitFailureMessage("startPendingEnterAnimation",
+7 −0
Original line number Diff line number Diff line
@@ -379,6 +379,13 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener {
        }
    }

    void doForAllChildTaskInfos(Consumer<ActivityManager.RunningTaskInfo> consumer) {
        for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
            final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i);
            consumer.accept(taskInfo);
        }
    }

    /** Collects all the current child tasks and prepares transaction to evict them to display. */
    void evictAllChildren(WindowContainerTransaction wct) {
        for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) {
+4 −1
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ public class TvSplitScreenController extends SplitScreenController {
    private final Optional<RecentTasksController> mRecentTasksOptional;
    private final LaunchAdjacentController mLaunchAdjacentController;
    private final SplitState mSplitState;
    private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;

    private final Handler mMainHandler;
    private final SystemWindows mSystemWindows;
@@ -109,6 +110,7 @@ public class TvSplitScreenController extends SplitScreenController {

        mMainHandler = mainHandler;
        mSystemWindows = systemWindows;
        mRootTDAOrganizer = rootTDAOrganizer;
    }

    /**
@@ -121,7 +123,8 @@ public class TvSplitScreenController extends SplitScreenController {
                mTaskOrganizer, mDisplayController, mDisplayImeController,
                mDisplayInsetsController, mTransitions, mTransactionPool,
                mIconProvider, mMainExecutor, mMainHandler,
                mRecentTasksOptional, mLaunchAdjacentController, mSplitState, mSystemWindows);
                mRecentTasksOptional, mLaunchAdjacentController, mSplitState, mSystemWindows,
                mRootTDAOrganizer);
    }

}
+3 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context;
import android.os.Handler;

import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -55,11 +56,11 @@ public class TvStageCoordinator extends StageCoordinator
            Optional<RecentTasksController> recentTasks,
            LaunchAdjacentController launchAdjacentController,
            SplitState splitState,
            SystemWindows systemWindows) {
            SystemWindows systemWindows, RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
        super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController,
                displayInsetsController, transitions, transactionPool, iconProvider,
                mainExecutor, mainHandler, recentTasks, launchAdjacentController,
                Optional.empty(), splitState, Optional.empty());
                Optional.empty(), splitState, Optional.empty(), rootTDAOrganizer);

        mTvSplitMenuController = new TvSplitMenuController(context, this,
                systemWindows, mainHandler);
Loading