mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
Update desktop mode to identify minimized tasks
When a task is minimised, it becomes invisible but is still running. WMShell now signals to the launcher when a task's visibility changes. The task bar takes the visibility into account to know if a running task is, in fact, minimised. Test: atest NexusLauncherTests:DesktopTaskbarRunningAppsControllerTest Flag: com.android.window.flags.enable_desktop_windowing_taskbar_running_apps Bug: 333872717 Change-Id: Iaff6b1240d354bb3c4de8e4884948acf9bf40112
This commit is contained in:
@@ -358,6 +358,9 @@
|
||||
<dimen name="taskbar_running_app_indicator_height">4dp</dimen>
|
||||
<dimen name="taskbar_running_app_indicator_width">14dp</dimen>
|
||||
<dimen name="taskbar_running_app_indicator_top_margin">2dp</dimen>
|
||||
<dimen name="taskbar_minimized_app_indicator_height">2dp</dimen>
|
||||
<dimen name="taskbar_minimized_app_indicator_width">12dp</dimen>
|
||||
<dimen name="taskbar_minimized_app_indicator_top_margin">2dp</dimen>
|
||||
|
||||
<!-- Transient taskbar -->
|
||||
<dimen name="transient_taskbar_padding">12dp</dimen>
|
||||
|
||||
@@ -47,6 +47,7 @@ class DesktopTaskbarRunningAppsController(
|
||||
|
||||
private var apps: Array<AppInfo>? = null
|
||||
private var allRunningDesktopAppInfos: List<AppInfo>? = null
|
||||
private var allMinimizedDesktopAppInfos: List<AppInfo>? = null
|
||||
|
||||
private val desktopVisibilityController: DesktopVisibilityController?
|
||||
get() = desktopVisibilityControllerProvider()
|
||||
@@ -95,6 +96,13 @@ class DesktopTaskbarRunningAppsController(
|
||||
return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
|
||||
}
|
||||
|
||||
override fun getMinimizedApps(): Set<String> {
|
||||
if (!isInDesktopMode) {
|
||||
return emptySet()
|
||||
}
|
||||
return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public override fun updateRunningApps() {
|
||||
if (!isInDesktopMode) {
|
||||
@@ -102,10 +110,34 @@ class DesktopTaskbarRunningAppsController(
|
||||
mControllers.taskbarViewController.commitRunningAppsToUI()
|
||||
return
|
||||
}
|
||||
allRunningDesktopAppInfos = getRunningDesktopAppInfos()
|
||||
val runningTasks = getDesktopRunningTasks()
|
||||
val runningAppInfo = getAppInfosFromRunningTasks(runningTasks)
|
||||
allRunningDesktopAppInfos = runningAppInfo
|
||||
updateMinimizedApps(runningTasks, runningAppInfo)
|
||||
mControllers.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()
|
||||
}
|
||||
|
||||
private fun getRunningDesktopAppInfosExceptHotseatApps(
|
||||
allRunningDesktopAppInfos: List<AppInfo>,
|
||||
hotseatItems: List<ItemInfo>
|
||||
@@ -116,15 +148,10 @@ class DesktopTaskbarRunningAppsController(
|
||||
.map { WorkspaceItemInfo(it) }
|
||||
}
|
||||
|
||||
private fun getRunningDesktopAppInfos(): List<AppInfo> {
|
||||
return getAppInfosFromRunningTasks(
|
||||
recentsModel.runningTasks
|
||||
.filter { taskInfo: RunningTaskInfo ->
|
||||
taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
|
||||
}
|
||||
.toList()
|
||||
)
|
||||
}
|
||||
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> {
|
||||
@@ -138,9 +165,10 @@ class DesktopTaskbarRunningAppsController(
|
||||
.filterNotNull()
|
||||
}
|
||||
|
||||
private fun <E> SparseArray<E>.toList(): List<E> {
|
||||
return valueIterator().asSequence().toList()
|
||||
}
|
||||
private fun getAppInfosFromRunningTask(task: RunningTaskInfo): AppInfo? =
|
||||
apps?.firstOrNull { it.targetPackage == task.realActivity?.packageName }
|
||||
|
||||
private fun <E> SparseArray<E>.toList(): List<E> = valueIterator().asSequence().toList()
|
||||
|
||||
companion object {
|
||||
private const val TAG = "TabletDesktopTaskbarRunningAppsController"
|
||||
|
||||
@@ -68,7 +68,7 @@ public class TaskbarModelCallbacks implements
|
||||
// Used to defer any UI updates during the SUW unstash animation.
|
||||
private boolean mDeferUpdatesForSUW;
|
||||
private Runnable mDeferredUpdates;
|
||||
private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
|
||||
private final DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
|
||||
visible -> updateRunningApps();
|
||||
|
||||
public TaskbarModelCallbacks(
|
||||
@@ -235,20 +235,23 @@ public class TaskbarModelCallbacks implements
|
||||
hotseatItemInfos = mControllers.taskbarRecentAppsController
|
||||
.updateHotseatItemInfos(hotseatItemInfos);
|
||||
Set<String> runningPackages = mControllers.taskbarRecentAppsController.getRunningApps();
|
||||
Set<String> minimizedPackages = mControllers.taskbarRecentAppsController.getMinimizedApps();
|
||||
|
||||
if (mDeferUpdatesForSUW) {
|
||||
ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
|
||||
mDeferredUpdates = () ->
|
||||
commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages);
|
||||
commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages,
|
||||
minimizedPackages);
|
||||
} else {
|
||||
commitHotseatItemUpdates(hotseatItemInfos, runningPackages);
|
||||
commitHotseatItemUpdates(hotseatItemInfos, runningPackages, minimizedPackages);
|
||||
}
|
||||
}
|
||||
|
||||
private void commitHotseatItemUpdates(
|
||||
ItemInfo[] hotseatItemInfos, Set<String> runningPackages) {
|
||||
private void commitHotseatItemUpdates(ItemInfo[] hotseatItemInfos, Set<String> runningPackages,
|
||||
Set<String> minimizedPackages) {
|
||||
mContainer.updateHotseatItems(hotseatItemInfos);
|
||||
mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages);
|
||||
mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages,
|
||||
minimizedPackages);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -69,4 +69,9 @@ public class TaskbarRecentAppsController {
|
||||
public Set<String> getRunningApps() {
|
||||
return emptySet();
|
||||
}
|
||||
|
||||
/** Returns the set of apps whose tasks are all minimized. */
|
||||
public Set<String> getMinimizedApps() {
|
||||
return emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,14 +510,30 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
}
|
||||
|
||||
/** Updates which icons are marked as running given the Set of currently running packages. */
|
||||
public void updateIconViewsRunningStates(Set<String> runningPackages) {
|
||||
public void updateIconViewsRunningStates(Set<String> runningPackages,
|
||||
Set<String> minimizedPackages) {
|
||||
for (View iconView : getIconViews()) {
|
||||
if (iconView instanceof BubbleTextView btv) {
|
||||
btv.updateRunningState(runningPackages.contains(btv.getTargetPackageName()));
|
||||
btv.updateRunningState(
|
||||
getRunningAppState(btv.getTargetPackageName(), runningPackages,
|
||||
minimizedPackages));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BubbleTextView.RunningAppState getRunningAppState(
|
||||
String packageName,
|
||||
Set<String> runningPackages,
|
||||
Set<String> minimizedPackages) {
|
||||
if (minimizedPackages.contains(packageName)) {
|
||||
return BubbleTextView.RunningAppState.MINIMIZED;
|
||||
}
|
||||
if (runningPackages.contains(packageName)) {
|
||||
return BubbleTextView.RunningAppState.RUNNING;
|
||||
}
|
||||
return BubbleTextView.RunningAppState.NOT_RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defers any updates to the UI for the setup wizard animation.
|
||||
*/
|
||||
|
||||
@@ -86,7 +86,8 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
|
||||
val newHotseatItems =
|
||||
taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
|
||||
|
||||
assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(hotseatPackages)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage })
|
||||
.containsExactlyElementsIn(hotseatPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,7 +120,8 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
|
||||
RUNNING_APP_PACKAGE_1,
|
||||
RUNNING_APP_PACKAGE_2,
|
||||
)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage })
|
||||
.containsExactlyElementsIn(expectedPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,7 +146,8 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
|
||||
RUNNING_APP_PACKAGE_1,
|
||||
RUNNING_APP_PACKAGE_2,
|
||||
)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
|
||||
assertThat(newHotseatItems.map { it?.targetPackage })
|
||||
.containsExactlyElementsIn(expectedPackages)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -155,7 +158,8 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
|
||||
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
|
||||
taskbarRunningAppsController.updateRunningApps()
|
||||
|
||||
assertThat(taskbarRunningAppsController.runningApps).isEqualTo(emptySet<String>())
|
||||
assertThat(taskbarRunningAppsController.runningApps).isEmpty()
|
||||
assertThat(taskbarRunningAppsController.minimizedApps).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -167,7 +171,28 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
|
||||
taskbarRunningAppsController.updateRunningApps()
|
||||
|
||||
assertThat(taskbarRunningAppsController.runningApps)
|
||||
.isEqualTo(setOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
|
||||
.containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
|
||||
assertThat(taskbarRunningAppsController.minimizedApps).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)
|
||||
taskbarRunningAppsController.updateRunningApps()
|
||||
|
||||
assertThat(taskbarRunningAppsController.runningApps)
|
||||
.containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
|
||||
assertThat(taskbarRunningAppsController.minimizedApps)
|
||||
.containsExactly(RUNNING_APP_PACKAGE_3)
|
||||
}
|
||||
|
||||
private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
|
||||
@@ -180,11 +205,15 @@ class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
|
||||
return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
|
||||
}
|
||||
|
||||
private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -416,6 +416,9 @@
|
||||
<dimen name="taskbar_running_app_indicator_height">0dp</dimen>
|
||||
<dimen name="taskbar_running_app_indicator_width">0dp</dimen>
|
||||
<dimen name="taskbar_running_app_indicator_top_margin">0dp</dimen>
|
||||
<dimen name="taskbar_minimized_app_indicator_height">0dp</dimen>
|
||||
<dimen name="taskbar_minimized_app_indicator_width">0dp</dimen>
|
||||
<dimen name="taskbar_minimized_app_indicator_top_margin">0dp</dimen>
|
||||
|
||||
<!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
|
||||
<dimen name="transient_taskbar_padding">0dp</dimen>
|
||||
|
||||
@@ -186,9 +186,20 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
// These fields, related to showing running apps, are only used for Taskbar.
|
||||
private final Size mRunningAppIndicatorSize;
|
||||
private final int mRunningAppIndicatorTopMargin;
|
||||
private final Size mMinimizedAppIndicatorSize;
|
||||
private final int mMinimizedAppIndicatorTopMargin;
|
||||
private final Paint mRunningAppIndicatorPaint;
|
||||
private final Rect mRunningAppIconBounds = new Rect();
|
||||
private boolean mIsRunning;
|
||||
private RunningAppState mRunningAppState;
|
||||
|
||||
/**
|
||||
* Various options for the running state of an app.
|
||||
*/
|
||||
public enum RunningAppState {
|
||||
NOT_RUNNING,
|
||||
RUNNING,
|
||||
MINIMIZED,
|
||||
}
|
||||
|
||||
@ViewDebug.ExportedProperty(category = "launcher")
|
||||
private boolean mStayPressed;
|
||||
@@ -259,9 +270,16 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
mRunningAppIndicatorSize = new Size(
|
||||
getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_width),
|
||||
getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_height));
|
||||
mMinimizedAppIndicatorSize = new Size(
|
||||
getResources().getDimensionPixelSize(R.dimen.taskbar_minimized_app_indicator_width),
|
||||
getResources().getDimensionPixelSize(
|
||||
R.dimen.taskbar_minimized_app_indicator_height));
|
||||
mRunningAppIndicatorTopMargin =
|
||||
getResources().getDimensionPixelSize(
|
||||
R.dimen.taskbar_running_app_indicator_top_margin);
|
||||
mMinimizedAppIndicatorTopMargin =
|
||||
getResources().getDimensionPixelSize(
|
||||
R.dimen.taskbar_minimized_app_indicator_top_margin);
|
||||
mRunningAppIndicatorPaint = new Paint();
|
||||
mRunningAppIndicatorPaint.setColor(getResources().getColor(
|
||||
R.color.taskbar_running_app_indicator_color, context.getTheme()));
|
||||
@@ -414,8 +432,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
|
||||
/** Updates whether the app this view represents is currently running. */
|
||||
@UiThread
|
||||
public void updateRunningState(boolean isRunning) {
|
||||
mIsRunning = isRunning;
|
||||
public void updateRunningState(RunningAppState runningAppState) {
|
||||
mRunningAppState = runningAppState;
|
||||
}
|
||||
|
||||
protected void setItemInfo(ItemInfoWithIcon itemInfo) {
|
||||
@@ -667,18 +685,20 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
|
||||
/** Draws a line under the app icon if this is representing a running app in Desktop Mode. */
|
||||
protected void drawRunningAppIndicatorIfNecessary(Canvas canvas) {
|
||||
if (!mIsRunning || mDisplay != DISPLAY_TASKBAR) {
|
||||
if (mRunningAppState == RunningAppState.NOT_RUNNING || mDisplay != DISPLAY_TASKBAR) {
|
||||
return;
|
||||
}
|
||||
getIconBounds(mRunningAppIconBounds);
|
||||
// TODO(b/333872717): update color, shape, and size of indicator
|
||||
int indicatorTop = mRunningAppIconBounds.bottom + mRunningAppIndicatorTopMargin;
|
||||
canvas.drawRect(
|
||||
mRunningAppIconBounds.centerX() - mRunningAppIndicatorSize.getWidth() / 2,
|
||||
indicatorTop,
|
||||
mRunningAppIconBounds.centerX() + mRunningAppIndicatorSize.getWidth() / 2,
|
||||
indicatorTop + mRunningAppIndicatorSize.getHeight(),
|
||||
mRunningAppIndicatorPaint);
|
||||
boolean isMinimized = mRunningAppState == RunningAppState.MINIMIZED;
|
||||
int indicatorTop =
|
||||
mRunningAppIconBounds.bottom + (isMinimized ? mMinimizedAppIndicatorTopMargin
|
||||
: mRunningAppIndicatorTopMargin);
|
||||
final Size indicatorSize =
|
||||
isMinimized ? mMinimizedAppIndicatorSize : mRunningAppIndicatorSize;
|
||||
canvas.drawRect(mRunningAppIconBounds.centerX() - indicatorSize.getWidth() / 2,
|
||||
indicatorTop, mRunningAppIconBounds.centerX() + indicatorSize.getWidth() / 2,
|
||||
indicatorTop + indicatorSize.getHeight(), mRunningAppIndicatorPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user