From 1b3daa918e28fb3780bac741d80e5447e03bdeaf Mon Sep 17 00:00:00 2001 From: minch Date: Fri, 21 Mar 2025 14:32:47 +0000 Subject: [PATCH 1/2] Handling for an empty desk Bug: 401582344 Test: m Flag: com.android.window.flags.enable_multiple_desktops_frontend Flag: com.android.window.flags.enable_multiple_desktops_backend Change-Id: I60960277f22196050491b152ea7e9476f4f70bb9 --- .../android/quickstep/RecentTasksList.java | 1 + .../com/android/quickstep/TopTaskTracker.java | 61 ++++++++++++------- .../fallback/FallbackRecentsView.java | 6 +- .../android/quickstep/views/RecentsView.java | 29 +++------ .../quickstep/views/RecentsViewUtils.kt | 30 ++++++++- .../quickstep/AbsSwipeUpHandlerTestCase.java | 4 +- 6 files changed, 77 insertions(+), 54 deletions(-) diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java index a77241549c..b481fe8ede 100644 --- a/quickstep/src/com/android/quickstep/RecentTasksList.java +++ b/quickstep/src/com/android/quickstep/RecentTasksList.java @@ -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); diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java index 2b83311052..1e5212e690 100644 --- a/quickstep/src/com/android/quickstep/TopTaskTracker.java +++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java @@ -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 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); } } @@ -365,9 +373,9 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta if (enableOverviewOnConnectedDisplays()) { return new CachedTaskInfo(tasks.stream().filter( info -> ExternalDisplaysKt.getSafeDisplayId(info) == displayId).toList(), - mCanEnterDesktopMode, displayId); + mContext, displayId); } else { - return new CachedTaskInfo(tasks, mCanEnterDesktopMode, displayId); + return new CachedTaskInfo(tasks, mContext, displayId); } } } @@ -399,7 +407,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 +417,13 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta } // Only used when enableShellTopTaskTracking() is disabled - CachedTaskInfo(@NonNull List allCachedTasks, boolean canEnterDesktopMode, + CachedTaskInfo(@NonNull List 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 +533,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 +559,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 +580,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 +587,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); } } diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index dc1cdde4bc..2e68d06104 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -184,10 +184,8 @@ public class FallbackRecentsView 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); } /** @@ -3155,7 +3136,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(); } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt index b265b13393..3b1ac71800 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt @@ -42,6 +42,7 @@ import com.android.quickstep.views.RecentsView.RUNNING_TASK_ATTACH_ALPHA 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 @@ -112,16 +113,19 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { 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 = 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.toIntArray() = IntArray(size).apply { this@toIntArray.forEach(::add) } + private fun List.toLauncher3IntArray() = + IntArray(size).apply { this@toLauncher3IntArray.forEach(::add) } /** Counts [TaskView]s that are large tiles. */ fun getLargeTileCount(): Int = taskViews.count { it.isLargeTile } @@ -477,6 +481,26 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { 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 diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java index 6adb7b4052..85ad1e4a31 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java @@ -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, From fa50caf83c5e5d1d8b7fb9108a790331f4241d9a Mon Sep 17 00:00:00 2001 From: minch Date: Mon, 24 Mar 2025 05:04:11 +0000 Subject: [PATCH 2/2] Remove wallpaper task and tasks below from `getCachedTopTask` Remove the wallpaper task and tasks below from `TopTaskTracker.getCachedTopTask` thus the empty task can be really empty. Also update the usage of the cached top task to avoid crash because it can be empty now. Bug: 402218420 Flag: EXEMPT refactor Test: m Change-Id: I15835ec3bf84b9ea5b6b2aba731f9f5b8a17353f --- .../com/android/quickstep/GestureState.java | 3 ++- .../com/android/quickstep/TopTaskTracker.java | 22 +++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index c4ba2d52bb..f093f62cdf 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -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; } /** diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java index 1e5212e690..53344a1408 100644 --- a/quickstep/src/com/android/quickstep/TopTaskTracker.java +++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java @@ -366,17 +366,21 @@ public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskSta Collections.addAll(mOrderedTaskList, tasks); } - ArrayList tasks = new ArrayList<>(mOrderedTaskList); - // Strip the pinned task and recents task - tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t) - || DesksUtils.isDesktopWallpaperTask(t)); + List 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(), - mContext, displayId); - } else { - return new CachedTaskInfo(tasks, mContext, 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); } }