Merge "Show desktop tasks when taskbar is pinned on home" into main

This commit is contained in:
Treehugger Robot
2025-01-23 02:10:17 -08:00
committed by Android (Google) Code Review
10 changed files with 117 additions and 47 deletions
@@ -28,6 +28,7 @@ import com.android.launcher3.R;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.RecentsFilterState;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
@@ -153,6 +154,8 @@ public final class KeyboardQuickSwitchController implements
// Skip the task reload if the list is not changed.
if (!mModel.isTaskListValid(mTaskListChangeId) || !taskIdsToExclude.equals(
mExcludedTaskIds)) {
final boolean shouldShowDesktopTasks = mControllers.taskbarDesktopModeController
.shouldShowDesktopTasksInTaskbar();
mExcludedTaskIds = taskIdsToExclude;
mTaskListChangeId = mModel.getTasks((tasks) -> {
processLoadedTasks(tasks, taskIdsToExclude);
@@ -162,7 +165,8 @@ public final class KeyboardQuickSwitchController implements
currentFocusIndexOverride,
mHasDesktopTask,
mWasDesktopTaskFilteredOut);
});
}, shouldShowDesktopTasks ? RecentsFilterState.EMPTY_FILTER
: RecentsFilterState.getEmptyDesktopTaskFilter());
}
mQuickSwitchViewController.updateLayoutForSurface(wasOpenedFromTaskbar,
@@ -188,8 +192,8 @@ public final class KeyboardQuickSwitchController implements
mQuickSwitchViewController = new KeyboardQuickSwitchViewController(
mControllers, mOverlayContext, keyboardQuickSwitchView, mControllerCallbacks);
final boolean onDesktop = mControllers.taskbarDesktopModeController
.getAreDesktopTasksVisibleAndNotInOverview();
final boolean shouldShowDesktopTasks = mControllers.taskbarDesktopModeController
.shouldShowDesktopTasksInTaskbar();
if (mModel.isTaskListValid(mTaskListChangeId)
&& taskIdsToExclude.equals(mExcludedTaskIds)) {
@@ -201,7 +205,7 @@ public final class KeyboardQuickSwitchController implements
/* updateTasks= */ false,
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
? 0 : currentFocusedIndex,
onDesktop,
shouldShowDesktopTasks,
mHasDesktopTask,
mWasDesktopTaskFilteredOut,
wasOpenedFromTaskbar);
@@ -219,11 +223,12 @@ public final class KeyboardQuickSwitchController implements
/* updateTasks= */ true,
currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
? 0 : currentFocusedIndex,
onDesktop,
shouldShowDesktopTasks,
mHasDesktopTask,
mWasDesktopTaskFilteredOut,
wasOpenedFromTaskbar);
});
}, shouldShowDesktopTasks ? RecentsFilterState.EMPTY_FILTER
: RecentsFilterState.getEmptyDesktopTaskFilter());
}
private boolean shouldExcludeTask(GroupTask task, Set<Integer> taskIdsToExclude) {
@@ -233,7 +238,7 @@ public final class KeyboardQuickSwitchController implements
private void processLoadedTasks(List<GroupTask> tasks, Set<Integer> taskIdsToExclude) {
mHasDesktopTask = false;
mWasDesktopTaskFilteredOut = false;
if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisibleAndNotInOverview()) {
if (mControllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar()) {
processLoadedTasksOnDesktop(tasks, taskIdsToExclude);
} else {
processLoadedTasksOutsideDesktop(tasks, taskIdsToExclude);
@@ -368,7 +368,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this),
bubbleControllersOptional,
new TaskbarDesktopModeController(DesktopVisibilityController.INSTANCE.get(this)));
new TaskbarDesktopModeController(this,
DesktopVisibilityController.INSTANCE.get(this)));
mLauncherPrefs = LauncherPrefs.get(this);
}
@@ -16,13 +16,16 @@
package com.android.launcher3.taskbar
import android.content.Context
import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.statehandlers.DesktopVisibilityController.TaskbarDesktopModeListener
import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
import com.android.launcher3.util.DisplayController
/** Handles Taskbar in Desktop Windowing mode. */
class TaskbarDesktopModeController(
private val desktopVisibilityController: DesktopVisibilityController
private val context: Context,
private val desktopVisibilityController: DesktopVisibilityController,
) : TaskbarDesktopModeListener {
private lateinit var taskbarControllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
@@ -45,6 +48,12 @@ class TaskbarDesktopModeController(
taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start()
}
fun shouldShowDesktopTasksInTaskbar(): Boolean {
return desktopVisibilityController.areDesktopTasksVisible() ||
DisplayController.showLockedTaskbarOnHome(context) &&
taskbarControllers.taskbarStashController.isOnHome
}
fun getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding: Boolean): Float {
return if (doesAnyTaskRequireTaskbarRounding) {
MAX_ROUNDNESS
@@ -26,6 +26,7 @@ import com.android.launcher3.model.data.TaskItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
import com.android.launcher3.util.CancellableTask
import com.android.quickstep.RecentsFilterState
import com.android.quickstep.RecentsModel
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
@@ -119,7 +120,7 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
get() {
if (
!canShowRunningApps ||
!controllers.taskbarDesktopModeController.areDesktopTasksVisible
!controllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar()
) {
return emptySet()
}
@@ -135,7 +136,7 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
get() {
if (
!canShowRunningApps ||
!controllers.taskbarDesktopModeController.areDesktopTasksVisible
!controllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar()
) {
return emptySet()
}
@@ -171,10 +172,10 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
/** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */
fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
// Ignore predicted apps - we show running or recent apps instead.
val areDesktopTasksVisible = controllers.taskbarDesktopModeController.areDesktopTasksVisible
val showDesktopTasks =
controllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar()
val removePredictions =
(areDesktopTasksVisible && canShowRunningApps) ||
(!areDesktopTasksVisible && canShowRecentApps)
(showDesktopTasks && canShowRunningApps) || (!showDesktopTasks && canShowRecentApps)
if (!removePredictions) {
shownHotseatItems = hotseatItems.filterNotNull()
onRecentsOrHotseatChanged()
@@ -186,7 +187,7 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
.filter { itemInfo -> !itemInfo.isPredictedItem }
.toMutableList()
if (areDesktopTasksVisible && canShowRunningApps) {
if (showDesktopTasks && canShowRunningApps) {
shownHotseatItems =
updateHotseatItemsFromRunningTasks(
getOrderedAndWrappedDesktopTasks(),
@@ -210,19 +211,24 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
private fun reloadRecentTasksIfNeeded() {
if (!recentsModel.isTaskListValid(taskListChangeId)) {
taskListChangeId =
recentsModel.getTasks { tasks ->
allRecentTasks = tasks
val oldRunningTaskdIds = runningTaskIds
val oldMinimizedTaskIds = minimizedTaskIds
desktopTask = allRecentTasks.filterIsInstance<DesktopTask>().firstOrNull()
val runningTasksChanged = oldRunningTaskdIds != runningTaskIds
val minimizedTasksChanged = oldMinimizedTaskIds != minimizedTaskIds
if (
onRecentsOrHotseatChanged() || runningTasksChanged || minimizedTasksChanged
) {
controllers.taskbarViewController.commitRunningAppsToUI()
}
}
recentsModel.getTasks(
{ tasks ->
allRecentTasks = tasks
val oldRunningTaskdIds = runningTaskIds
val oldMinimizedTaskIds = minimizedTaskIds
desktopTask = allRecentTasks.filterIsInstance<DesktopTask>().firstOrNull()
val runningTasksChanged = oldRunningTaskdIds != runningTaskIds
val minimizedTasksChanged = oldMinimizedTaskIds != minimizedTaskIds
if (
onRecentsOrHotseatChanged() ||
runningTasksChanged ||
minimizedTasksChanged
) {
controllers.taskbarViewController.commitRunningAppsToUI()
}
},
RecentsFilterState.EMPTY_FILTER,
)
}
}
@@ -235,7 +241,7 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
val oldShownTasks = shownTasks
orderedRunningTaskIds = updateOrderedRunningTaskIds()
shownTasks =
if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) {
if (controllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar()) {
computeShownRunningTasks()
} else {
computeShownRecentTasks()
@@ -269,6 +269,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
private final long mTaskbarBackgroundDuration;
private boolean mUserIsNotGoingHome = false;
private final boolean mInAppStateAffectsDesktopTasksVisibilityInTaskbar;
// Evaluate whether the handle should be stashed
private final LongPredicate mIsStashedPredicate = flags -> {
boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
@@ -293,8 +295,17 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
mAccessibilityManager = mActivity.getSystemService(AccessibilityManager.class);
mTaskbarBackgroundDuration =
activity.getResources().getInteger(R.integer.taskbar_background_duration);
// Taskbar, via `TaskbarDesktopModeController`, depends on `TaskbarStashController` state to
// determine whether desktop tasks should be shown because taskbar is pinned on the home
// screen for freeform windowing displays. In this case, list of items shown in the taskbar
// needs to be updated when in-app state changes.
// TODO(b/390665752): Feature to "lock" pinned taskbar to home screen will be superseded by
// pinning, in other launcher states, at which point this variable can be removed.
mInAppStateAffectsDesktopTasksVisibilityInTaskbar =
DisplayController.showLockedTaskbarOnHome(mActivity);
mTaskbarBackgroundDuration = activity.getResources().getInteger(
R.integer.taskbar_background_duration);
if (mActivity.isPhoneMode()) {
mUnstashedHeight = mActivity.getResources().getDimensionPixelSize(
R.dimen.taskbar_phone_size);
@@ -1237,6 +1248,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
if (hasAnyFlag(changedFlags, FLAG_IN_OVERVIEW | FLAG_IN_APP)) {
mControllers.runAfterInit(() -> mControllers.taskbarInsetsController
.onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
if (mInAppStateAffectsDesktopTasksVisibilityInTaskbar) {
mControllers.runAfterInit(
() -> mControllers.taskbarViewController.commitRunningAppsToUI());
}
}
mActivity.applyForciblyShownFlagWhileTransientTaskbarUnstashed(!isStashedInApp());
}
@@ -419,10 +419,6 @@ public class RecentTasksList {
private @Nullable DesktopTask createDesktopTask(GroupedTaskInfo recentTaskInfo) {
ArrayList<Task> tasks = new ArrayList<>(recentTaskInfo.getTaskInfoList().size());
int[] minimizedTaskIds = recentTaskInfo.getMinimizedTaskIds();
if (minimizedTaskIds.length == recentTaskInfo.getTaskInfoList().size()) {
// All Tasks are minimized -> don't create a DesktopTask
return null;
}
for (TaskInfo taskInfo : recentTaskInfo.getTaskInfoList()) {
Task.TaskKey key = new Task.TaskKey(taskInfo);
Task task = Task.from(key, taskInfo, false);
@@ -19,6 +19,7 @@ package com.android.quickstep;
import androidx.annotation.Nullable;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.TaskViewType;
import com.android.systemui.shared.recents.model.Task;
import java.util.HashMap;
@@ -38,7 +39,7 @@ public class RecentsFilterState {
public static final int MIN_FILTERING_TASK_COUNT = 2;
// default filter that returns true for any input
public static final Predicate<GroupTask> DEFAULT_FILTER = (groupTask -> true);
public static final Predicate<GroupTask> EMPTY_FILTER = (groupTask -> true);
// the package name to filter recent tasks by
@Nullable
@@ -116,14 +117,37 @@ public class RecentsFilterState {
* Returns a predicate for filtering out GroupTasks by package name.
*
* @param packageName package name to filter GroupTasks by
* if null, Predicate always returns true.
* if null, Predicate filters out desktop tasks with no non-minimized tasks.
*/
public static Predicate<GroupTask> getFilter(@Nullable String packageName) {
if (packageName == null) {
return DEFAULT_FILTER;
return getEmptyDesktopTaskFilter();
}
return (groupTask) -> (groupTask.containsPackage(packageName));
return (groupTask) -> (groupTask.containsPackage(packageName)
&& !isDestopTaskWithMinimizedTasksOnly(groupTask));
}
/**
* Returns a predicate that filters out desk tasks that contain no non-minimized desktop tasks.
*/
public static Predicate<GroupTask> getEmptyDesktopTaskFilter() {
return (groupTask -> !isDestopTaskWithMinimizedTasksOnly(groupTask));
}
/**
* Whether the provided task is a desktop task with no non-minimized tasks - returns true if the
* desktop task has no tasks at all.
*
* @param groupTask The group task to check.
*/
static boolean isDestopTaskWithMinimizedTasksOnly(GroupTask groupTask) {
if (groupTask.taskViewType != TaskViewType.DESKTOP) {
return false;
}
return groupTask.getTasks().stream()
.filter(task -> !task.isMinimized)
.toList().isEmpty();
}
/**
@@ -154,7 +154,7 @@ public class RecentsModel implements RecentTasksDataSource, TaskStackChangeListe
/**
* Fetches the list of recent tasks. Tasks are ordered by recency, with the latest active tasks
* at the end of the list.
* at the end of the list. Filters out desktop tasks that contain no non-minimized tasks.
*
* @param callback The callback to receive the task plan once its complete or null. This is
* always called on the UI thread.
@@ -163,7 +163,7 @@ public class RecentsModel implements RecentTasksDataSource, TaskStackChangeListe
@Override
public int getTasks(@Nullable Consumer<List<GroupTask>> callback) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback,
RecentsFilterState.DEFAULT_FILTER);
RecentsFilterState.getEmptyDesktopTaskFilter());
}
/**
@@ -147,7 +147,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
@Test
fun canShowRunningAndRecentAppsIsFalseAfterInit_getTasksOnlyCalledInInit() {
// getTasks() should have been called once from init().
verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>())
verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>(), any())
recentAppsController.canShowRunningApps = false
recentAppsController.canShowRecentApps = false
prepareHotseatAndRunningAndRecentApps(
@@ -156,7 +156,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
)
// Verify that getTasks() was not called again after the init().
verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>())
verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>(), any())
}
@Test
@@ -881,7 +881,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
taskListChangeId
}
.whenever(mockRecentsModel)
.getTasks(any<Consumer<List<GroupTask>>>())
.getTasks(any<Consumer<List<GroupTask>>>(), any())
recentTasksChangedListener?.onRecentTasksChanged()
}
@@ -945,7 +945,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
}
private fun setInDesktopMode(inDesktopMode: Boolean) {
whenever(taskbarControllers.taskbarDesktopModeController.areDesktopTasksVisible)
whenever(taskbarControllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar())
.thenReturn(inDesktopMode)
}
@@ -21,6 +21,8 @@ import static com.google.common.truth.Truth.assertThat;
import static junit.framework.TestCase.assertNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -160,12 +162,15 @@ public class RecentTasksListTest {
List<Task> actualFreeformTasks = taskList.get(0).getTasks();
assertEquals(3, actualFreeformTasks.size());
assertEquals(1, actualFreeformTasks.get(0).key.id);
assertFalse(actualFreeformTasks.get(0).isMinimized);
assertEquals(4, actualFreeformTasks.get(1).key.id);
assertFalse(actualFreeformTasks.get(1).isMinimized);
assertEquals(5, actualFreeformTasks.get(2).key.id);
assertFalse(actualFreeformTasks.get(2).isMinimized);
}
@Test
public void loadTasksInBackground_freeformTask_onlyMinimizedTasks_doesNotCreateDesktopTask()
public void loadTasksInBackground_freeformTask_onlyMinimizedTasks_createDesktopTask()
throws Exception {
List<TaskInfo> tasks = Arrays.asList(
createRecentTaskInfo(1 /* taskId */),
@@ -180,7 +185,16 @@ public class RecentTasksListTest {
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
Integer.MAX_VALUE /* numTasks */, -1 /* requestId */, false /* loadKeysOnly */);
assertEquals(0, taskList.size());
assertEquals(1, taskList.size());
assertEquals(TaskViewType.DESKTOP, taskList.get(0).taskViewType);
List<Task> actualFreeformTasks = taskList.get(0).getTasks();
assertEquals(3, actualFreeformTasks.size());
assertEquals(1, actualFreeformTasks.get(0).key.id);
assertTrue(actualFreeformTasks.get(0).isMinimized);
assertEquals(4, actualFreeformTasks.get(1).key.id);
assertTrue(actualFreeformTasks.get(1).isMinimized);
assertEquals(5, actualFreeformTasks.get(2).key.id);
assertTrue(actualFreeformTasks.get(2).isMinimized);
}
private TaskInfo createRecentTaskInfo(int taskId) {