Introduce `SingleTask` and `SplitTask`

See go/refactor-group-task for details. This CL introduces `SingleTask`
and `SplitTask` and makes `GroupTask` abstract.

Bug: 388593902
Test: m
Flag: EXEMPT pure refactor with no behavior change.
Change-Id: I96d0eb0600420ce5cb2fff30ed9d766224b6961e
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index cb16345..bef753e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -32,6 +32,7 @@
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.SingleTask;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -270,7 +271,7 @@
 
         if (desktopTask != null) {
             mTasks = desktopTask.getTasks().stream()
-                    .map(GroupTask::new)
+                    .map(SingleTask::new)
                     .filter(task -> !shouldExcludeTask(task, taskIdsToExclude))
                     .collect(Collectors.toList());
             // All other tasks, apart from the grouped desktop task, are hidden
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 4afabde..753da9e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -29,6 +29,7 @@
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.util.DesktopTask
 import com.android.quickstep.util.GroupTask
+import com.android.quickstep.util.SingleTask
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import java.io.PrintWriter
 
@@ -204,7 +205,7 @@
         // Kind of hacky, we wrap each single task in the Desktop as a GroupTask.
         val orderFromId = orderedRunningTaskIds.withIndex().associate { (index, id) -> id to index }
         val sortedTasks = tasks.sortedWith(compareBy(nullsLast()) { orderFromId[it.key.id] })
-        return sortedTasks.map { GroupTask(it) }
+        return sortedTasks.map { SingleTask(it) }
     }
 
     private fun reloadRecentTasksIfNeeded() {
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index ee4ee38..ed394cb 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -39,6 +39,8 @@
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.SingleTask;
+import com.android.quickstep.util.SplitTask;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.wm.shell.Flags;
 import com.android.wm.shell.recents.IRecentTasksListener;
@@ -50,6 +52,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -360,22 +363,19 @@
                 final Task.TaskKey task1Key = new Task.TaskKey(taskInfo1);
                 final Task task1 = Task.from(task1Key, taskInfo1,
                         tmpLockedUsers.get(task1Key.userId) /* isLocked */);
-                final Task task2;
-                final SplitConfigurationOptions.SplitBounds launcherSplitBounds;
 
                 if (rawTask.isBaseType(TYPE_SPLIT)) {
                     final TaskInfo taskInfo2 = rawTask.getBaseGroupedTask().getTaskInfo2();
                     final Task.TaskKey task2Key = new Task.TaskKey(taskInfo2);
-                    task2 = Task.from(task2Key, taskInfo2,
+                    final Task task2 = Task.from(task2Key, taskInfo2,
                             tmpLockedUsers.get(task2Key.userId) /* isLocked */);
-                    launcherSplitBounds =
+                    final SplitConfigurationOptions.SplitBounds launcherSplitBounds =
                             convertShellSplitBoundsToLauncher(
                                     rawTask.getBaseGroupedTask().getSplitBounds());
+                    allTasks.add(new SplitTask(task1, task2, launcherSplitBounds));
                 } else {
-                    task2 = null;
-                    launcherSplitBounds = null;
+                    allTasks.add(new SingleTask(task1));
                 }
-                allTasks.add(new GroupTask(task1, task2, launcherSplitBounds));
             } else {
                 TaskInfo taskInfo1 = rawTask.getTaskInfo1();
                 TaskInfo taskInfo2 = rawTask.getTaskInfo2();
@@ -407,9 +407,14 @@
                 if (taskInfo1.isVisible) {
                     numVisibleTasks++;
                 }
-                final SplitConfigurationOptions.SplitBounds launcherSplitBounds =
-                        convertShellSplitBoundsToLauncher(rawTask.getSplitBounds());
-                allTasks.add(new GroupTask(task1, task2, launcherSplitBounds));
+                if (task2 != null) {
+                    Objects.requireNonNull(rawTask.getSplitBounds());
+                    final SplitConfigurationOptions.SplitBounds launcherSplitBounds =
+                            convertShellSplitBoundsToLauncher(rawTask.getSplitBounds());
+                    allTasks.add(new SplitTask(task1, task2, launcherSplitBounds));
+                } else {
+                    allTasks.add(new SingleTask(task1));
+                }
             }
         }
 
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 8edbacb..ef63b9b 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -142,7 +142,9 @@
         if (mSplitBounds == null) {
             SplitBounds shellSplitBounds = targets.extras.getParcelable(KEY_EXTRA_SPLIT_BOUNDS,
                     SplitBounds.class);
-            mSplitBounds = convertShellSplitBoundsToLauncher(shellSplitBounds);
+            if (shellSplitBounds != null) {
+                mSplitBounds = convertShellSplitBoundsToLauncher(shellSplitBounds);
+            }
         }
 
         boolean containsSplitTargets = mSplitBounds != null;
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index d9209bf..fff7e9b 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -33,7 +33,6 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.desktop.DesktopRecentsTransitionController;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
@@ -47,6 +46,7 @@
 import com.android.quickstep.GestureState;
 import com.android.quickstep.fallback.window.RecentsDisplayModel;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.SingleTask;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.views.OverviewActionsView;
@@ -210,7 +210,7 @@
             if (!found) {
                 ArrayList<GroupTask> newList = new ArrayList<>(taskGroups.size() + 1);
                 newList.addAll(taskGroups);
-                newList.add(new GroupTask(mHomeTask, null, null));
+                newList.add(new SingleTask(mHomeTask));
                 taskGroups = newList;
             }
         }
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.kt b/quickstep/src/com/android/quickstep/util/DesktopTask.kt
index 1cee2d2..5463cf7 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.kt
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.kt
@@ -17,7 +17,6 @@
 
 import com.android.quickstep.views.TaskViewType
 import com.android.systemui.shared.recents.model.Task
-import java.util.Objects
 
 /**
  * A [Task] container that can contain N number of tasks that are part of the desktop in recent
@@ -39,9 +38,6 @@
     override fun equals(o: Any?): Boolean {
         if (this === o) return true
         if (o !is DesktopTask) return false
-        if (!super.equals(o)) return false
-        return tasks == o.tasks
+        return super.equals(o)
     }
-
-    override fun hashCode() = Objects.hash(super.hashCode(), tasks)
 }
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.kt b/quickstep/src/com/android/quickstep/util/GroupTask.kt
index 0bee5f6..d5bbcd3 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.kt
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.kt
@@ -22,10 +22,10 @@
 import java.util.Objects
 
 /**
- * A [Task] container that can contain one or two tasks, depending on if the two tasks are
- * represented as an app-pair in the recents task list.
+ * An abstract class for creating [Task] containers that can be [SingleTask]s, [SplitTask]s, or
+ * [DesktopTask]s in the recent tasks list.
  */
-open class GroupTask
+abstract class GroupTask
 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
 constructor(
     @Deprecated("Prefer using `getTasks()` instead") @JvmField val task1: Task,
@@ -33,13 +33,16 @@
     @JvmField val mSplitBounds: SplitConfigurationOptions.SplitBounds?,
     @JvmField val taskViewType: TaskViewType,
 ) {
-    constructor(task: Task) : this(task, null, null)
-
-    constructor(
-        t1: Task,
-        t2: Task?,
+    protected constructor(
+        task1: Task,
+        task2: Task?,
         splitBounds: SplitConfigurationOptions.SplitBounds?,
-    ) : this(t1, t2, splitBounds, if (t2 != null) TaskViewType.GROUPED else TaskViewType.SINGLE)
+    ) : this(
+        task1,
+        task2,
+        splitBounds,
+        if (task2 != null) TaskViewType.GROUPED else TaskViewType.SINGLE,
+    )
 
     open fun containsTask(taskId: Int) =
         task1.key.id == taskId || (task2 != null && task2.key.id == taskId)
@@ -59,18 +62,50 @@
         get() = listOfNotNull(task1, task2)
 
     /** Creates a copy of this instance */
-    open fun copy() = GroupTask(Task(task1), if (task2 != null) Task(task2) else null, mSplitBounds)
+    abstract fun copy(): GroupTask
 
     override fun toString() = "type=$taskViewType task1=$task1 task2=$task2"
 
     override fun equals(o: Any?): Boolean {
         if (this === o) return true
         if (o !is GroupTask) return false
-        return taskViewType == o.taskViewType &&
-            task1 == o.task1 &&
-            task2 == o.task2 &&
-            mSplitBounds == o.mSplitBounds
+        return taskViewType == o.taskViewType && tasks == o.tasks
     }
 
-    override fun hashCode() = Objects.hash(task1, task2, mSplitBounds, taskViewType)
+    override fun hashCode() = Objects.hash(tasks, taskViewType)
+}
+
+/** A [Task] container that must contain exactly one task in the recent tasks list. */
+class SingleTask(task: Task) :
+    GroupTask(task, task2 = null, mSplitBounds = null, TaskViewType.SINGLE) {
+    override fun copy() = SingleTask(task1)
+
+    override fun toString() = "type=$taskViewType task=$task1"
+
+    override fun equals(o: Any?): Boolean {
+        if (this === o) return true
+        if (o !is SingleTask) return false
+        return super.equals(o)
+    }
+}
+
+/**
+ * A [Task] container that must contain exactly two tasks and split bounds to represent an app-pair
+ * in the recent tasks list.
+ */
+class SplitTask(task1: Task, task2: Task, splitBounds: SplitConfigurationOptions.SplitBounds) :
+    GroupTask(task1, task2, splitBounds, TaskViewType.GROUPED) {
+
+    override fun copy() = SplitTask(task1, task2!!, mSplitBounds!!)
+
+    override fun toString() = "type=$taskViewType task1=$task1 task2=$task2"
+
+    override fun equals(o: Any?): Boolean {
+        if (this === o) return true
+        if (o !is SplitTask) return false
+        if (mSplitBounds!! != o.mSplitBounds!!) return false
+        return super.equals(o)
+    }
+
+    override fun hashCode() = Objects.hash(super.hashCode(), mSplitBounds)
 }
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
index d982e81..4005c5a 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -33,38 +33,34 @@
         // TODO(b/254378592): Remove these methods when the two classes are reunited
         /** Converts the shell version of SplitBounds to the launcher version */
         @JvmStatic
-        fun convertShellSplitBoundsToLauncher(
-            shellSplitBounds: SplitBounds?
-        ): SplitConfigurationOptions.SplitBounds? {
-            return if (shellSplitBounds == null) {
-                null
-            } else {
-                SplitConfigurationOptions.SplitBounds(
-                    shellSplitBounds.leftTopBounds,
-                    shellSplitBounds.rightBottomBounds,
-                    shellSplitBounds.leftTopTaskId,
-                    shellSplitBounds.rightBottomTaskId,
-                    shellSplitBounds.snapPosition
-                )
-            }
-        }
+        fun convertShellSplitBoundsToLauncher(shellSplitBounds: SplitBounds) =
+            SplitConfigurationOptions.SplitBounds(
+                shellSplitBounds.leftTopBounds,
+                shellSplitBounds.rightBottomBounds,
+                shellSplitBounds.leftTopTaskId,
+                shellSplitBounds.rightBottomTaskId,
+                shellSplitBounds.snapPosition,
+            )
 
         /**
          * Given a TransitionInfo, generates the tree structure for those changes and extracts out
-         * the top most root and it's two immediate children.
-         * Changes can be provided in any order.
+         * the top most root and it's two immediate children. Changes can be provided in any order.
          *
-         * @return a [Pair] where first -> top most split root,
-         *         second -> [List] of 2, leftTop/bottomRight stage roots
+         * @return a [Pair] where first -> top most split root, second -> [List] of 2,
+         *   leftTop/bottomRight stage roots
          */
-        fun extractTopParentAndChildren(transitionInfo: TransitionInfo):
-                Pair<Change, List<Change>>? {
+        fun extractTopParentAndChildren(
+            transitionInfo: TransitionInfo
+        ): Pair<Change, List<Change>>? {
             val parentToChildren = mutableMapOf<Change, MutableList<Change>>()
             val hasParent = mutableSetOf<Change>()
             // filter out anything that isn't opening and the divider
-            val taskChanges: List<Change> = transitionInfo.changes
-                    .filter { change -> (change.mode == TRANSIT_OPEN ||
-                            change.mode == TRANSIT_TO_FRONT) && change.flags < FLAG_FIRST_CUSTOM}
+            val taskChanges: List<Change> =
+                transitionInfo.changes
+                    .filter { change ->
+                        (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT) &&
+                            change.flags < FLAG_FIRST_CUSTOM
+                    }
                     .toList()
 
             // 1. Build Parent-Child Relationships
@@ -73,8 +69,8 @@
                 //  startAnimation() and we can know the precise taskIds of launching tasks.
                 change.parent?.let { parent ->
                     parentToChildren
-                            .getOrPut(transitionInfo.getChange(parent)!!) { mutableListOf() }
-                            .add(change)
+                        .getOrPut(transitionInfo.getChange(parent)!!) { mutableListOf() }
+                        .add(change)
                     hasParent.add(change)
                 }
             }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 8d8e62e..2374cc1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -21,6 +21,7 @@
 import android.content.Context
 import android.content.Intent
 import android.content.res.Resources
+import android.graphics.Rect
 import android.os.Process
 import android.os.UserHandle
 import android.platform.test.annotations.EnableFlags
@@ -35,12 +36,16 @@
 import com.android.launcher3.model.data.TaskItemInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.RecentsModel.RecentTasksChangedListener
 import com.android.quickstep.TaskIconCache
 import com.android.quickstep.util.DesktopTask
 import com.android.quickstep.util.GroupTask
+import com.android.quickstep.util.SingleTask
+import com.android.quickstep.util.SplitTask
 import com.android.systemui.shared.recents.model.Task
+import com.android.wm.shell.shared.split.SplitScreenConstants
 import com.google.common.truth.Truth.assertThat
 import java.util.function.Consumer
 import org.junit.Before
@@ -912,15 +917,21 @@
         return packageNames.map { packageName ->
             if (packageName.startsWith("split")) {
                 val splitPackages = packageName.split("_")
-                GroupTask(
+                SplitTask(
                     createTask(100, splitPackages[0]),
                     createTask(101, splitPackages[1]),
-                    /* splitBounds = */ null,
+                    SplitConfigurationOptions.SplitBounds(
+                        /* leftTopBounds = */ Rect(),
+                        /* rightBottomBounds = */ Rect(),
+                        /* leftTopTaskId = */ -1,
+                        /* rightBottomTaskId = */ -1,
+                        /* snapPosition = */ SplitScreenConstants.SNAP_TO_2_50_50,
+                    ),
                 )
             } else {
                 // Use the number at the end of the test packageName as the id.
                 val id = 1000 + packageName[packageName.length - 1].code
-                GroupTask(createTask(id, packageName))
+                SingleTask(createTask(id, packageName))
             }
         }
     }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
index e7f3523..df70b10 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarViewTestUtil.kt
@@ -28,6 +28,7 @@
 import com.android.launcher3.taskbar.TaskbarIconType.OVERFLOW
 import com.android.launcher3.taskbar.TaskbarIconType.RECENT
 import com.android.quickstep.util.GroupTask
+import com.android.quickstep.util.SingleTask
 import com.android.systemui.shared.recents.model.Task
 import com.android.systemui.shared.recents.model.Task.TaskKey
 import com.google.common.truth.FailureMetadata
@@ -56,7 +57,7 @@
     /** Creates a list of fake recent tasks. */
     fun createRecents(size: Int): List<GroupTask> {
         return List(size) {
-            GroupTask(
+            SingleTask(
                 Task().apply {
                     key =
                         TaskKey(
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 542eb64..0c74610 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -18,6 +18,8 @@
 
 import static com.android.quickstep.AbsSwipeUpHandler.STATE_HANDLER_INVALIDATED;
 import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
+import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
@@ -68,6 +70,7 @@
 import com.android.quickstep.views.RecentsViewContainer;
 import com.android.systemui.shared.Flags;
 import com.android.systemui.shared.system.InputConsumerController;
+import com.android.wm.shell.shared.split.SplitBounds;
 
 import com.google.android.msdl.data.model.MSDLToken;
 
@@ -140,6 +143,12 @@
     public void setUpAnimationTargets() {
         Bundle extras = new Bundle();
         extras.putBoolean(KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION, true);
+        extras.putParcelable(KEY_EXTRA_SPLIT_BOUNDS, new SplitBounds(
+                /* leftTopBounds = */ new Rect(),
+                /* rightBottomBounds = */ new Rect(),
+                /* leftTopTaskId = */ -1,
+                /* rightBottomTaskId = */ -1,
+                /* snapPosition = */ SNAP_TO_2_50_50));
         mRecentsAnimationTargets = new RecentsAnimationTargets(
                 new RemoteAnimationTarget[] {mRemoteAnimationTarget},
                 new RemoteAnimationTarget[] {mRemoteAnimationTarget},
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java
index ccfe36d..d168ba1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentTasksListTest.java
@@ -33,6 +33,7 @@
 import android.app.TaskInfo;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Rect;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -43,6 +44,8 @@
 import com.android.quickstep.views.TaskViewType;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.wm.shell.shared.GroupedTaskInfo;
+import com.android.wm.shell.shared.split.SplitBounds;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -97,7 +100,12 @@
     @Test
     public void loadTasksInBackground_onlyKeys_noValidTaskDescription() throws Exception  {
         GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forSplitTasks(
-                new RecentTaskInfo(), new RecentTaskInfo(), null);
+                new RecentTaskInfo(), new RecentTaskInfo(), new SplitBounds(
+                        /* leftTopBounds = */ new Rect(),
+                        /* rightBottomBounds = */ new Rect(),
+                        /* leftTopTaskId = */ -1,
+                        /* rightBottomTaskId = */ -1,
+                        /* snapPosition = */ SplitScreenConstants.SNAP_TO_2_50_50));
         when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
 
@@ -127,7 +135,13 @@
         task1.taskDescription = new ActivityManager.TaskDescription(taskDescription);
         RecentTaskInfo task2 = new RecentTaskInfo();
         task2.taskDescription = new ActivityManager.TaskDescription();
-        GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forSplitTasks(task1, task2, null);
+        GroupedTaskInfo recentTaskInfos = GroupedTaskInfo.forSplitTasks(task1, task2,
+                new SplitBounds(
+                        /* leftTopBounds = */ new Rect(),
+                        /* rightBottomBounds = */ new Rect(),
+                        /* leftTopTaskId = */ -1,
+                        /* rightBottomTaskId = */ -1,
+                        /* snapPosition = */ SplitScreenConstants.SNAP_TO_2_50_50));
         when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
                 .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsModelTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsModelTest.java
index a5c60ce..99a1c59 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsModelTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RecentsModelTest.java
@@ -32,6 +32,7 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.annotation.UiThreadTest;
@@ -42,9 +43,12 @@
 import com.android.launcher3.R;
 import com.android.launcher3.graphics.ThemeManager;
 import com.android.launcher3.icons.IconProvider;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.SplitTask;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -173,7 +177,13 @@
         Task.TaskKey taskKey2 = new Task.TaskKey(taskInfo2);
         Task task2 = Task.from(taskKey2, taskInfo2, false);
 
-        allTasks.add(new GroupTask(task1, task2, null));
+        allTasks.add(
+                new SplitTask(task1, task2, new SplitConfigurationOptions.SplitBounds(
+                        /* leftTopBounds = */ new Rect(),
+                        /* rightBottomBounds = */ new Rect(),
+                        /* leftTopTaskId = */ -1,
+                        /* rightBottomTaskId = */ -1,
+                        /* snapPosition = */ SplitScreenConstants.SNAP_TO_2_50_50)));
         return allTasks;
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index b6cf5bd..823f808 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -19,13 +19,17 @@
 import android.content.ComponentName
 import android.content.Intent
 import android.graphics.Bitmap
+import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TestDispatcherProvider
 import com.android.quickstep.util.DesktopTask
-import com.android.quickstep.util.GroupTask
+import com.android.quickstep.util.SingleTask
+import com.android.quickstep.util.SplitTask
 import com.android.systemui.shared.recents.model.Task
 import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.first
@@ -48,8 +52,18 @@
     private val tasks = (0..5).map(::createTaskWithId)
     private val defaultTaskList =
         listOf(
-            GroupTask(tasks[0]),
-            GroupTask(tasks[1], tasks[2], null),
+            SingleTask(tasks[0]),
+            SplitTask(
+                tasks[1],
+                tasks[2],
+                SplitConfigurationOptions.SplitBounds(
+                    /* leftTopBounds = */ Rect(),
+                    /* rightBottomBounds = */ Rect(),
+                    /* leftTopTaskId = */ -1,
+                    /* rightBottomTaskId = */ -1,
+                    /* snapPosition = */ SNAP_TO_2_50_50,
+                ),
+            ),
             DesktopTask(tasks.subList(3, 6)),
         )
     private val recentsModel = FakeRecentTasksDataSource()
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
index 108cfb5..fa043b9 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/GroupTaskTest.kt
@@ -21,7 +21,6 @@
 import android.graphics.Rect
 import com.android.launcher3.util.LauncherMultivalentJUnit
 import com.android.launcher3.util.SplitConfigurationOptions
-import com.android.quickstep.views.TaskViewType
 import com.android.systemui.shared.recents.model.Task
 import com.android.wm.shell.shared.split.SplitScreenConstants
 import com.google.common.truth.Truth.assertThat
@@ -33,28 +32,28 @@
 
     @Test
     fun testGroupTask_sameInstance_isEqual() {
-        val task = GroupTask(createTask(1))
+        val task = SingleTask(createTask(1))
         assertThat(task).isEqualTo(task)
     }
 
     @Test
     fun testGroupTask_identicalConstructor_isEqual() {
-        val task1 = GroupTask(createTask(1))
-        val task2 = GroupTask(createTask(1))
+        val task1 = SingleTask(createTask(1))
+        val task2 = SingleTask(createTask(1))
         assertThat(task1).isEqualTo(task2)
     }
 
     @Test
     fun testGroupTask_copy_isEqual() {
-        val task1 = GroupTask(createTask(1))
+        val task1 = SingleTask(createTask(1))
         val task2 = task1.copy()
         assertThat(task1).isEqualTo(task2)
     }
 
     @Test
     fun testGroupTask_differentId_isNotEqual() {
-        val task1 = GroupTask(createTask(1))
-        val task2 = GroupTask(createTask(2))
+        val task1 = SingleTask(createTask(1))
+        val task2 = SingleTask(createTask(2))
         assertThat(task1).isNotEqualTo(task2)
     }
 
@@ -66,10 +65,10 @@
                 Rect(),
                 1,
                 2,
-                SplitScreenConstants.SNAP_TO_2_50_50
+                SplitScreenConstants.SNAP_TO_2_50_50,
             )
-        val task1 = GroupTask(createTask(1), createTask(2), splitBounds, TaskViewType.GROUPED)
-        val task2 = GroupTask(createTask(1), createTask(2), splitBounds, TaskViewType.GROUPED)
+        val task1 = SplitTask(createTask(1), createTask(2), splitBounds)
+        val task2 = SplitTask(createTask(1), createTask(2), splitBounds)
         assertThat(task1).isEqualTo(task2)
     }
 
@@ -81,7 +80,7 @@
                 Rect(),
                 1,
                 2,
-                SplitScreenConstants.SNAP_TO_2_50_50
+                SplitScreenConstants.SNAP_TO_2_50_50,
             )
         val splitBounds2 =
             SplitConfigurationOptions.SplitBounds(
@@ -89,17 +88,17 @@
                 Rect(),
                 1,
                 2,
-                SplitScreenConstants.SNAP_TO_2_33_66
+                SplitScreenConstants.SNAP_TO_2_33_66,
             )
-        val task1 = GroupTask(createTask(1), createTask(2), splitBounds1, TaskViewType.GROUPED)
-        val task2 = GroupTask(createTask(1), createTask(2), splitBounds2, TaskViewType.GROUPED)
+        val task1 = SplitTask(createTask(1), createTask(2), splitBounds1)
+        val task2 = SplitTask(createTask(1), createTask(2), splitBounds2)
         assertThat(task1).isNotEqualTo(task2)
     }
 
     @Test
     fun testGroupTask_differentType_isNotEqual() {
-        val task1 = GroupTask(createTask(1), null, null, TaskViewType.SINGLE)
-        val task2 = GroupTask(createTask(1), null, null, TaskViewType.DESKTOP)
+        val task1 = SingleTask(createTask(1))
+        val task2 = DesktopTask(listOf(createTask(1)))
         assertThat(task1).isNotEqualTo(task2)
     }
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index 708273e..0491c07 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -660,10 +660,16 @@
         intent.component = task2ComponentName
         taskInfo.baseIntent = intent
         task2.key = Task.TaskKey(taskInfo)
-        return GroupTask(
+        return SplitTask(
             task1,
             task2,
-            SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_2_50_50),
+            SplitConfigurationOptions.SplitBounds(
+                /* leftTopBounds = */ Rect(),
+                /* rightBottomBounds = */ Rect(),
+                /* leftTopTaskId = */ -1,
+                /* rightBottomTaskId = */ -1,
+                /* snapPosition = */ SNAP_TO_2_50_50,
+            ),
         )
     }
 
@@ -692,10 +698,16 @@
         intent.component = task2ComponentName
         taskInfo.baseIntent = intent
         task2.key = Task.TaskKey(taskInfo)
-        return GroupTask(
+        return SplitTask(
             task1,
             task2,
-            SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_2_50_50),
+            SplitConfigurationOptions.SplitBounds(
+                /* leftTopBounds = */ Rect(),
+                /* rightBottomBounds = */ Rect(),
+                /* leftTopTaskId = */ -1,
+                /* rightBottomTaskId = */ -1,
+                /* snapPosition = */ SNAP_TO_2_50_50,
+            ),
         )
     }
 }