Merge changes from topic "taskbar-running-minimized" into main
* changes: Maintain Running Tasks order in Desktop mode Change running apps section to use GroupTask instead of AppInfo
This commit is contained in:
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
|
||||
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
|
||||
@@ -29,7 +26,6 @@ import com.android.launcher3.model.BgDataModel.FixedContainerItems;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.statehandlers.DesktopVisibilityController;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
@@ -37,8 +33,6 @@ import com.android.launcher3.util.ItemInfoMatcher;
|
||||
import com.android.launcher3.util.LauncherBindableItemsContainer;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.quickstep.LauncherActivityInterface;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -54,7 +48,7 @@ import java.util.function.Predicate;
|
||||
* Launcher model Callbacks for rendering taskbar.
|
||||
*/
|
||||
public class TaskbarModelCallbacks implements
|
||||
BgDataModel.Callbacks, LauncherBindableItemsContainer, RecentsModel.RunningTasksListener {
|
||||
BgDataModel.Callbacks, LauncherBindableItemsContainer {
|
||||
|
||||
private final SparseArray<ItemInfo> mHotseatItems = new SparseArray<>();
|
||||
private List<ItemInfo> mPredictedItems = Collections.emptyList();
|
||||
@@ -68,8 +62,6 @@ public class TaskbarModelCallbacks implements
|
||||
// Used to defer any UI updates during the SUW unstash animation.
|
||||
private boolean mDeferUpdatesForSUW;
|
||||
private Runnable mDeferredUpdates;
|
||||
private final DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
|
||||
visible -> updateRunningApps();
|
||||
|
||||
public TaskbarModelCallbacks(
|
||||
TaskbarActivityContext context, TaskbarView container) {
|
||||
@@ -79,39 +71,6 @@ public class TaskbarModelCallbacks implements
|
||||
|
||||
public void init(TaskbarControllers controllers) {
|
||||
mControllers = controllers;
|
||||
if (mControllers.taskbarRecentAppsController.getCanShowRunningApps()) {
|
||||
RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
|
||||
|
||||
if (shouldShowRunningAppsInDesktopMode()) {
|
||||
DesktopVisibilityController desktopVisibilityController =
|
||||
LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
|
||||
if (desktopVisibilityController != null) {
|
||||
desktopVisibilityController.registerDesktopVisibilityListener(
|
||||
mDesktopVisibilityListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters listeners in this class.
|
||||
*/
|
||||
public void unregisterListeners() {
|
||||
RecentsModel.INSTANCE.get(mContext).unregisterRunningTasksListener();
|
||||
|
||||
if (shouldShowRunningAppsInDesktopMode()) {
|
||||
DesktopVisibilityController desktopVisibilityController =
|
||||
LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
|
||||
if (desktopVisibilityController != null) {
|
||||
desktopVisibilityController.unregisterDesktopVisibilityListener(
|
||||
mDesktopVisibilityListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldShowRunningAppsInDesktopMode() {
|
||||
// TODO(b/335401172): unify DesktopMode checks in Launcher
|
||||
return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,10 +191,12 @@ public class TaskbarModelCallbacks implements
|
||||
predictionNextIndex++;
|
||||
}
|
||||
}
|
||||
hotseatItemInfos = mControllers.taskbarRecentAppsController
|
||||
.updateHotseatItemInfos(hotseatItemInfos);
|
||||
Set<String> runningPackages = mControllers.taskbarRecentAppsController.getRunningApps();
|
||||
Set<String> minimizedPackages = mControllers.taskbarRecentAppsController.getMinimizedApps();
|
||||
|
||||
final TaskbarRecentAppsController recentAppsController =
|
||||
mControllers.taskbarRecentAppsController;
|
||||
hotseatItemInfos = recentAppsController.updateHotseatItemInfos(hotseatItemInfos);
|
||||
Set<String> runningPackages = recentAppsController.getRunningAppPackages();
|
||||
Set<String> minimizedPackages = recentAppsController.getMinimizedAppPackages();
|
||||
|
||||
if (mDeferUpdatesForSUW) {
|
||||
ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
|
||||
@@ -270,21 +231,11 @@ public class TaskbarModelCallbacks implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRunningTasksChanged() {
|
||||
updateRunningApps();
|
||||
}
|
||||
|
||||
/** Called when there's a change in running apps to update the UI. */
|
||||
public void commitRunningAppsToUI() {
|
||||
commitItemsToUI();
|
||||
}
|
||||
|
||||
/** Call TaskbarRecentAppsController to update running apps with mHotseatItems. */
|
||||
public void updateRunningApps() {
|
||||
mControllers.taskbarRecentAppsController.updateRunningApps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
|
||||
mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy);
|
||||
@@ -296,7 +247,6 @@ public class TaskbarModelCallbacks implements
|
||||
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
|
||||
Preconditions.assertUIThread();
|
||||
mControllers.taskbarAllAppsController.setApps(apps, flags, packageUserKeytoUidMap);
|
||||
mControllers.taskbarRecentAppsController.setApps(apps);
|
||||
}
|
||||
|
||||
protected void dumpLogs(String prefix, PrintWriter pw) {
|
||||
|
||||
@@ -15,16 +15,13 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar
|
||||
|
||||
import android.app.ActivityManager.RunningTaskInfo
|
||||
import android.app.WindowConfiguration
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.launcher3.Flags.enableRecentsInTaskbar
|
||||
import com.android.launcher3.model.data.AppInfo
|
||||
import com.android.launcher3.model.data.ItemInfo
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo
|
||||
import com.android.launcher3.statehandlers.DesktopVisibilityController
|
||||
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
|
||||
import com.android.quickstep.RecentsModel
|
||||
import com.android.quickstep.util.DesktopTask
|
||||
import com.android.quickstep.util.GroupTask
|
||||
import com.android.window.flags.Flags.enableDesktopWindowingMode
|
||||
import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
|
||||
import java.io.PrintWriter
|
||||
@@ -42,22 +39,22 @@ class TaskbarRecentAppsController(
|
||||
) : LoggableTaskbarController {
|
||||
|
||||
// TODO(b/335401172): unify DesktopMode checks in Launcher.
|
||||
val canShowRunningApps =
|
||||
var canShowRunningApps =
|
||||
enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()
|
||||
|
||||
// TODO(b/343532825): Add a setting to disable Recents even when the flag is on.
|
||||
var isEnabled: Boolean = enableRecentsInTaskbar() || canShowRunningApps
|
||||
@VisibleForTesting
|
||||
set(isEnabledFromTest){
|
||||
set(isEnabledFromTest) {
|
||||
field = isEnabledFromTest
|
||||
}
|
||||
|
||||
// Initialized in init.
|
||||
private lateinit var controllers: TaskbarControllers
|
||||
|
||||
private var apps: Array<AppInfo>? = null
|
||||
private var allRunningDesktopAppInfos: List<AppInfo>? = null
|
||||
private var allMinimizedDesktopAppInfos: List<AppInfo>? = null
|
||||
private var shownHotseatItems: List<ItemInfo> = emptyList()
|
||||
private var allRecentTasks: List<GroupTask> = emptyList()
|
||||
private var desktopTask: DesktopTask? = null
|
||||
// TODO(next CL): actually read and show these
|
||||
var shownTasks: List<GroupTask> = emptyList()
|
||||
private set
|
||||
|
||||
private val desktopVisibilityController: DesktopVisibilityController?
|
||||
get() = desktopVisibilityControllerProvider()
|
||||
@@ -65,122 +62,139 @@ class TaskbarRecentAppsController(
|
||||
private val isInDesktopMode: Boolean
|
||||
get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
|
||||
|
||||
val runningApps: Set<String>
|
||||
val runningAppPackages: Set<String>
|
||||
/**
|
||||
* Returns the package names of apps that should be indicated as "running" to the user.
|
||||
* Specifically, we return all the open tasks if we are in Desktop mode, else emptySet().
|
||||
*/
|
||||
get() {
|
||||
if (!isEnabled || !isInDesktopMode) {
|
||||
if (!canShowRunningApps || !isInDesktopMode) {
|
||||
return emptySet()
|
||||
}
|
||||
return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
|
||||
val tasks = desktopTask?.tasks ?: return emptySet()
|
||||
return tasks.map { task -> task.key.packageName }.toSet()
|
||||
}
|
||||
|
||||
val minimizedApps: Set<String>
|
||||
val minimizedAppPackages: Set<String>
|
||||
/**
|
||||
* Returns the package names of apps that should be indicated as "minimized" to the user.
|
||||
* Specifically, we return all the running packages where all the tasks in that package are
|
||||
* minimized (not visible).
|
||||
*/
|
||||
get() {
|
||||
if (!isInDesktopMode) {
|
||||
if (!canShowRunningApps || !isInDesktopMode) {
|
||||
return emptySet()
|
||||
}
|
||||
return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet()
|
||||
?: emptySet()
|
||||
val desktopTasks = desktopTask?.tasks ?: return emptySet()
|
||||
val packageToTasks = desktopTasks.groupBy { it.key.packageName }
|
||||
return packageToTasks.filterValues { tasks -> tasks.all { !it.isVisible } }.keys
|
||||
}
|
||||
|
||||
private val recentTasksChangedListener =
|
||||
RecentsModel.RecentTasksChangedListener { reloadRecentTasksIfNeeded() }
|
||||
|
||||
// TODO(b/343291428): add TaskVisualsChangListener as well (for calendar/clock?)
|
||||
|
||||
// Used to keep track of the last requested task list ID, so that we do not request to load the
|
||||
// tasks again if we have already requested it and the task list has not changed
|
||||
private var taskListChangeId = -1
|
||||
|
||||
fun init(taskbarControllers: TaskbarControllers) {
|
||||
controllers = taskbarControllers
|
||||
recentsModel.registerRecentTasksChangedListener(recentTasksChangedListener)
|
||||
reloadRecentTasksIfNeeded()
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
apps = null
|
||||
}
|
||||
|
||||
/** Stores the current [AppInfo] instances, no-op except in desktop environment. */
|
||||
fun setApps(apps: Array<AppInfo>?) {
|
||||
this.apps = apps
|
||||
recentsModel.unregisterRecentTasksChangedListener()
|
||||
}
|
||||
|
||||
/** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */
|
||||
// TODO(next CL): add new section of Tasks instead of changing Hotseat items
|
||||
fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
|
||||
if (!isEnabled || !isInDesktopMode) {
|
||||
// Ignore predicted apps - we show running or recent apps instead.
|
||||
val removePredictions = isInDesktopMode && canShowRunningApps
|
||||
if (!removePredictions) {
|
||||
shownHotseatItems = hotseatItems.filterNotNull()
|
||||
onRecentsOrHotseatChanged()
|
||||
return hotseatItems
|
||||
}
|
||||
val newHotseatItemInfos =
|
||||
shownHotseatItems =
|
||||
hotseatItems
|
||||
.filterNotNull()
|
||||
// Ignore predicted apps - we show running apps instead
|
||||
.filter { itemInfo -> !itemInfo.isPredictedItem }
|
||||
.toMutableList()
|
||||
val runningDesktopAppInfos =
|
||||
allRunningDesktopAppInfos?.let {
|
||||
getRunningDesktopAppInfosExceptHotseatApps(it, newHotseatItemInfos.toList())
|
||||
|
||||
onRecentsOrHotseatChanged()
|
||||
|
||||
return shownHotseatItems.toTypedArray()
|
||||
}
|
||||
|
||||
private fun reloadRecentTasksIfNeeded() {
|
||||
if (!recentsModel.isTaskListValid(taskListChangeId)) {
|
||||
taskListChangeId =
|
||||
recentsModel.getTasks { tasks ->
|
||||
allRecentTasks = tasks
|
||||
desktopTask = allRecentTasks.filterIsInstance<DesktopTask>().firstOrNull()
|
||||
onRecentsOrHotseatChanged()
|
||||
controllers.taskbarViewController.commitRunningAppsToUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onRecentsOrHotseatChanged() {
|
||||
shownTasks =
|
||||
if (isInDesktopMode) {
|
||||
computeShownRunningTasks()
|
||||
} else {
|
||||
computeShownRecentTasks()
|
||||
}
|
||||
if (runningDesktopAppInfos != null) {
|
||||
newHotseatItemInfos.addAll(runningDesktopAppInfos)
|
||||
}
|
||||
return newHotseatItemInfos.toTypedArray()
|
||||
}
|
||||
|
||||
private fun getRunningDesktopAppInfosExceptHotseatApps(
|
||||
allRunningDesktopAppInfos: List<AppInfo>,
|
||||
hotseatItems: List<ItemInfo>
|
||||
): List<ItemInfo> {
|
||||
val hotseatPackages = hotseatItems.map { it.targetPackage }
|
||||
return allRunningDesktopAppInfos
|
||||
.filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
|
||||
.map { WorkspaceItemInfo(it) }
|
||||
}
|
||||
|
||||
private fun getDesktopRunningTasks(): List<RunningTaskInfo> =
|
||||
recentsModel.runningTasks.filter { taskInfo: RunningTaskInfo ->
|
||||
taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
|
||||
}
|
||||
|
||||
// TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
|
||||
private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
|
||||
// Early return if apps is empty, since we then have no AppInfo to compare to
|
||||
if (apps == null) {
|
||||
private fun computeShownRunningTasks(): List<GroupTask> {
|
||||
if (!canShowRunningApps) {
|
||||
return emptyList()
|
||||
}
|
||||
val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
|
||||
return packageNames
|
||||
.map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
|
||||
.filterNotNull()
|
||||
val tasks = desktopTask?.tasks ?: emptyList()
|
||||
// Kind of hacky, we wrap each single task in the Desktop as a GroupTask.
|
||||
var desktopTaskAsList = tasks.map { GroupTask(it) }
|
||||
// TODO(b/315344726 Multi-instance support): dedupe Tasks of the same package too.
|
||||
desktopTaskAsList = dedupeHotseatTasks(desktopTaskAsList, shownHotseatItems)
|
||||
val desktopPackages = desktopTaskAsList.map { it.packageNames }
|
||||
// Remove any missing Tasks.
|
||||
val newShownTasks = shownTasks.filter { it.packageNames in desktopPackages }.toMutableList()
|
||||
val newShownPackages = newShownTasks.map { it.packageNames }
|
||||
// Add any new Tasks, maintaining the order from previous shownTasks.
|
||||
newShownTasks.addAll(desktopTaskAsList.filter { it.packageNames !in newShownPackages })
|
||||
return newShownTasks.toList()
|
||||
}
|
||||
|
||||
/** Called to update the list of currently running apps, no-op except in desktop environment. */
|
||||
fun updateRunningApps() {
|
||||
if (!isEnabled || !isInDesktopMode) {
|
||||
return controllers.taskbarViewController.commitRunningAppsToUI()
|
||||
private fun computeShownRecentTasks(): List<GroupTask> {
|
||||
// TODO(next CL): implement Recents section
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
private fun dedupeHotseatTasks(
|
||||
groupTasks: List<GroupTask>,
|
||||
shownHotseatItems: List<ItemInfo>
|
||||
): List<GroupTask> {
|
||||
val hotseatPackages = shownHotseatItems.map { item -> item.targetPackage }
|
||||
return groupTasks.filter { groupTask ->
|
||||
groupTask.hasMultipleTasks() ||
|
||||
!hotseatPackages.contains(groupTask.task1.key.packageName)
|
||||
}
|
||||
val runningTasks = getDesktopRunningTasks()
|
||||
val runningAppInfo = getAppInfosFromRunningTasks(runningTasks)
|
||||
allRunningDesktopAppInfos = runningAppInfo
|
||||
updateMinimizedApps(runningTasks, runningAppInfo)
|
||||
controllers.taskbarViewController.commitRunningAppsToUI()
|
||||
}
|
||||
|
||||
private fun updateMinimizedApps(
|
||||
runningTasks: List<RunningTaskInfo>,
|
||||
runningAppInfo: List<AppInfo>,
|
||||
) {
|
||||
val allRunningAppTasks =
|
||||
runningAppInfo
|
||||
.mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } }
|
||||
.associate { (appInfo, targetPackage) ->
|
||||
appInfo to
|
||||
runningTasks
|
||||
.filter { it.realActivity?.packageName == targetPackage }
|
||||
.map { it.taskId }
|
||||
}
|
||||
val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible }
|
||||
allMinimizedDesktopAppInfos =
|
||||
allRunningAppTasks
|
||||
.filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } }
|
||||
.keys
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun dumpLogs(prefix: String, pw: PrintWriter) {
|
||||
pw.println("$prefix TaskbarRecentAppsController:")
|
||||
pw.println("$prefix\tisEnabled=$isEnabled")
|
||||
pw.println("$prefix\tcanShowRunningApps=$canShowRunningApps")
|
||||
// TODO(next CL): add more logs
|
||||
pw.println("$prefix\tshownHotseatItems=${shownHotseatItems.map{item->item.targetPackage}}")
|
||||
pw.println("$prefix\tallRecentTasks=${allRecentTasks.map { it.packageNames }}")
|
||||
pw.println("$prefix\tdesktopTask=${desktopTask?.packageNames}")
|
||||
pw.println("$prefix\tshownTasks=${shownTasks.map { it.packageNames }}")
|
||||
pw.println("$prefix\trunningTasks=$runningAppPackages")
|
||||
pw.println("$prefix\tminimizedTasks=$minimizedAppPackages")
|
||||
}
|
||||
|
||||
private val GroupTask.packageNames: List<String>
|
||||
get() = tasks.map { task -> task.key.packageName }
|
||||
}
|
||||
|
||||
@@ -224,7 +224,6 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
}
|
||||
LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks);
|
||||
mActivity.removeOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
|
||||
mModelCallbacks.unregisterListeners();
|
||||
}
|
||||
|
||||
public boolean areIconsVisible() {
|
||||
@@ -869,6 +868,11 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
return mTaskbarView.isEventOverAnyItem(ev);
|
||||
}
|
||||
|
||||
/** Called when there's a change in running apps to update the UI. */
|
||||
public void commitRunningAppsToUI() {
|
||||
mModelCallbacks.commitRunningAppsToUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpLogs(String prefix, PrintWriter pw) {
|
||||
pw.println(prefix + "TaskbarViewController:");
|
||||
@@ -889,14 +893,4 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
mModelCallbacks.dumpLogs(prefix + "\t", pw);
|
||||
}
|
||||
|
||||
/** Called when there's a change in running apps to update the UI. */
|
||||
public void commitRunningAppsToUI() {
|
||||
mModelCallbacks.commitRunningAppsToUI();
|
||||
}
|
||||
|
||||
/** Call TaskbarModelCallbacks to update running apps. */
|
||||
public void updateRunningApps() {
|
||||
mModelCallbacks.updateRunningApps();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ class TaskbarFeatureEvaluator(
|
||||
val hasNavButtons = taskbarActivityContext.isThreeButtonNav
|
||||
|
||||
val hasRecents: Boolean
|
||||
get() = taskbarControllers.taskbarRecentAppsController.isEnabled
|
||||
get() = taskbarControllers.taskbarRecentAppsController.shownTasks.isNotEmpty()
|
||||
|
||||
val hasDivider: Boolean
|
||||
get() = enableTaskbarPinning() || hasRecents
|
||||
|
||||
@@ -70,7 +70,8 @@ public class RecentTasksList {
|
||||
private TaskLoadResult mResultsBg = INVALID_RESULT;
|
||||
private TaskLoadResult mResultsUi = INVALID_RESULT;
|
||||
|
||||
private RecentsModel.RunningTasksListener mRunningTasksListener;
|
||||
private @Nullable RecentsModel.RunningTasksListener mRunningTasksListener;
|
||||
private @Nullable RecentsModel.RecentTasksChangedListener mRecentTasksChangedListener;
|
||||
// Tasks are stored in order of least recently launched to most recently launched.
|
||||
private ArrayList<ActivityManager.RunningTaskInfo> mRunningTasks;
|
||||
|
||||
@@ -199,6 +200,9 @@ public class RecentTasksList {
|
||||
|
||||
public void onRecentTasksChanged() {
|
||||
invalidateLoadedTasks();
|
||||
if (mRecentTasksChangedListener != null) {
|
||||
mRecentTasksChangedListener.onRecentTasksChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void invalidateLoadedTasks() {
|
||||
@@ -221,6 +225,21 @@ public class RecentTasksList {
|
||||
mRunningTasksListener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener for running tasks
|
||||
*/
|
||||
public void registerRecentTasksChangedListener(
|
||||
RecentsModel.RecentTasksChangedListener listener) {
|
||||
mRecentTasksChangedListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the previously registered running tasks listener
|
||||
*/
|
||||
public void unregisterRecentTasksChangedListener() {
|
||||
mRecentTasksChangedListener = null;
|
||||
}
|
||||
|
||||
private void initRunningTasks(ArrayList<ActivityManager.RunningTaskInfo> runningTasks) {
|
||||
// Tasks are retrieved in order of most recently launched/used to least recently launched.
|
||||
mRunningTasks = new ArrayList<>(runningTasks);
|
||||
@@ -357,6 +376,7 @@ public class RecentTasksList {
|
||||
task.setLastSnapshotData(taskInfo);
|
||||
task.positionInParent = taskInfo.positionInParent;
|
||||
task.appBounds = taskInfo.configuration.windowConfiguration.getAppBounds();
|
||||
task.isVisible = taskInfo.isVisible;
|
||||
tasks.add(task);
|
||||
}
|
||||
return new DesktopTask(tasks);
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.launcher3.util.Executors.SimpleThreadFactory;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.quickstep.recents.data.RecentTasksDataSource;
|
||||
import com.android.quickstep.util.DesktopTask;
|
||||
import com.android.quickstep.util.GroupTask;
|
||||
import com.android.quickstep.util.TaskVisualsChangeListener;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
@@ -301,6 +302,8 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
|
||||
/**
|
||||
* Registers a listener for running tasks
|
||||
* TODO(b/343292503): Should we remove RunningTasksListener entirely if it's not needed?
|
||||
* (Note that Desktop mode gets the running tasks by checking {@link DesktopTask#tasks}
|
||||
*/
|
||||
public void registerRunningTasksListener(RunningTasksListener listener) {
|
||||
mTaskList.registerRunningTasksListener(listener);
|
||||
@@ -313,6 +316,20 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
mTaskList.unregisterRunningTasksListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener for recent tasks
|
||||
*/
|
||||
public void registerRecentTasksChangedListener(RecentTasksChangedListener listener) {
|
||||
mTaskList.registerRecentTasksChangedListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the previously registered running tasks listener
|
||||
*/
|
||||
public void unregisterRecentTasksChangedListener() {
|
||||
mTaskList.unregisterRecentTasksChangedListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of running tasks.
|
||||
*/
|
||||
@@ -379,4 +396,14 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
|
||||
*/
|
||||
void onRunningTasksChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for receiving recent tasks changes
|
||||
*/
|
||||
public interface RecentTasksChangedListener {
|
||||
/**
|
||||
* Called when there's a change to recent tasks
|
||||
*/
|
||||
void onRecentTasksChanged();
|
||||
}
|
||||
}
|
||||
|
||||
+289
-129
@@ -16,24 +16,34 @@
|
||||
|
||||
package com.android.launcher3.taskbar
|
||||
|
||||
import android.app.ActivityManager.RunningTaskInfo
|
||||
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.os.Process
|
||||
import android.os.UserHandle
|
||||
import android.testing.AndroidTestingRunner
|
||||
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
|
||||
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION
|
||||
import com.android.launcher3.model.data.AppInfo
|
||||
import com.android.launcher3.model.data.ItemInfo
|
||||
import com.android.launcher3.statehandlers.DesktopVisibilityController
|
||||
import com.android.quickstep.RecentsModel
|
||||
import com.android.quickstep.RecentsModel.RecentTasksChangedListener
|
||||
import com.android.quickstep.util.DesktopTask
|
||||
import com.android.quickstep.util.GroupTask
|
||||
import com.android.systemui.shared.recents.model.Task
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.util.function.Consumer
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@@ -45,173 +55,292 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
|
||||
@Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
|
||||
|
||||
private var nextTaskId: Int = 500
|
||||
private var taskListChangeId: Int = 1
|
||||
|
||||
private lateinit var recentAppsController: TaskbarRecentAppsController
|
||||
private lateinit var recentTasksChangedListener: RecentTasksChangedListener
|
||||
private lateinit var userHandle: UserHandle
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
super.setup()
|
||||
userHandle = Process.myUserHandle()
|
||||
|
||||
recentAppsController =
|
||||
TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController }
|
||||
recentAppsController.init(taskbarControllers)
|
||||
recentAppsController.isEnabled = true
|
||||
recentAppsController.setApps(
|
||||
ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
|
||||
)
|
||||
recentAppsController.canShowRunningApps = true
|
||||
|
||||
val listenerCaptor = ArgumentCaptor.forClass(RecentTasksChangedListener::class.java)
|
||||
verify(mockRecentsModel).registerRecentTasksChangedListener(listenerCaptor.capture())
|
||||
recentTasksChangedListener = listenerCaptor.value
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() {
|
||||
setInDesktopMode(false)
|
||||
val hotseatItems =
|
||||
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
|
||||
|
||||
assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
|
||||
.isEqualTo(hotseatItems.toTypedArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItems() {
|
||||
setInDesktopMode(false)
|
||||
val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
|
||||
val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages)
|
||||
val runningTasks =
|
||||
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
recentAppsController.updateRunningApps()
|
||||
|
||||
fun updateHotseatItemInfos_cantShowRunning_inDesktopMode_returnsAllHotseatItems() {
|
||||
recentAppsController.canShowRunningApps = false
|
||||
setInDesktopMode(true)
|
||||
val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1)
|
||||
val newHotseatItems =
|
||||
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
|
||||
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = hotseatPackages,
|
||||
runningTaskPackages = emptyList(),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage })
|
||||
.containsExactlyElementsIn(hotseatPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() {
|
||||
fun updateHotseatItemInfos_canShowRunning_inDesktopMode_returnsNonPredictedHotseatItems() {
|
||||
recentAppsController.canShowRunningApps = true
|
||||
setInDesktopMode(true)
|
||||
val hotseatItems =
|
||||
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
|
||||
|
||||
assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
|
||||
.isEqualTo(hotseatItems.toTypedArray())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningApps() {
|
||||
setInDesktopMode(true)
|
||||
val hotseatItems =
|
||||
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
|
||||
val runningTasks =
|
||||
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
recentAppsController.updateRunningApps()
|
||||
|
||||
val newHotseatItems =
|
||||
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
|
||||
|
||||
val expectedPackages =
|
||||
listOf(
|
||||
HOTSEAT_PACKAGE_1,
|
||||
HOTSEAT_PACKAGE_2,
|
||||
RUNNING_APP_PACKAGE_1,
|
||||
RUNNING_APP_PACKAGE_2,
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1),
|
||||
runningTaskPackages = emptyList(),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage })
|
||||
.containsExactlyElementsIn(expectedPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItems() {
|
||||
fun onRecentTasksChanged_cantShowRunning_inDesktopMode_shownTasks_returnsEmptyList() {
|
||||
recentAppsController.canShowRunningApps = false
|
||||
setInDesktopMode(true)
|
||||
val hotseatItems =
|
||||
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
|
||||
val runningTasks =
|
||||
createDesktopTasksFromPackageNames(
|
||||
listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
)
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
recentAppsController.updateRunningApps()
|
||||
|
||||
val newHotseatItems =
|
||||
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
|
||||
|
||||
val expectedPackages =
|
||||
listOf(
|
||||
HOTSEAT_PACKAGE_1,
|
||||
HOTSEAT_PACKAGE_2,
|
||||
RUNNING_APP_PACKAGE_1,
|
||||
RUNNING_APP_PACKAGE_2,
|
||||
)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage })
|
||||
.containsExactlyElementsIn(expectedPackages)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1),
|
||||
runningTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
assertThat(recentAppsController.shownTasks).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRunningApps_notInDesktopMode_returnsEmptySet() {
|
||||
fun onRecentTasksChanged_inDesktopMode_noRunningApps_shownTasks_returnsEmptyList() {
|
||||
setInDesktopMode(true)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = emptyList(),
|
||||
recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
|
||||
)
|
||||
assertThat(recentAppsController.shownTasks).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_inDesktopMode_shownTasks_returnsRunningTasks() {
|
||||
setInDesktopMode(true)
|
||||
val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = runningTaskPackages,
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
|
||||
assertThat(shownPackages).containsExactlyElementsIn(runningTaskPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_inDesktopMode_runningAppIsHotseatItem_shownTasks_returnsDistinctItems() {
|
||||
setInDesktopMode(true)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
|
||||
runningTaskPackages =
|
||||
listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
val expectedPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
|
||||
assertThat(shownPackages).containsExactlyElementsIn(expectedPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_notInDesktopMode_getRunningApps_returnsEmptySet() {
|
||||
setInDesktopMode(false)
|
||||
val runningTasks =
|
||||
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
recentAppsController.updateRunningApps()
|
||||
|
||||
assertThat(recentAppsController.runningApps).isEmpty()
|
||||
assertThat(recentAppsController.minimizedApps).isEmpty()
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
assertThat(recentAppsController.runningAppPackages).isEmpty()
|
||||
assertThat(recentAppsController.minimizedAppPackages).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getRunningApps_inDesktopMode_returnsRunningApps() {
|
||||
fun onRecentTasksChanged_inDesktopMode_getRunningApps_returnsAllDesktopTasks() {
|
||||
setInDesktopMode(true)
|
||||
val runningTasks =
|
||||
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
recentAppsController.updateRunningApps()
|
||||
val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = runningTaskPackages,
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
assertThat(recentAppsController.runningAppPackages)
|
||||
.containsExactlyElementsIn(runningTaskPackages)
|
||||
assertThat(recentAppsController.minimizedAppPackages).isEmpty()
|
||||
}
|
||||
|
||||
assertThat(recentAppsController.runningApps)
|
||||
.containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
assertThat(recentAppsController.minimizedApps).isEmpty()
|
||||
@Test
|
||||
fun onRecentTasksChanged_inDesktopMode_getRunningApps_includesHotseat() {
|
||||
setInDesktopMode(true)
|
||||
val runningTaskPackages =
|
||||
listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
|
||||
runningTaskPackages = runningTaskPackages,
|
||||
recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
|
||||
)
|
||||
assertThat(recentAppsController.runningAppPackages)
|
||||
.containsExactlyElementsIn(runningTaskPackages)
|
||||
assertThat(recentAppsController.minimizedAppPackages).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getMinimizedApps_inDesktopMode_returnsAllAppsRunningAndInvisibleAppsMinimized() {
|
||||
setInDesktopMode(true)
|
||||
val runningTasks =
|
||||
ArrayList(
|
||||
listOf(
|
||||
createDesktopTaskInfo(RUNNING_APP_PACKAGE_1) { isVisible = true },
|
||||
createDesktopTaskInfo(RUNNING_APP_PACKAGE_2) { isVisible = true },
|
||||
createDesktopTaskInfo(RUNNING_APP_PACKAGE_3) { isVisible = false },
|
||||
)
|
||||
)
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
recentAppsController.updateRunningApps()
|
||||
val runningTaskPackages =
|
||||
listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
|
||||
val minimizedTaskIndices = setOf(2) // RUNNING_APP_PACKAGE_3
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = runningTaskPackages,
|
||||
minimizedTaskIndices = minimizedTaskIndices,
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
assertThat(recentAppsController.runningAppPackages)
|
||||
.containsExactlyElementsIn(runningTaskPackages)
|
||||
assertThat(recentAppsController.minimizedAppPackages).containsExactly(RUNNING_APP_PACKAGE_3)
|
||||
}
|
||||
|
||||
assertThat(recentAppsController.runningApps)
|
||||
.containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
|
||||
assertThat(recentAppsController.minimizedApps).containsExactly(RUNNING_APP_PACKAGE_3)
|
||||
@Test
|
||||
fun getMinimizedApps_inDesktopMode_twoTasksSamePackageOneMinimizedReturnsNotMinimized() {
|
||||
setInDesktopMode(true)
|
||||
val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_1)
|
||||
val minimizedTaskIndices = setOf(1) // The second RUNNING_APP_PACKAGE_1 task.
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = runningTaskPackages,
|
||||
minimizedTaskIndices = minimizedTaskIndices,
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
assertThat(recentAppsController.runningAppPackages)
|
||||
.containsExactlyElementsIn(runningTaskPackages.toSet())
|
||||
assertThat(recentAppsController.minimizedAppPackages).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_inDesktopMode_shownTasks_maintainsOrder() {
|
||||
setInDesktopMode(true)
|
||||
val originalOrder = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = originalOrder,
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = listOf(RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_1),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
|
||||
assertThat(shownPackages).isEqualTo(originalOrder)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_inDesktopMode_addTask_shownTasks_maintainsOrder() {
|
||||
setInDesktopMode(true)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages =
|
||||
listOf(RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_3),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
|
||||
val expectedOrder =
|
||||
listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
|
||||
assertThat(shownPackages).isEqualTo(expectedOrder)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_inDesktopMode_removeTask_shownTasks_maintainsOrder() {
|
||||
setInDesktopMode(true)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages =
|
||||
listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = listOf(RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_1),
|
||||
recentTaskPackages = emptyList()
|
||||
)
|
||||
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
|
||||
assertThat(shownPackages).isEqualTo(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRecentTasksChanged_enterDesktopMode_shownTasks_onlyIncludesRunningTasks() {
|
||||
setInDesktopMode(false)
|
||||
val runningTaskPackages = listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
val recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
|
||||
prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages = emptyList(),
|
||||
runningTaskPackages = runningTaskPackages,
|
||||
recentTaskPackages = recentTaskPackages
|
||||
)
|
||||
setInDesktopMode(true)
|
||||
recentTasksChangedListener.onRecentTasksChanged()
|
||||
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
|
||||
assertThat(shownPackages).containsExactlyElementsIn(runningTaskPackages)
|
||||
}
|
||||
|
||||
private fun prepareHotseatAndRunningAndRecentApps(
|
||||
hotseatPackages: List<String>,
|
||||
runningTaskPackages: List<String>,
|
||||
minimizedTaskIndices: Set<Int> = emptySet(),
|
||||
recentTaskPackages: List<String>,
|
||||
): Array<ItemInfo?> {
|
||||
val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages)
|
||||
val newHotseatItems =
|
||||
recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
|
||||
val runningTasks = createDesktopTask(runningTaskPackages, minimizedTaskIndices)
|
||||
val recentTasks = createRecentTasksFromPackageNames(recentTaskPackages)
|
||||
val allTasks =
|
||||
ArrayList<GroupTask>().apply {
|
||||
if (runningTasks != null) {
|
||||
add(runningTasks)
|
||||
}
|
||||
addAll(recentTasks)
|
||||
}
|
||||
doAnswer {
|
||||
val callback: Consumer<ArrayList<GroupTask>> = it.getArgument(0)
|
||||
callback.accept(allTasks)
|
||||
taskListChangeId
|
||||
}
|
||||
.whenever(mockRecentsModel)
|
||||
.getTasks(any<Consumer<List<GroupTask>>>())
|
||||
recentTasksChangedListener.onRecentTasksChanged()
|
||||
return newHotseatItems
|
||||
}
|
||||
|
||||
private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
|
||||
return packageNames.map { createTestAppInfo(packageName = it) }
|
||||
}
|
||||
|
||||
private fun createDesktopTasksFromPackageNames(
|
||||
packageNames: List<String>
|
||||
): ArrayList<RunningTaskInfo> {
|
||||
return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
|
||||
}
|
||||
|
||||
private fun createDesktopTaskInfo(
|
||||
packageName: String,
|
||||
init: RunningTaskInfo.() -> Unit = { isVisible = true },
|
||||
): RunningTaskInfo {
|
||||
return RunningTaskInfo().apply {
|
||||
taskId = nextTaskId++
|
||||
configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
|
||||
realActivity = ComponentName(packageName, "TestActivity")
|
||||
init()
|
||||
return packageNames.map {
|
||||
createTestAppInfo(packageName = it).apply {
|
||||
container =
|
||||
if (it.startsWith("predicted")) {
|
||||
CONTAINER_HOTSEAT_PREDICTION
|
||||
} else {
|
||||
CONTAINER_HOTSEAT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,23 +349,54 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
|
||||
className: String = "testClassName"
|
||||
) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent())
|
||||
|
||||
private fun createDesktopTask(
|
||||
packageNames: List<String>,
|
||||
minimizedTaskIndices: Set<Int>
|
||||
): DesktopTask? {
|
||||
if (packageNames.isEmpty()) return null
|
||||
|
||||
return DesktopTask(
|
||||
ArrayList(
|
||||
packageNames.mapIndexed { index, packageName ->
|
||||
createTask(packageName, index !in minimizedTaskIndices)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun createRecentTasksFromPackageNames(packageNames: List<String>): List<GroupTask> {
|
||||
return packageNames.map { GroupTask(createTask(it)) }
|
||||
}
|
||||
|
||||
private fun createTask(packageName: String, isVisible: Boolean = true): Task {
|
||||
return Task(
|
||||
Task.TaskKey(
|
||||
nextTaskId++,
|
||||
WINDOWING_MODE_FREEFORM,
|
||||
Intent().apply { `package` = packageName },
|
||||
ComponentName(packageName, "TestActivity"),
|
||||
userHandle.identifier,
|
||||
0
|
||||
)
|
||||
)
|
||||
.apply { this.isVisible = isVisible }
|
||||
}
|
||||
|
||||
private fun setInDesktopMode(inDesktopMode: Boolean) {
|
||||
whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode)
|
||||
}
|
||||
|
||||
private val GroupTask.packageNames: List<String>
|
||||
get() = tasks.map { task -> task.key.packageName }
|
||||
|
||||
private companion object {
|
||||
const val HOTSEAT_PACKAGE_1 = "hotseat1"
|
||||
const val HOTSEAT_PACKAGE_2 = "hotseat2"
|
||||
const val PREDICTED_PACKAGE_1 = "predicted1"
|
||||
const val RUNNING_APP_PACKAGE_1 = "running1"
|
||||
const val RUNNING_APP_PACKAGE_2 = "running2"
|
||||
const val RUNNING_APP_PACKAGE_3 = "running3"
|
||||
val ALL_APP_PACKAGES =
|
||||
listOf(
|
||||
HOTSEAT_PACKAGE_1,
|
||||
HOTSEAT_PACKAGE_2,
|
||||
RUNNING_APP_PACKAGE_1,
|
||||
RUNNING_APP_PACKAGE_2,
|
||||
RUNNING_APP_PACKAGE_3,
|
||||
)
|
||||
const val RECENT_PACKAGE_1 = "recent1"
|
||||
const val RECENT_PACKAGE_2 = "recent2"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user