From b78b1dfd7c336d96aafa8418ca7a6a5d510ab332 Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Mon, 28 Nov 2022 03:40:58 +0000 Subject: [PATCH] Consolidate entering split screen behavior Add a fallback logic for entering split screen by verifying it contances opening task to the indicated side to prevent leaving one side of the split empty. Fix checking the wrong running task when entering split screen by checking the top running task instead of checking reported focusing task since the focusing task is not matching with the leaf task running on top always. Fix: 246689775 Fix: 260389099 Test: atest WMShellUnitTests Test: drag and drop Calender to enter split while Calender on top won't leave empty side split. Test: drag and drop Chrome to enter split while Chrome on top won't pup up not supported toast. Change-Id: Ic7ea239b10ce41d956a85dbd6d04e007babd0743 --- .../shell/recents/RecentTasksController.java | 10 ++++ .../splitscreen/SplitScreenController.java | 11 ++-- .../shell/splitscreen/StageCoordinator.java | 54 +++++++++---------- .../SplitScreenControllerTests.java | 12 ++--- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index f9172ba183def..7908f35d7ac25 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -341,6 +341,16 @@ public class RecentTasksController implements TaskStackListenerCallback, return recentTasks; } + /** + * Returns the top running leaf task. + */ + @Nullable + public ActivityManager.RunningTaskInfo getTopRunningTask() { + List tasks = mActivityTaskManager.getTasks(1, + false /* filterOnlyVisibleRecents */); + return tasks.isEmpty() ? null : tasks.get(0); + } + /** * Find the background task that match the given component. */ 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 a79ac45228cad..b20125df3a6de 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 @@ -315,10 +315,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, return mStageCoordinator; } - public ActivityManager.RunningTaskInfo getFocusingTaskInfo() { - return mStageCoordinator.getFocusingTaskInfo(); - } - public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) { return mStageCoordinator.isValidToEnterSplitScreen(taskInfo); } @@ -628,9 +624,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, if (!isSplitScreenVisible()) { // Split screen is not yet activated, check if the current top running task is valid to // split together. - final ActivityManager.RunningTaskInfo taskInfo = getFocusingTaskInfo(); - if (taskInfo != null && isValidToEnterSplitScreen(taskInfo)) { - return Objects.equals(taskInfo.baseIntent.getComponent(), launchingActivity); + final ActivityManager.RunningTaskInfo topRunningTask = mRecentTasksOptional + .map(recentTasks -> recentTasks.getTopRunningTask()).orElse(null); + if (topRunningTask != null && isValidToEnterSplitScreen(topRunningTask)) { + return Objects.equals(topRunningTask.baseIntent.getComponent(), launchingActivity); } return false; } 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 acb71a80ee8a0..db1062a6ef522 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 @@ -150,7 +150,7 @@ import java.util.Optional; */ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler, - ShellTaskOrganizer.TaskListener, ShellTaskOrganizer.FocusListener { + ShellTaskOrganizer.TaskListener { private static final String TAG = StageCoordinator.class.getSimpleName(); @@ -186,8 +186,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private final Rect mTempRect1 = new Rect(); private final Rect mTempRect2 = new Rect(); - private ActivityManager.RunningTaskInfo mFocusingTaskInfo; - /** * A single-top root task which the split divider attached to. */ @@ -304,7 +302,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mDisplayController.addDisplayWindowListener(this); mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId)); transitions.addHandler(this); - mTaskOrganizer.addFocusListener(this); mSplitUnsupportedToast = Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT); } @@ -455,8 +452,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } /** Launches an activity into split by legacy transition. */ - void startIntentLegacy(PendingIntent intent, Intent fillInIntent, - @SplitPosition int position, @Nullable Bundle options) { + void startIntentLegacy(PendingIntent intent, Intent fillInIntent, @SplitPosition int position, + @Nullable Bundle options) { + final boolean isEnteringSplit = !isSplitActive(); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictChildTasks(position, evictWct); @@ -466,22 +464,29 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback, SurfaceControl.Transaction t) { - if (apps == null || apps.length == 0) { - if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { - mMainExecutor.execute(() -> - exitSplitScreen(mMainStage.getChildCount() == 0 - ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN)); - mSplitUnsupportedToast.show(); + if (isEnteringSplit) { + boolean openingToSide = false; + if (apps != null) { + for (int i = 0; i < apps.length; ++i) { + if (apps[i].mode == MODE_OPENING + && mSideStage.containsTask(apps[i].taskId)) { + openingToSide = true; + break; + } + } + } + if (!openingToSide) { + mMainExecutor.execute(() -> exitSplitScreen( + mSideStage.getChildCount() == 0 ? mMainStage : mSideStage, + EXIT_REASON_UNKNOWN)); } - - // Do nothing when the animation was cancelled. - t.apply(); - return; } - for (int i = 0; i < apps.length; ++i) { - if (apps[i].mode == MODE_OPENING) { - t.show(apps[i].leash); + if (apps != null) { + for (int i = 0; i < apps.length; ++i) { + if (apps[i].mode == MODE_OPENING) { + t.show(apps[i].leash); + } } } t.apply(); @@ -503,7 +508,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, // If split still not active, apply windows bounds first to avoid surface reset to // wrong pos by SurfaceAnimator from wms. - if (!mMainStage.isActive() && mLogger.isEnterRequestedByDrag()) { + if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) { updateWindowBounds(mSplitLayout, wct); } @@ -1617,15 +1622,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode()); } - ActivityManager.RunningTaskInfo getFocusingTaskInfo() { - return mFocusingTaskInfo; - } - - @Override - public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { - mFocusingTaskInfo = taskInfo; - } - @Override public void onSnappedToDismiss(boolean bottomOrRight, int reason) { final boolean mainStageToTop = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java index 38b75f81171f6..f8ded7709c68e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java @@ -178,10 +178,10 @@ public class SplitScreenControllerTests extends ShellTestCase { Intent startIntent = createStartIntent("startActivity"); PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE); - // Put the same component into focus task - ActivityManager.RunningTaskInfo focusTaskInfo = + // Put the same component to the top running task + ActivityManager.RunningTaskInfo topRunningTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent); - doReturn(focusTaskInfo).when(mStageCoordinator).getFocusingTaskInfo(); + doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask(); doReturn(true).when(mStageCoordinator).isValidToEnterSplitScreen(any()); mSplitScreenController.startIntent(pendingIntent, null, SPLIT_POSITION_TOP_OR_LEFT, null); @@ -199,10 +199,10 @@ public class SplitScreenControllerTests extends ShellTestCase { Intent startIntent = createStartIntent("startActivity"); PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE); - // Put the same component into focus task - ActivityManager.RunningTaskInfo focusTaskInfo = + // Put the same component to the top running task + ActivityManager.RunningTaskInfo topRunningTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent); - doReturn(focusTaskInfo).when(mStageCoordinator).getFocusingTaskInfo(); + doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask(); doReturn(true).when(mStageCoordinator).isValidToEnterSplitScreen(any()); // Put the same component into a task in the background ActivityManager.RecentTaskInfo sameTaskInfo = new ActivityManager.RecentTaskInfo();