Merge changes from topic "empty-desk" into main

* changes:
  Remove wallpaper task and tasks below from `getCachedTopTask`
  Handling for an empty desk
This commit is contained in:
Min Chen
2025-03-26 13:02:49 -07:00
committed by Android (Google) Code Review
7 changed files with 90 additions and 62 deletions
@@ -361,7 +361,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
* @return the single top-most running taskId for this gesture
*/
public int getTopRunningTaskId() {
return getRunningTaskIds(false /*getMultipleTasks*/)[0];
var taskIds = getRunningTaskIds(/* getMultipleTasks = */ false);
return taskIds.length != 0 ? taskIds[0] : INVALID_TASK_ID;
}
/**
@@ -417,6 +417,7 @@ public class RecentTasksList implements WindowManagerProxy.DesktopVisibilityList
continue;
}
// [getTaskInfo1] will not be null for types below beside [TYPE_DESK].
if (Flags.enableShellTopTaskTracking()) {
final TaskInfo taskInfo1 = rawTask.getBaseGroupedTask().getTaskInfo1();
final Task.TaskKey task1Key = new Task.TaskKey(taskInfo1);
@@ -26,12 +26,13 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.android.launcher3.Flags.enableOverviewOnConnectedDisplays;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_A;
import static com.android.quickstep.fallback.window.RecentsWindowFlags.enableOverviewOnConnectedDisplays;
import static com.android.wm.shell.Flags.enableShellTopTaskTracking;
import static com.android.wm.shell.Flags.enableFlexibleSplit;
import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_DESK;
import static com.android.wm.shell.shared.GroupedTaskInfo.TYPE_SPLIT;
import static com.android.launcher3.statehandlers.DesktopVisibilityController.INACTIVE_DESK_ID;
import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode;
import static com.android.wm.shell.shared.desktopmode.DesktopModeStatus.enableMultipleDesktops;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.TaskInfo;
@@ -46,6 +47,7 @@ import androidx.annotation.UiThread;
import com.android.launcher3.dagger.ApplicationContext;
import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.util.DaggerSingletonObject;
import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.SplitConfigurationOptions;
@@ -96,7 +98,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
// most.
private ArrayMap<Integer, GroupedTaskInfo> mVisibleTasks = new ArrayMap<>();
private final boolean mCanEnterDesktopMode;
private final Context mContext;
@Inject
public TopTaskTracker(@ApplicationContext Context context, DaggerSingletonTracker tracker,
@@ -118,7 +120,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
systemUiProxy.unregisterSplitScreenListener(this);
});
mCanEnterDesktopMode = canEnterDesktopMode(context);
mContext = context;
}
@Override
@@ -201,7 +203,13 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
Log.d(TAG, "onVisibleTasksChanged:");
for (GroupedTaskInfo groupedTask : visibleTasks) {
Log.d(TAG, "\t" + groupedTask);
final int displayId = groupedTask.getBaseGroupedTask().getTaskInfo1().getDisplayId();
GroupedTaskInfo baseGroupedTask = groupedTask.getBaseGroupedTask();
int displayId;
if (enableMultipleDesktops(mContext) && baseGroupedTask.isBaseType(TYPE_DESK)) {
displayId = baseGroupedTask.getDeskDisplayId();
} else {
displayId = baseGroupedTask.getTaskInfo1().getDisplayId();
}
mVisibleTasks.put(displayId, groupedTask);
}
}
@@ -344,9 +352,9 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
if (enableOverviewOnConnectedDisplays()) {
return new CachedTaskInfo(Arrays.stream(tasks).filter(
info -> ExternalDisplaysKt.getSafeDisplayId(info)
== displayId).toList(), mCanEnterDesktopMode, displayId);
== displayId).toList(), mContext, displayId);
} else {
return new CachedTaskInfo(Arrays.asList(tasks), mCanEnterDesktopMode,
return new CachedTaskInfo(Arrays.asList(tasks), mContext,
displayId);
}
}
@@ -358,17 +366,21 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
Collections.addAll(mOrderedTaskList, tasks);
}
ArrayList<TaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
// Strip the pinned task and recents task
tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t)
|| DesksUtils.isDesktopWallpaperTask(t));
List<TaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
// Strip the pinned task and recents task.
tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t));
if (enableOverviewOnConnectedDisplays()) {
return new CachedTaskInfo(tasks.stream().filter(
info -> ExternalDisplaysKt.getSafeDisplayId(info) == displayId).toList(),
mCanEnterDesktopMode, displayId);
} else {
return new CachedTaskInfo(tasks, mCanEnterDesktopMode, displayId);
tasks = tasks.stream().filter(
info -> ExternalDisplaysKt.getSafeDisplayId(info) == displayId).toList();
}
if (enableMultipleDesktops(mContext)) {
tasks = tasks.stream().takeWhile(
taskInfo -> !DesksUtils.isDesktopWallpaperTask(taskInfo)).toList();
} else {
tasks.removeIf(taskInfo -> DesksUtils.isDesktopWallpaperTask(taskInfo));
}
return new CachedTaskInfo(tasks, mContext, displayId);
}
}
@@ -399,7 +411,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
@Nullable
private final GroupedTaskInfo mVisibleTasks;
private boolean mCanEnterDesktopMode = false;
private Context mContext;
// Only used when enableShellTopTaskTracking() is enabled
CachedTaskInfo(@Nullable GroupedTaskInfo visibleTasks) {
@@ -409,13 +421,13 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
}
// Only used when enableShellTopTaskTracking() is disabled
CachedTaskInfo(@NonNull List<TaskInfo> allCachedTasks, boolean canEnterDesktopMode,
CachedTaskInfo(@NonNull List<TaskInfo> allCachedTasks, Context context,
int displayId) {
mDisplayId = displayId;
mVisibleTasks = null;
mAllCachedTasks = allCachedTasks;
mTopTask = allCachedTasks.isEmpty() ? null : allCachedTasks.get(0);
mCanEnterDesktopMode = canEnterDesktopMode;
mDisplayId = displayId;
mContext = context;
}
/**
@@ -525,7 +537,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
&& t.getActivityType() != ACTIVITY_TYPE_RECENTS)
.toList();
return visibleNonExcludedTasks.isEmpty() ? null
: new CachedTaskInfo(visibleNonExcludedTasks, mCanEnterDesktopMode, mDisplayId);
: new CachedTaskInfo(visibleNonExcludedTasks, mContext, mDisplayId);
}
/**
@@ -551,7 +563,7 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
}
private boolean isDesktopTask(TaskInfo taskInfo) {
return mCanEnterDesktopMode
return canEnterDesktopMode(mContext)
&& taskInfo.configuration.windowConfiguration.getWindowingMode()
== WindowConfiguration.WINDOWING_MODE_FREEFORM;
}
@@ -572,10 +584,6 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
}
return mVisibleTasks.getBaseGroupedTask();
} else {
final TaskInfo baseTaskInfo = getLegacyBaseTask();
if (baseTaskInfo == null) {
return null;
}
if (splitTaskIds != null && splitTaskIds.length >= 2) {
TaskInfo[] splitTasksInfo = getSplitPlaceholderTasksInfo(splitTaskIds);
if (splitTasksInfo[0] == null || splitTasksInfo[1] == null) {
@@ -583,12 +591,23 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta
}
return GroupedTaskInfo.forSplitTasks(splitTasksInfo[0],
splitTasksInfo[1], /* splitBounds = */ null);
} else if (isDesktopTask(baseTaskInfo)) {
return GroupedTaskInfo.forDeskTasks(INACTIVE_DESK_ID, mDisplayId,
Collections.singletonList(
baseTaskInfo), /* minimizedFreeformTaskIds = */
Collections.emptySet());
} else {
final TaskInfo baseTaskInfo = getLegacyBaseTask();
if (enableMultipleDesktops(mContext)) {
DesktopVisibilityController desktopVisibilityController =
DesktopVisibilityController.INSTANCE.get(mContext);
if (desktopVisibilityController.isInDesktopMode(mDisplayId)) {
return GroupedTaskInfo.forDeskTasks(
desktopVisibilityController.getActiveDeskId(mDisplayId),
mDisplayId, mAllCachedTasks,
/* minimizedFreeformTaskIds = */ Collections.emptySet());
}
} else if (isDesktopTask(baseTaskInfo)) {
return GroupedTaskInfo.forDeskTasks(INACTIVE_DESK_ID, mDisplayId,
Collections.singletonList(
baseTaskInfo), /* minimizedFreeformTaskIds = */
Collections.emptySet());
}
return GroupedTaskInfo.forFullscreenTasks(baseTaskInfo);
}
}
@@ -190,10 +190,8 @@ public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewCon
return super.shouldAddStubTaskView(groupedTaskInfo);
}
Task runningTask = Task.from(groupedTaskInfo.getTaskInfo1());
if (mHomeTask != null && runningTask != null
&& mHomeTask.key.id == runningTask.key.id
&& !hasTaskViews() && mLoadPlanEverApplied) {
if (mHomeTask != null && groupedTaskInfo.containsTask(mHomeTask.key.id) && !hasTaskViews()
&& mLoadPlanEverApplied) {
// Do not add a stub task if we are running over home with empty recents, so that we
// show the empty recents message instead of showing a stub task and later removing it.
// Ignore empty task signal if applyLoadPlan has never run.
@@ -3087,26 +3087,7 @@ public abstract class RecentsView<
* Returns true if we should add a stub taskView for the running task id
*/
protected boolean shouldAddStubTaskView(GroupedTaskInfo groupedTaskInfo) {
int[] runningTaskIds;
if (groupedTaskInfo != null) {
runningTaskIds = groupedTaskInfo.getTaskInfoList().stream().mapToInt(
taskInfo -> taskInfo.taskId).toArray();
} else {
runningTaskIds = new int[0];
}
TaskView matchingTaskView = null;
if (groupedTaskInfo != null && groupedTaskInfo.isBaseType(GroupedTaskInfo.TYPE_DESK)
&& runningTaskIds.length == 1) {
// TODO(b/342635213): Unsure if it's expected, desktop runningTasks only have a single
// taskId, therefore we match any DesktopTaskView that contains the runningTaskId.
TaskView taskview = getTaskViewByTaskId(runningTaskIds[0]);
if (taskview instanceof DesktopTaskView) {
matchingTaskView = taskview;
}
} else {
matchingTaskView = getTaskViewByTaskIds(runningTaskIds);
}
return matchingTaskView == null;
return mUtils.shouldAddStubTaskView(groupedTaskInfo);
}
/**
@@ -3156,7 +3137,13 @@ public abstract class RecentsView<
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
} else {
var runningTaskView = getTaskViewByTaskId(groupedTaskInfo.getTaskInfo1().taskId);
TaskView runningTaskView;
if (DesktopModeStatus.enableMultipleDesktops(mContext) && groupedTaskInfo.isBaseType(
GroupedTaskInfo.TYPE_DESK)) {
runningTaskView = mUtils.getDesktopTaskViewForDeskId(groupedTaskInfo.getDeskId());
} else {
runningTaskView = getTaskViewByTaskId(groupedTaskInfo.getTaskInfo1().taskId);
}
if (runningTaskView != null) {
runningTaskViewId = runningTaskView.getTaskViewId();
}
@@ -45,6 +45,7 @@ import com.android.quickstep.views.RecentsView.TAG
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.wm.shell.shared.GroupedTaskInfo
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.enableMultipleDesktops
import java.util.function.BiConsumer
import kotlin.math.min
import kotlin.reflect.KMutableProperty1
@@ -115,16 +116,19 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) : DesktopVisi
taskViews.filter { recentsView.mTopRowIdSet.contains(it.taskViewId) }
/** Returns all the task Ids in the top row, without the focused task */
fun getTopRowIdArray(): IntArray = getTopRowTaskViews().map { it.taskViewId }.toIntArray()
fun getTopRowIdArray(): IntArray =
getTopRowTaskViews().map { it.taskViewId }.toLauncher3IntArray()
/** Returns all the TaskViews in the bottom row, without the focused task */
fun getBottomRowTaskViews(): List<TaskView> =
taskViews.filter { !recentsView.mTopRowIdSet.contains(it.taskViewId) && !it.isLargeTile }
/** Returns all the task Ids in the bottom row, without the focused task */
fun getBottomRowIdArray(): IntArray = getBottomRowTaskViews().map { it.taskViewId }.toIntArray()
fun getBottomRowIdArray(): IntArray =
getBottomRowTaskViews().map { it.taskViewId }.toLauncher3IntArray()
private fun List<Int>.toIntArray() = IntArray(size).apply { this@toIntArray.forEach(::add) }
private fun List<Int>.toLauncher3IntArray() =
IntArray(size).apply { this@toLauncher3IntArray.forEach(::add) }
/** Counts [TaskView]s that are large tiles. */
fun getLargeTileCount(): Int = taskViews.count { it.isLargeTile }
@@ -539,6 +543,26 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) : DesktopVisi
return desktopTaskView
}
fun shouldAddStubTaskView(groupedTaskInfo: GroupedTaskInfo): Boolean {
val matchingTaskView =
when {
groupedTaskInfo.isBaseType(GroupedTaskInfo.TYPE_DESK) &&
enableMultipleDesktops(recentsView.context) ->
getDesktopTaskViewForDeskId(groupedTaskInfo.deskDisplayId)
groupedTaskInfo.isBaseType(GroupedTaskInfo.TYPE_DESK) &&
groupedTaskInfo.taskInfoList.size == 1 ->
recentsView.getTaskViewByTaskId(groupedTaskInfo.taskInfo1!!.taskId)
as? DesktopTaskView
else -> {
val runningTaskIds = groupedTaskInfo.taskInfoList.map { it.taskId }.toIntArray()
recentsView.getTaskViewByTaskIds(runningTaskIds)
}
}
return matchingTaskView == null
}
companion object {
class RecentsViewFloatProperty(
private val utilsProperty: KMutableProperty1<RecentsViewUtils, Float>
@@ -51,7 +51,6 @@ import android.os.SystemClock;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.Display;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.ViewTreeObserver;
@@ -104,8 +103,7 @@ public abstract class AbsSwipeUpHandlerTestCase<
new ActivityManager.RunningTaskInfo();
protected final TopTaskTracker.CachedTaskInfo mCachedTaskInfo =
new TopTaskTracker.CachedTaskInfo(
Collections.singletonList(mRunningTaskInfo), /* canEnterDesktop = */ false,
DEFAULT_DISPLAY);
Collections.singletonList(mRunningTaskInfo), mContext, DEFAULT_DISPLAY);
protected final RemoteAnimationTarget mRemoteAnimationTarget = new RemoteAnimationTarget(
/* taskId= */ 0,
/* mode= */ RemoteAnimationTarget.MODE_CLOSING,