Remove all external usages of GroupTask.task1/2 from Launcher3

See go/refactor-group-task for details. This CL removes all the usages
of `task1` and `task2` from `GroupTask` in Launcher3. Follow-up CLs will
remove it from NexusLauncher and remove the fields altogether.

Bug: 388593902
Test: m
Flag: EXEMPT pure refactor with no behavior change.
Change-Id: I902c8135b3a0aae95acf25267b3bcbf286bd4e7d
This commit is contained in:
Ahmed Fakhry
2025-01-31 17:14:44 +00:00
parent 51a340a3c4
commit b6ecf5889e
16 changed files with 191 additions and 144 deletions
@@ -233,7 +233,8 @@ public final class KeyboardQuickSwitchController implements
}
private boolean shouldExcludeTask(GroupTask task, Set<Integer> taskIdsToExclude) {
return Flags.taskbarOverflow() && taskIdsToExclude.contains(task.task1.key.id);
return Flags.taskbarOverflow() && task.getTasks().stream().anyMatch(
t -> taskIdsToExclude.contains(t.key.id));
}
private void processLoadedTasks(List<GroupTask> tasks, Set<Integer> taskIdsToExclude) {
@@ -51,6 +51,9 @@ import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
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.system.InteractionJankMonitorWrapper;
import java.util.HashMap;
@@ -255,14 +258,21 @@ public class KeyboardQuickSwitchView extends ConstraintLayout {
layoutInflater,
previousTaskView);
final boolean firstTaskIsLeftTopTask =
groupTask.mSplitBounds == null
|| groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id
|| groupTask.task2 == null;
Task task1;
Task task2;
if (groupTask instanceof SplitTask splitTask) {
task1 = splitTask.getTopLeftTask();
task2 = splitTask.getBottomRightTask();
} else if (groupTask instanceof SingleTask singleTask) {
task1 = singleTask.getTask();
task2 = null;
} else {
continue;
}
currentTaskView.setThumbnailsForSplitTasks(
firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2,
firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1,
task1,
task2,
updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
updateTasks ? mViewCallbacks::updateIconInBackground : null,
groupTask.mSplitBounds);
@@ -44,6 +44,7 @@ import com.android.launcher3.util.DisplayController;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SingleTask;
import com.android.quickstep.util.SlideInRemoteTransition;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -281,9 +282,10 @@ public class KeyboardQuickSwitchViewController {
return -1;
}
RemoteTransition remoteTransition = slideInTransition;
if (mOnDesktop
&& mControllers.taskbarActivityContext.canUnminimizeDesktopTask(task.task1.key.id)
) {
boolean canUnminimizeDesktopTask = task instanceof SingleTask singleTask
&& mControllers.taskbarActivityContext.canUnminimizeDesktopTask(
singleTask.getTask().key.id);
if (mOnDesktop && canUnminimizeDesktopTask) {
// This app is being unminimized - use our own transition runner.
remoteTransition = new RemoteTransition(
new DesktopAppLaunchTransition(
@@ -49,7 +49,7 @@ import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.HomeVisibilityState;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SplitTask;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -480,8 +480,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
@Override
public void launchSplitTasks(
@NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
mLauncher.launchSplitTasks(groupTask, remoteTransition);
@NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) {
mLauncher.launchSplitTasks(splitTask, remoteTransition);
}
@Override
@@ -155,6 +155,8 @@ import com.android.quickstep.RecentsModel;
import com.android.quickstep.SystemUiProxy;
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.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -1293,11 +1295,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
if (tag instanceof GroupTask groupTask) {
// TODO: b/316004172, b/343289567: Handle `DesktopTask` and `SplitTask`.
if (tag instanceof SingleTask singleTask) {
RemoteTransition remoteTransition =
(areDesktopTasksVisible() && canUnminimizeDesktopTask(groupTask.task1.key.id))
(areDesktopTasksVisible() && canUnminimizeDesktopTask(
singleTask.getTask().key.id))
? createDesktopAppLaunchRemoteTransition(AppLaunchType.UNMINIMIZE,
Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
: null;
if (areDesktopTasksVisible() && mControllers.uiController.isInOverviewUi()) {
RunnableList runnableList = recents.launchRunningDesktopTaskView();
@@ -1305,12 +1309,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
// launch.
if (runnableList != null) {
runnableList.add(() -> UI_HELPER_EXECUTOR.execute(
() -> handleGroupTaskLaunch(groupTask, remoteTransition,
() -> handleGroupTaskLaunch(singleTask, remoteTransition,
areDesktopTasksVisible(),
DesktopTaskToFrontReason.TASKBAR_TAP)));
}
} else {
handleGroupTaskLaunch(groupTask, remoteTransition, areDesktopTasksVisible(),
handleGroupTaskLaunch(singleTask, remoteTransition, areDesktopTasksVisible(),
DesktopTaskToFrontReason.TASKBAR_TAP);
}
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
@@ -1480,13 +1484,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
remoteTransition));
return;
}
if (onDesktop) {
boolean useRemoteTransition = canUnminimizeDesktopTask(task.task1.key.id);
if (onDesktop && task instanceof SingleTask singleTask) {
boolean useRemoteTransition = canUnminimizeDesktopTask(singleTask.getTask().key.id);
UI_HELPER_EXECUTOR.execute(() -> {
if (onStartCallback != null) {
onStartCallback.run();
}
SystemUiProxy.INSTANCE.get(this).showDesktopApp(task.task1.key.id,
SystemUiProxy.INSTANCE.get(this).showDesktopApp(singleTask.getTask().key.id,
useRemoteTransition ? remoteTransition : null, toFrontReason);
if (onFinishCallback != null) {
onFinishCallback.run();
@@ -1494,18 +1498,19 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
});
return;
}
if (task.task2 == null) {
if (task instanceof SingleTask singleTask) {
UI_HELPER_EXECUTOR.execute(() -> {
ActivityOptions activityOptions =
makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED).options;
activityOptions.setRemoteTransition(remoteTransition);
ActivityManagerWrapper.getInstance().startActivityFromRecents(
task.task1.key, activityOptions);
singleTask.getTask().key, activityOptions);
});
return;
}
mControllers.uiController.launchSplitTasks(task, remoteTransition);
assert task instanceof SplitTask;
mControllers.uiController.launchSplitTasks((SplitTask) task, remoteTransition);
}
/** Returns whether the given task is minimized and can be unminimized. */
@@ -80,9 +80,9 @@ import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.views.BubbleTextHolder;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LogUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.SingleTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.shared.draganddrop.DragAndDropConstants;
@@ -433,8 +433,8 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im
null, item.user));
}
intent.putExtra(Intent.EXTRA_USER, item.user);
} else if (tag instanceof GroupTask groupTask && !groupTask.hasMultipleTasks()) {
Task task = groupTask.task1;
} else if (tag instanceof SingleTask singleTask) {
Task task = singleTask.getTask();
clipDescription = new ClipDescription(task.titleDescription,
new String[] {
ClipDescription.MIMETYPE_APPLICATION_TASK
@@ -76,12 +76,14 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
var shownTasks: List<GroupTask> = emptyList()
private set
val shownTaskIds: List<Int>
get() = shownTasks.flatMap { shownTask -> shownTask.tasks }.map { it.key.id }
/**
* The task-state of an app, i.e. whether the app has a task and what state
* that task is in.
* The task-state of an app, i.e. whether the app has a task and what state that task is in.
*
* @property taskId The ID of the task if one exists (i.e. if the state is
* RUNNING or MINIMIZED), null otherwise (NOT_RUNNING).
* @property taskId The ID of the task if one exists (i.e. if the state is RUNNING or
* MINIMIZED), null otherwise (NOT_RUNNING).
*/
data class TaskState(val runningAppState: RunningAppState, val taskId: Int? = null)
@@ -214,9 +216,9 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
return shownHotseatItems.toTypedArray()
}
private fun getOrderedAndWrappedDesktopTasks(): List<GroupTask> {
private fun getOrderedAndWrappedDesktopTasks(): List<SingleTask> {
val tasks = desktopTask?.tasks ?: emptyList()
// Kind of hacky, we wrap each single task in the Desktop as a GroupTask.
// We wrap each task in the Desktop as a `SingleTask`.
val orderFromId = orderedRunningTaskIds.withIndex().associate { (index, id) -> id to index }
val sortedTasks = tasks.sortedWith(compareBy(nullsLast()) { orderFromId[it.key.id] })
return sortedTasks.map { SingleTask(it) }
@@ -286,7 +288,7 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
}
private fun updateOrderedRunningTaskIds(): MutableList<Int> {
val desktopTasksAsList = getOrderedAndWrappedDesktopTasks().flatMap { it.tasks }
val desktopTasksAsList = getOrderedAndWrappedDesktopTasks().map { it.task }
val desktopTaskIds = desktopTasksAsList.map { it.key.id }
var newOrder =
orderedRunningTaskIds
@@ -311,42 +313,43 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
val newShownTasks =
if (Flags.enableMultiInstanceMenuTaskbar()) {
val deduplicatedDesktopTasks =
desktopTasks.distinctBy { Pair(it.task1.key.packageName, it.task1.key.userId) }
desktopTasks.distinctBy { Pair(it.task.key.packageName, it.task.key.userId) }
shownTasks
.filter {
!it.supportsMultipleTasks() &&
it.task1.key.id in deduplicatedDesktopTasks.map { it.task1.key.id }
it is SingleTask &&
it.task.key.id in deduplicatedDesktopTasks.map { it.task.key.id }
}
.toMutableList()
.apply {
addAll(
deduplicatedDesktopTasks.filter { currentTask ->
val currentTaskKey = currentTask.task1.key
currentTaskKey.id !in shownTasks.map { it.task1.key.id } &&
val currentTaskKey = currentTask.task.key
currentTaskKey.id !in shownTaskIds &&
shownHotseatItems.none { hotseatItem ->
hotseatItem.targetPackage == currentTaskKey.packageName &&
hotseatItem.user.identifier == currentTaskKey.userId
currentTask.containsPackage(
hotseatItem.targetPackage,
hotseatItem.user.identifier,
)
}
}
)
}
} else {
val desktopTaskIds = desktopTasks.map { it.task1.key.id }
val desktopTaskIds = desktopTasks.map { it.task.key.id }
val shownHotseatItemTaskIds =
shownHotseatItems.mapNotNull { it as? TaskItemInfo }.map { it.taskId }
shownTasks
.filter { !it.supportsMultipleTasks() && it.task1.key.id in desktopTaskIds }
.filter { it is SingleTask && it.task.key.id in desktopTaskIds }
.toMutableList()
.apply {
addAll(
desktopTasks.filter { desktopTask ->
desktopTask.task1.key.id !in
shownTasks.map { shownTask -> shownTask.task1.key.id }
desktopTask.task.key.id !in shownTaskIds
}
)
removeAll { it.task1.key.id in shownHotseatItemTaskIds }
removeAll { it is SingleTask && it.task.key.id in shownHotseatItemTaskIds }
}
}
@@ -371,21 +374,28 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
groupTasks: List<GroupTask>,
shownHotseatItems: List<ItemInfo>,
): List<GroupTask> {
// TODO: b/393476333 - Check the behavior of the Taskbar recents section when empty desks
// become supported.
return if (Flags.enableMultiInstanceMenuTaskbar()) {
groupTasks.filter { groupTask ->
val taskKey = groupTask.task1.key
// Keep tasks that are group tasks or unique package name/user combinations
groupTask.hasMultipleTasks() ||
shownHotseatItems.none {
it.targetPackage == taskKey.packageName &&
it.user.identifier == taskKey.userId
}
when (groupTask) {
is SingleTask ->
shownHotseatItems.none {
groupTask.containsPackage(it.targetPackage, it.user.identifier)
}
else -> true
}
}
} else {
val hotseatPackages = shownHotseatItems.map { it.targetPackage }
groupTasks.filter { groupTask ->
groupTask.hasMultipleTasks() ||
!hotseatPackages.contains(groupTask.task1.key.packageName)
when (groupTask) {
is SingleTask -> hotseatPackages.none { groupTask.containsPackage(it) }
else -> true
}
}
}
}
@@ -39,7 +39,7 @@ import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SplitTask;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskContainer;
import com.android.quickstep.views.TaskView;
@@ -332,7 +332,7 @@ public class TaskbarUIController implements BubbleBarController.BubbleBarLocatio
* Launches the given task in split-screen.
*/
public void launchSplitTasks(
@NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) { }
@NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) { }
/**
* Returns the matching view (if any) in the taskbar.
@@ -70,6 +70,7 @@ import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SingleTask;
import com.android.quickstep.views.TaskViewType;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -657,9 +658,10 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
final Set<GroupTask> recentTasksSet = new ArraySet<>(recentTasks);
for (GroupTask task : recentTasks) {
if (mTaskbarOverflowView != null && overflownTasks != null
&& overflownTasks.size() < itemsToAddToOverflow) {
&& overflownTasks.size() < itemsToAddToOverflow
&& task instanceof SingleTask singleTask) {
// TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
overflownTasks.add(task.task1);
overflownTasks.add(singleTask.getTask());
if (overflownTasks.size() == itemsToAddToOverflow) {
mTaskbarOverflowView.setItems(overflownTasks);
}
@@ -733,18 +735,22 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
&& tagClass.isInstance(getChildAt(mNextViewIndex).getTag());
}
/** Binds the GroupTask to the BubbleTextView to be ready to present to the user. */
/** Binds the SingleTask to the BubbleTextView to be ready to present to the user. */
public void applyGroupTaskToBubbleTextView(BubbleTextView btv, GroupTask groupTask) {
// TODO(b/343289567): support app pairs.
Task task1 = groupTask.task1;
if (!(groupTask instanceof SingleTask singleTask)) {
// TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
return;
}
Task task = singleTask.getTask();
// TODO(b/344038728): use FastBitmapDrawable instead of Drawable, to get disabled state
// while dragging.
Drawable taskIcon = groupTask.task1.icon;
Drawable taskIcon = task.icon;
if (taskIcon != null) {
taskIcon = taskIcon.getConstantState().newDrawable().mutate();
}
btv.applyIconAndLabel(taskIcon, task1.titleDescription);
btv.setTag(groupTask);
btv.applyIconAndLabel(taskIcon, task.titleDescription);
btv.setTag(singleTask);
}
/**
@@ -92,6 +92,7 @@ import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SingleTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -739,9 +740,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
return mControllers.taskbarRecentAppsController.getRunningAppState(
itemInfo.getTaskId());
}
if (tag instanceof GroupTask groupTask && !groupTask.hasMultipleTasks()) {
if (tag instanceof SingleTask singleTask) {
return mControllers.taskbarRecentAppsController.getRunningAppState(
groupTask.task1.key.id);
singleTask.getTask().key.id);
}
return BubbleTextView.RunningAppState.NOT_RUNNING;
}
@@ -178,10 +178,10 @@ import com.android.quickstep.TaskUtils;
import com.android.quickstep.TouchInteractionService.TISBinder;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
import com.android.quickstep.util.AsyncClockEventDelegate;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LauncherUnfoldAnimationController;
import com.android.quickstep.util.QuickstepOnboardingPrefs;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SplitTask;
import com.android.quickstep.util.SplitToWorkspaceController;
import com.android.quickstep.util.SplitWithKeyboardShortcutController;
import com.android.quickstep.util.TISBindHelper;
@@ -1386,33 +1386,23 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
}
/**
* Launches the given {@link GroupTask} in splitscreen.
* Launches the given {@link SplitTask} in splitscreen.
*/
public void launchSplitTasks(
@NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
// SplitBounds can be null if coming from Taskbar launch.
final boolean firstTaskIsLeftTopTask = isFirstTaskLeftTopTask(groupTask);
// task2 should never be null when calling this method. Allow a crash to catch invalid calls
Task task1 = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
Task task2 = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
@NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) {
mSplitSelectStateController.launchExistingSplitPair(
null /* launchingTaskView */,
task1.key.id,
task2.key.id,
splitTask.getTopLeftTask().key.id,
splitTask.getBottomRightTask().key.id,
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
/* callback= */ success -> mSplitSelectStateController.resetState(),
/* freezeTaskList= */ false,
groupTask.mSplitBounds == null
splitTask.mSplitBounds == null
? SNAP_TO_2_50_50
: groupTask.mSplitBounds.snapPosition,
: splitTask.mSplitBounds.snapPosition,
remoteTransition);
}
private static boolean isFirstTaskLeftTopTask(@NonNull GroupTask groupTask) {
return groupTask.mSplitBounds == null
|| groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
}
/**
* Launches two apps as an app pair.
*/
@@ -27,8 +27,6 @@ class DesktopTask(override val tasks: List<Task>) :
override fun containsTask(taskId: Int) = tasks.any { it.key.id == taskId }
override fun hasMultipleTasks() = tasks.size > 1
override fun supportsMultipleTasks() = true
override fun copy() = DesktopTask(tasks)
@@ -50,9 +50,16 @@ constructor(
/**
* Returns true if a task in this group has a package name that matches the given `packageName`.
*/
fun containsPackage(packageName: String) = tasks.any { it.key.packageName == packageName }
fun containsPackage(packageName: String?) = tasks.any { it.key.packageName == packageName }
open fun hasMultipleTasks() = task2 != null
/**
* Returns true if a task in this group has a package name that matches the given `packageName`,
* and its user ID matches the given `userId`.
*/
fun containsPackage(packageName: String?, userId: Int) =
tasks.any { it.key.packageName == packageName && it.key.userId == userId }
fun isEmpty() = tasks.isEmpty()
/** Returns whether this task supports multiple tasks or not. */
open fun supportsMultipleTasks() = taskViewType == TaskViewType.GROUPED
@@ -78,6 +85,10 @@ constructor(
/** 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) {
val task: Task
get() = task1
override fun copy() = SingleTask(task1)
override fun toString() = "type=$taskViewType task=$task1"
@@ -96,6 +107,12 @@ class SingleTask(task: Task) :
class SplitTask(task1: Task, task2: Task, splitBounds: SplitConfigurationOptions.SplitBounds) :
GroupTask(task1, task2, splitBounds, TaskViewType.GROUPED) {
val topLeftTask: Task
get() = if (mSplitBounds!!.leftTopTaskId == task1.key.id) task1!! else task2!!
val bottomRightTask: Task
get() = if (topLeftTask == task1) task2!! else task1!!
override fun copy() = SplitTask(task1, task2!!, mSplitBounds!!)
override fun toString() = "type=$taskViewType task1=$task1 task2=$task2"
@@ -71,7 +71,6 @@ import com.android.internal.logging.InstanceId;
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
@@ -260,7 +259,7 @@ public class SplitSelectStateController {
GroupTask groupTask = taskGroups.get(i);
if (isInstanceOfAppPair(
groupTask, componentKeys.get(0), componentKeys.get(1))) {
lastActiveTasks[0] = groupTask.task1;
lastActiveTasks[0] = ((SplitTask) groupTask).getTopLeftTask();
break;
}
}
@@ -314,11 +313,15 @@ public class SplitSelectStateController {
*/
public boolean isInstanceOfAppPair(GroupTask groupTask, @NonNull ComponentKey componentKey1,
@NonNull ComponentKey componentKey2) {
return ((isInstanceOfComponent(groupTask.task1, componentKey1)
&& isInstanceOfComponent(groupTask.task2, componentKey2))
||
(isInstanceOfComponent(groupTask.task1, componentKey2)
&& isInstanceOfComponent(groupTask.task2, componentKey1)));
if (groupTask instanceof SplitTask splitTask) {
return ((isInstanceOfComponent(splitTask.getTopLeftTask(), componentKey1)
&& isInstanceOfComponent(splitTask.getBottomRightTask(), componentKey2))
||
(isInstanceOfComponent(splitTask.getTopLeftTask(), componentKey2)
&& isInstanceOfComponent(splitTask.getBottomRightTask(),
componentKey1)));
}
return false;
}
/**
@@ -212,9 +212,11 @@ import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SingleTask;
import com.android.quickstep.util.SplitAnimationController.Companion.SplitAnimInitProps;
import com.android.quickstep.util.SplitAnimationTimings;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.SplitTask;
import com.android.quickstep.util.SurfaceTransaction;
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.quickstep.util.TaskGridNavHelper;
@@ -1968,7 +1970,7 @@ public abstract class RecentsView<
GroupTask groupTask = taskGroups.get(i);
boolean containsStagedTask = stagedTaskIdToBeRemoved != INVALID_TASK_ID
&& groupTask.containsTask(stagedTaskIdToBeRemoved);
boolean shouldSkipGroupTask = containsStagedTask && !groupTask.hasMultipleTasks();
boolean shouldSkipGroupTask = containsStagedTask && groupTask instanceof SingleTask;
if ((isSplitSelectionActive() && groupTask.taskViewType == TaskViewType.DESKTOP)
|| shouldSkipGroupTask) {
@@ -1982,25 +1984,27 @@ public abstract class RecentsView<
// to be a temporary container for the remaining task.
TaskView taskView = getTaskViewFromPool(
containsStagedTask ? TaskViewType.SINGLE : groupTask.taskViewType);
if (taskView instanceof GroupedTaskView) {
boolean firstTaskIsLeftTopTask =
groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
Task rightBottomTask = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
mTaskOverlayFactory, groupTask.mSplitBounds);
} else if (taskView instanceof DesktopTaskView) {
if (taskView instanceof GroupedTaskView groupedTaskView) {
var splitTask = (SplitTask) groupTask;
groupedTaskView.bind(splitTask.getTopLeftTask(),
splitTask.getBottomRightTask(), mOrientationState,
mTaskOverlayFactory, splitTask.mSplitBounds);
} else if (taskView instanceof DesktopTaskView desktopTaskView) {
// Minimized tasks should not be shown in Overview
List<Task> nonMinimizedTasks =
groupTask.getTasks().stream()
.filter(task -> !task.isMinimized)
.toList();
((DesktopTaskView) taskView).bind(nonMinimizedTasks, mOrientationState,
desktopTaskView.bind(nonMinimizedTasks, mOrientationState,
mTaskOverlayFactory);
} else {
Task task = groupTask.task1.key.id == stagedTaskIdToBeRemoved ? groupTask.task2
: groupTask.task1;
} else if (groupTask instanceof SplitTask splitTask) {
Task task = splitTask.getTopLeftTask().key.id == stagedTaskIdToBeRemoved
? splitTask.getBottomRightTask()
: splitTask.getTopLeftTask();
taskView.bind(task, mOrientationState, mTaskOverlayFactory);
} else {
taskView.bind(((SingleTask) groupTask).getTask(), mOrientationState,
mTaskOverlayFactory);
}
addView(taskView);
@@ -102,12 +102,12 @@ class SplitSelectStateControllerTest {
fun activeTasks_noMatchingTasks() {
val nonMatchingComponent = ComponentKey(ComponentName("no", "match"), primaryUserHandle)
val groupTask1 =
generateGroupTask(
generateSplitTask(
ComponentName("pomegranate", "juice"),
ComponentName("pumpkin", "pie"),
)
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("hotdog", "juice"),
ComponentName("personal", "computer"),
)
@@ -143,12 +143,12 @@ class SplitSelectStateControllerTest {
val matchingComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(
generateSplitTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pomegranate", "juice"),
)
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer"),
)
@@ -170,7 +170,7 @@ class SplitSelectStateControllerTest {
it[0].key.baseIntent.component?.className,
matchingClass,
)
assertEquals(it[0], groupTask1.task1)
assertEquals(it[0], groupTask1.topLeftTask)
}
// Capture callback from recentsModel#getTasks()
@@ -196,12 +196,12 @@ class SplitSelectStateControllerTest {
val nonPrimaryUserComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
val groupTask1 =
generateGroupTask(
generateSplitTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pomegranate", "juice"),
)
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer"),
)
@@ -237,14 +237,14 @@ class SplitSelectStateControllerTest {
val nonPrimaryUserComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), nonPrimaryUserHandle)
val groupTask1 =
generateGroupTask(
generateSplitTask(
ComponentName(matchingPackage, matchingClass),
nonPrimaryUserHandle,
ComponentName("pomegranate", "juice"),
nonPrimaryUserHandle,
)
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pumpkin", "pie"),
ComponentName("personal", "computer"),
)
@@ -267,7 +267,7 @@ class SplitSelectStateControllerTest {
matchingClass,
)
assertEquals("userId mismatched", it[0].key.userId, nonPrimaryUserHandle.identifier)
assertEquals(it[0], groupTask1.task1)
assertEquals(it[0], groupTask1.topLeftTask)
}
// Capture callback from recentsModel#getTasks()
@@ -293,12 +293,12 @@ class SplitSelectStateControllerTest {
val matchingComponent =
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(
generateSplitTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pumpkin", "pie"),
)
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass),
)
@@ -320,7 +320,7 @@ class SplitSelectStateControllerTest {
it[0].key.baseIntent.component?.className,
matchingClass,
)
assertEquals(it[0], groupTask1.task1)
assertEquals(it[0], groupTask1.topLeftTask)
}
// Capture callback from recentsModel#getTasks()
@@ -348,9 +348,9 @@ class SplitSelectStateControllerTest {
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
generateSplitTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass),
)
@@ -374,7 +374,7 @@ class SplitSelectStateControllerTest {
it[1].key.baseIntent.component?.className,
matchingClass,
)
assertEquals(it[1], groupTask2.task2)
assertEquals(it[1], groupTask2.bottomRightTask)
}
// Capture callback from recentsModel#getTasks()
@@ -401,9 +401,9 @@ class SplitSelectStateControllerTest {
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
generateSplitTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass),
)
@@ -426,7 +426,7 @@ class SplitSelectStateControllerTest {
it[0].key.baseIntent.component?.className,
matchingClass,
)
assertEquals(it[0], groupTask2.task2)
assertEquals(it[0], groupTask2.bottomRightTask)
assertNull("No tasks should have matched", it[1] /*task*/)
}
@@ -454,12 +454,12 @@ class SplitSelectStateControllerTest {
ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
val groupTask1 =
generateGroupTask(
generateSplitTask(
ComponentName(matchingPackage, matchingClass),
ComponentName("pumpkin", "pie"),
)
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName("pomegranate", "juice"),
ComponentName(matchingPackage, matchingClass),
)
@@ -482,7 +482,7 @@ class SplitSelectStateControllerTest {
it[0].key.baseIntent.component?.className,
matchingClass,
)
assertEquals(it[0], groupTask1.task1)
assertEquals(it[0], groupTask1.topLeftTask)
assertEquals(
"ComponentName package mismatched",
it[1].key.baseIntent.component?.packageName,
@@ -493,7 +493,7 @@ class SplitSelectStateControllerTest {
it[1].key.baseIntent.component?.className,
matchingClass,
)
assertEquals(it[1], groupTask2.task2)
assertEquals(it[1], groupTask2.bottomRightTask)
}
// Capture callback from recentsModel#getTasks()
@@ -524,14 +524,14 @@ class SplitSelectStateControllerTest {
ComponentKey(ComponentName(matchingPackage2, matchingClass2), primaryUserHandle)
val groupTask1 =
generateGroupTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
generateSplitTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
val groupTask2 =
generateGroupTask(
generateSplitTask(
ComponentName(matchingPackage2, matchingClass2),
ComponentName(matchingPackage, matchingClass),
)
val groupTask3 =
generateGroupTask(
generateSplitTask(
ComponentName("hotdog", "pie"),
ComponentName(matchingPackage, matchingClass),
)
@@ -545,7 +545,7 @@ class SplitSelectStateControllerTest {
val taskConsumer =
Consumer<Array<Task>> {
assertEquals("Expected array length 2", 2, it.size)
assertEquals("Found wrong task", it[0], groupTask2.task1)
assertEquals("Found wrong task", it[0], groupTask2.topLeftTask)
}
// Capture callback from recentsModel#getTasks()
@@ -640,11 +640,11 @@ class SplitSelectStateControllerTest {
verify(recentsView, times(0)).resetDesktopTaskFromSplitSelectState()
}
// Generate GroupTask with default userId.
private fun generateGroupTask(
/** Generates a [SplitTask] with default userId. */
private fun generateSplitTask(
task1ComponentName: ComponentName,
task2ComponentName: ComponentName,
): GroupTask {
): SplitTask {
val task1 = Task()
var taskInfo = ActivityManager.RunningTaskInfo()
taskInfo.taskId = getUniqueId()
@@ -666,20 +666,20 @@ class SplitSelectStateControllerTest {
SplitConfigurationOptions.SplitBounds(
/* leftTopBounds = */ Rect(),
/* rightBottomBounds = */ Rect(),
/* leftTopTaskId = */ -1,
/* rightBottomTaskId = */ -1,
/* leftTopTaskId = */ task1.key.id,
/* rightBottomTaskId = */ task2.key.id,
/* snapPosition = */ SNAP_TO_2_50_50,
),
)
}
// Generate GroupTask with custom user handles.
private fun generateGroupTask(
/** Generates a [SplitTask] with custom user handles. */
private fun generateSplitTask(
task1ComponentName: ComponentName,
userHandle1: UserHandle,
task2ComponentName: ComponentName,
userHandle2: UserHandle,
): GroupTask {
): SplitTask {
val task1 = Task()
var taskInfo = ActivityManager.RunningTaskInfo()
taskInfo.taskId = getUniqueId()
@@ -704,8 +704,8 @@ class SplitSelectStateControllerTest {
SplitConfigurationOptions.SplitBounds(
/* leftTopBounds = */ Rect(),
/* rightBottomBounds = */ Rect(),
/* leftTopTaskId = */ -1,
/* rightBottomTaskId = */ -1,
/* leftTopTaskId = */ task1.key.id,
/* rightBottomTaskId = */ task2.key.id,
/* snapPosition = */ SNAP_TO_2_50_50,
),
)