From 76ce5869fc9acbd8b925682d99dc73833bc5aa2c Mon Sep 17 00:00:00 2001 From: Jeff Chang Date: Wed, 9 Nov 2022 16:39:42 +0800 Subject: [PATCH 1/2] Support back gesture to split pair in background MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split screen will be dismissed right after both sides of the split were occluded. So if users try to use a back-gesture to go back to the previous split pair, it’ll be back to home instead of going back to the split pair. This CL support the split pair in background to make split experience better. Bug: 236317871 Test: atest com.android.wm.shell.SplitLayoutTests Change-Id: I1ead65011ced82e1faa24ccfbc8bf474828fc7dc --- .../wm/shell/splitscreen/StageCoordinator.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index da8dc8733ef5f..80149996cf6c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -1064,6 +1064,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, wct.setSmallestScreenWidthDp(childrenToTop.mRootTaskInfo.token, SMALLEST_SCREEN_WIDTH_DP_UNDEFINED); } + wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, + false /* reparentLeafTaskIfRelaunch */); mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { t.setWindowCrop(mMainStage.mRootLeash, null) @@ -1441,16 +1443,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return; } + final WindowContainerTransaction wct = new WindowContainerTransaction(); if (!mainStageVisible) { + wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, + true /* setReparentLeafTaskIfRelaunch */); // Both stages are not visible, check if it needs to dismiss split screen. - if (mExitSplitScreenOnHide - // Don't dismiss split screen when both stages are not visible due to sleeping - // display. - || (!mMainStage.mRootTaskInfo.isSleeping - && !mSideStage.mRootTaskInfo.isSleeping)) { + if (mExitSplitScreenOnHide) { exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RETURN_HOME); } + } else { + wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token, + false /* setReparentLeafTaskIfRelaunch */); } + mSyncQueue.queue(wct); mSyncQueue.runInSync(t -> { t.setVisibility(mSideStage.mRootLeash, sideStageVisible) @@ -1571,6 +1576,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT, EXIT_REASON_APP_FINISHED); } + } else { + exitSplitScreen(null /* childrenToTop */, EXIT_REASON_UNKNOWN); } } else if (isSideStage && hasChildren && !mMainStage.isActive()) { final WindowContainerTransaction wct = new WindowContainerTransaction(); From 5af1f6704d88d497271c2e9feb1fe8002a5dcf04 Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Thu, 10 Nov 2022 19:06:44 +0800 Subject: [PATCH 2/2] 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 --- .../shell/draganddrop/DragAndDropPolicy.java | 2 +- .../wm/shell/splitscreen/MainStage.java | 14 +- .../splitscreen/SplitScreenController.java | 16 +- .../splitscreen/SplitscreenEventLogger.java | 8 + .../shell/splitscreen/StageCoordinator.java | 141 +++++++++++++----- .../shell/splitscreen/StageTaskListener.java | 18 +++ .../shell/transition/DefaultMixedHandler.java | 2 +- 7 files changed, 141 insertions(+), 60 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index 62bf5172e106a..d93a9012c8f1e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -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(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java index e7ec15e70c11c..89538cb394d4b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java @@ -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; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index b26bc9cd7f9c6..ef70d9bd84eee 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -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; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java index 1016e1bcd66f6..5483fa5d29f6d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitscreenEventLogger.java @@ -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: diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index 80149996cf6c8..602d0e6c0201f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -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); - } + 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); + mSplitLayout.flingDividerToDismiss( + mSideStagePosition != SPLIT_POSITION_BOTTOM_OR_RIGHT, + EXIT_REASON_APP_FINISHED); + } 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; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 8a52c8750ba68..a841b7f96d3c5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.RemoteAnimationTarget.MODE_OPENING; 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 static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE; import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS; @@ -69,6 +70,8 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { public interface StageListenerCallbacks { void onRootTaskAppeared(); + void onChildTaskAppeared(int taskId); + void onStatusChanged(boolean visible, boolean hasChildren); void onChildTaskStatusChanged(int taskId, boolean present, boolean visible); @@ -185,6 +188,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { // Status is managed/synchronized by the transition lifecycle. return; } + mCallbacks.onChildTaskAppeared(taskId); sendStatusChanged(); } else { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo @@ -338,6 +342,14 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } } + void evictOtherChildren(WindowContainerTransaction wct, int taskId) { + for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { + final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); + if (taskId == taskInfo.taskId) continue; + wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + } + } + void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) { final SparseArray toBeEvict = mChildrenTaskInfo.clone(); for (int i = 0; i < apps.length; i++) { @@ -360,6 +372,12 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } } + void reparentTopTask(WindowContainerTransaction wct) { + wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token, + CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES, + true /* onTop */, true /* reparentTopOnly */); + } + void resetBounds(WindowContainerTransaction wct) { wct.setBounds(mRootTaskInfo.token, null); wct.setAppBounds(mRootTaskInfo.token, null); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index 3cba92956f958..a2d7bc43653a3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -111,7 +111,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler { @Override public WindowContainerTransaction handleRequest(@NonNull IBinder transition, @NonNull TransitionRequestInfo request) { - if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitActive()) { + if (mPipHandler.requestHasPipEnter(request) && mSplitHandler.isSplitScreenVisible()) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request while " + "Split-Screen is active, so treat it as Mixed."); if (request.getRemoteTransition() != null) {