Merge "Enhance error handling logic to restore split-screen" into tm-qpr-dev am: c583cc014d

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

Change-Id: I3a0e6b64a63f4833d381821aa230fd20656bcc6c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index e0ad9cb..7d7c59e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -500,7 +500,9 @@
                     || (taskInfo.topActivityType == WindowConfiguration.ACTIVITY_TYPE_HOME
                     && taskInfo.isVisible);
             final boolean focusTaskChanged = (mLastFocusedTaskInfo == null
-                    || mLastFocusedTaskInfo.taskId != taskInfo.taskId) && isFocusedOrHome;
+                    || mLastFocusedTaskInfo.taskId != taskInfo.taskId
+                    || mLastFocusedTaskInfo.getWindowingMode() != taskInfo.getWindowingMode())
+                    && isFocusedOrHome;
             if (focusTaskChanged) {
                 for (int i = 0; i < mFocusListeners.size(); i++) {
                     mFocusListeners.valueAt(i).onFocusTaskChanged(taskInfo);
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 249468d..21bea46 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
@@ -24,8 +24,6 @@
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-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.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -64,7 +62,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.InstanceId;
 import com.android.internal.protolog.common.ProtoLog;
-import com.android.internal.util.ArrayUtils;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -102,7 +99,7 @@
  */
 // TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
 public class SplitScreenController implements DragAndDropPolicy.Starter,
-        RemoteCallable<SplitScreenController>, ShellTaskOrganizer.FocusListener {
+        RemoteCallable<SplitScreenController> {
     private static final String TAG = SplitScreenController.class.getSimpleName();
 
     public static final int EXIT_REASON_UNKNOWN = 0;
@@ -150,8 +147,6 @@
     // outside the bounds of the roots by being reparented into a higher level fullscreen container
     private SurfaceControl mSplitTasksContainerLayer;
 
-    private ActivityManager.RunningTaskInfo mFocusingTaskInfo;
-
     public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue, Context context,
             RootTaskDisplayAreaOrganizer rootTDAOrganizer,
@@ -173,7 +168,6 @@
         mLogger = new SplitscreenEventLogger();
         mIconProvider = iconProvider;
         mRecentTasksOptional = recentTasks;
-        mTaskOrganizer.addFocusListener(this);
     }
 
     public SplitScreen asSplitScreen() {
@@ -190,11 +184,6 @@
         return mMainExecutor;
     }
 
-    @Override
-    public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
-        mFocusingTaskInfo = taskInfo;
-    }
-
     public void onOrganizerRegistered() {
         if (mStageCoordinator == null) {
             // TODO: Multi-display
@@ -213,6 +202,14 @@
         return mStageCoordinator;
     }
 
+    public ActivityManager.RunningTaskInfo getFocusingTaskInfo() {
+        return mStageCoordinator.getFocusingTaskInfo();
+    }
+
+    public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
+        return mStageCoordinator.isValidToEnterSplitScreen(taskInfo);
+    }
+
     @Nullable
     public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
         if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
@@ -228,12 +225,6 @@
                 && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
     }
 
-    public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
-        return taskInfo.supportsMultiWindow
-                && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())
-                && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode());
-    }
-
     public @SplitPosition int getSplitPosition(int taskId) {
         return mStageCoordinator.getSplitPosition(taskId);
     }
@@ -470,8 +461,9 @@
             return Objects.equals(launchingActivity, pairedActivity);
         }
 
-        if (mFocusingTaskInfo != null && isValidToEnterSplitScreen(mFocusingTaskInfo)) {
-            return Objects.equals(mFocusingTaskInfo.baseIntent.getComponent(), launchingActivity);
+        final ActivityManager.RunningTaskInfo taskInfo = getFocusingTaskInfo();
+        if (taskInfo != null && isValidToEnterSplitScreen(taskInfo)) {
+            return Objects.equals(taskInfo.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 3e65946..2229e26 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
@@ -35,6 +35,8 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
 import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
+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.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
@@ -98,6 +100,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.InstanceId;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.ArrayUtils;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -138,7 +141,7 @@
  */
 public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
         DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler,
-        ShellTaskOrganizer.TaskListener {
+        ShellTaskOrganizer.TaskListener, ShellTaskOrganizer.FocusListener {
 
     private static final String TAG = StageCoordinator.class.getSimpleName();
 
@@ -176,6 +179,8 @@
     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.
      */
@@ -255,6 +260,7 @@
         mDisplayController.addDisplayWindowListener(this);
         mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
         transitions.addHandler(this);
+        mTaskOrganizer.addFocusListener(this);
     }
 
     @VisibleForTesting
@@ -1226,12 +1232,21 @@
                 }
             }
         } else if (isSideStage && !mMainStage.isActive()) {
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            mSplitLayout.init();
-            prepareEnterSplitScreen(wct);
-            mSyncQueue.queue(wct);
-            mSyncQueue.runInSync(t ->
-                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+            if (mFocusingTaskInfo != null && !isValidToEnterSplitScreen(mFocusingTaskInfo)) {
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                mSideStage.removeAllTasks(wct, true);
+                wct.reorder(mRootTaskInfo.token, false /* onTop */);
+                mTaskOrganizer.applyTransaction(wct);
+                Slog.i(TAG, "cancel entering split screen, reason = "
+                        + exitReasonToString(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW));
+            } else {
+                final WindowContainerTransaction wct = new WindowContainerTransaction();
+                mSplitLayout.init();
+                prepareEnterSplitScreen(wct);
+                mSyncQueue.queue(wct);
+                mSyncQueue.runInSync(t ->
+                        updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+            }
         }
         if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
             mShouldUpdateRecents = true;
@@ -1246,6 +1261,21 @@
         }
     }
 
+    boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
+        return taskInfo.supportsMultiWindow
+                && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())
+                && 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 c90a825..c10e4a1 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
@@ -24,6 +24,7 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
@@ -90,12 +91,13 @@
     @Test
     public void testIsLaunchingAdjacently_notInSplitScreen() {
         doReturn(false).when(mSplitScreenController).isSplitScreenVisible();
+        doReturn(true).when(mSplitScreenController).isValidToEnterSplitScreen(any());
 
         // Verify launching the same activity returns true.
         Intent startIntent = createStartIntent("startActivity");
         ActivityManager.RunningTaskInfo focusTaskInfo =
                 createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
-        mSplitScreenController.onFocusTaskChanged(focusTaskInfo);
+        doReturn(focusTaskInfo).when(mSplitScreenController).getFocusingTaskInfo();
         assertTrue(mSplitScreenController.isLaunchingAdjacently(
                 startIntent, SPLIT_POSITION_TOP_OR_LEFT));
 
@@ -103,7 +105,7 @@
         Intent diffIntent = createStartIntent("diffActivity");
         focusTaskInfo =
                 createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, diffIntent);
-        mSplitScreenController.onFocusTaskChanged(focusTaskInfo);
+        doReturn(focusTaskInfo).when(mSplitScreenController).getFocusingTaskInfo();
         assertFalse(mSplitScreenController.isLaunchingAdjacently(
                 startIntent, SPLIT_POSITION_TOP_OR_LEFT));
     }