desktop-exploded-view: Basic support for minimized tasks

This makes minimized tasks visible in overview. These tasks are
immediately placed in the exploded position and then fade in during
the course of EXPLODE_PROGRESS.

This CL also moves isLiveTile from TaskTileUiState to TaskData.Data
since it's no longer a TaskView wide state.

Note: this CL only makes the minimized tasks visible in overview. It
does not yet un-minimize tasks on click.

Flag: com.android.launcher3.enable_desktop_exploded_view
Test: Manual
BUG=370495260

Change-Id: I5e441e81ae542902be9cd33d49bcb76d06bb1190
This commit is contained in:
Daniel Andersson
2025-04-07 10:31:47 -07:00
parent 9ab761e37c
commit 641ffe50d8
12 changed files with 94 additions and 61 deletions
@@ -75,6 +75,7 @@ class GetTaskUseCaseTest {
thumbnail = null,
backgroundColor = Color.BLACK,
isLocked = false,
isMinimized = false,
)
val result = sut.invoke(TASK_1_ID).firstOrNull()
assertThat(result).isEqualTo(expectedResult)
@@ -102,6 +103,7 @@ class GetTaskUseCaseTest {
icon = TASK_1_ICON
thumbnail = null
isLocked = false
isMinimized = false
}
}
}
@@ -42,7 +42,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = null,
isLiveTile = false,
hasHeader = false,
clickCloseListener = null,
)
@@ -52,12 +51,15 @@ class TaskUiStateMapperTest {
@Test
fun taskData_isLiveTile_returns_LiveTile() {
val inputs =
listOf(TASK_DATA, TASK_DATA.copy(thumbnailData = null), TASK_DATA.copy(isLocked = true))
listOf(
TASK_DATA.copy(isLiveTile = true),
TASK_DATA.copy(isLiveTile = true, thumbnailData = null),
TASK_DATA.copy(isLiveTile = true, isLocked = true),
)
inputs.forEach { input ->
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = input,
isLiveTile = true,
hasHeader = false,
clickCloseListener = null,
)
@@ -70,10 +72,10 @@ class TaskUiStateMapperTest {
fun taskData_isLiveTileWithHeader_returns_LiveTileWithHeader() {
val inputs =
listOf(
TASK_DATA,
TASK_DATA.copy(thumbnailData = null),
TASK_DATA.copy(isLocked = true),
TASK_DATA.copy(title = null),
TASK_DATA.copy(isLiveTile = true),
TASK_DATA.copy(isLiveTile = true, thumbnailData = null),
TASK_DATA.copy(isLiveTile = true, isLocked = true),
TASK_DATA.copy(isLiveTile = true, title = null),
)
val closeCallback = View.OnClickListener {}
val expected =
@@ -84,7 +86,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = taskData,
isLiveTile = true,
hasHeader = true,
clickCloseListener = closeCallback,
)
@@ -97,16 +98,15 @@ class TaskUiStateMapperTest {
fun taskData_isLiveTileWithHeader_missingHeaderData_returns_LiveTileWithoutHeader() {
val inputs =
listOf(
TASK_DATA.copy(icon = null),
TASK_DATA.copy(titleDescription = null),
TASK_DATA.copy(icon = null, titleDescription = null),
TASK_DATA.copy(isLiveTile = true, icon = null),
TASK_DATA.copy(isLiveTile = true, titleDescription = null),
TASK_DATA.copy(isLiveTile = true, icon = null, titleDescription = null),
)
inputs.forEach { taskData ->
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = taskData,
isLiveTile = true,
hasHeader = true,
clickCloseListener = {},
)
@@ -119,7 +119,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = TASK_DATA,
isLiveTile = false,
hasHeader = false,
clickCloseListener = null,
)
@@ -158,7 +157,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = taskData,
isLiveTile = false,
hasHeader = true,
clickCloseListener = closeCallback,
)
@@ -185,7 +183,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = taskData,
isLiveTile = false,
hasHeader = true,
clickCloseListener = {},
)
@@ -201,7 +198,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = TASK_DATA.copy(thumbnailData = null),
isLiveTile = false,
hasHeader = false,
clickCloseListener = null,
)
@@ -215,7 +211,6 @@ class TaskUiStateMapperTest {
val result =
TaskUiStateMapper.toTaskThumbnailUiState(
taskData = TASK_DATA.copy(isLocked = true),
isLiveTile = false,
hasHeader = false,
clickCloseListener = null,
)
@@ -241,6 +236,7 @@ class TaskUiStateMapperTest {
thumbnailData = TASK_THUMBNAIL_DATA,
backgroundColor = TASK_BACKGROUND_COLOR,
isLocked = false,
isLiveTile = false,
)
}
}
@@ -70,6 +70,8 @@ class TaskViewModelTest {
whenever(getTaskUseCase.invoke(TASK_MODEL_1.id)).thenReturn(flow { emit(TASK_MODEL_1) })
whenever(getTaskUseCase.invoke(TASK_MODEL_2.id)).thenReturn(flow { emit(TASK_MODEL_2) })
whenever(getTaskUseCase.invoke(TASK_MODEL_3.id)).thenReturn(flow { emit(TASK_MODEL_3) })
whenever(getTaskUseCase.invoke(TASK_MODEL_MINIMIZED.id))
.thenReturn(flow { emit(TASK_MODEL_MINIMIZED) })
whenever(getTaskUseCase.invoke(INVALID_TASK_ID)).thenReturn(flow { emit(null) })
recentsViewData.runningTaskIds.value = emptySet()
}
@@ -81,7 +83,6 @@ class TaskViewModelTest {
val expectedResult =
TaskTileUiState(
tasks = listOf(TASK_MODEL_1.toUiState()),
isLiveTile = false,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
@@ -129,7 +130,6 @@ class TaskViewModelTest {
TASK_MODEL_3.toUiState(),
TaskData.NoData(INVALID_TASK_ID),
),
isLiveTile = false,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
@@ -149,11 +149,34 @@ class TaskViewModelTest {
TaskTileUiState(
tasks =
listOf(
TASK_MODEL_1.toUiState(),
TASK_MODEL_2.toUiState(),
TASK_MODEL_3.toUiState(),
TASK_MODEL_1.toUiState(isLiveTile = true),
TASK_MODEL_2.toUiState(isLiveTile = true),
TASK_MODEL_3.toUiState(isLiveTile = true),
),
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
isCentralTask = false,
)
assertThat(sut.state.first()).isEqualTo(expectedResult)
}
@Test
fun isMixedLiveTile_when_oneTaskIsMinimized() =
testScope.runTest {
recentsViewData.runningTaskShowScreenshot.value = false
recentsViewData.runningTaskIds.value =
setOf(TASK_MODEL_1.id, TASK_MODEL_2.id, TASK_MODEL_3.id, TASK_MODEL_MINIMIZED.id)
sut.bind(TASK_MODEL_1.id, TASK_MODEL_2.id, TASK_MODEL_3.id, TASK_MODEL_MINIMIZED.id)
val expectedResult =
TaskTileUiState(
tasks =
listOf(
TASK_MODEL_1.toUiState(isLiveTile = true),
TASK_MODEL_2.toUiState(isLiveTile = true),
TASK_MODEL_3.toUiState(isLiveTile = true),
TASK_MODEL_MINIMIZED.toUiState(isLiveTile = false),
),
isLiveTile = true,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
@@ -177,7 +200,6 @@ class TaskViewModelTest {
TASK_MODEL_2.toUiState(),
TASK_MODEL_3.toUiState(),
),
isLiveTile = false,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
@@ -200,7 +222,6 @@ class TaskViewModelTest {
TASK_MODEL_2.toUiState(),
TASK_MODEL_3.toUiState(),
),
isLiveTile = false,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
@@ -219,7 +240,6 @@ class TaskViewModelTest {
val expectedResult =
TaskTileUiState(
tasks = listOf(TASK_MODEL_1.toUiState(), TASK_MODEL_2.toUiState()),
isLiveTile = false,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME,
taskOverlayEnabled = false,
@@ -235,7 +255,6 @@ class TaskViewModelTest {
val expectedResult =
TaskTileUiState(
listOf(TaskData.NoData(INVALID_TASK_ID)),
isLiveTile = false,
hasHeader = false,
sysUiStatusNavFlags = FLAGS_APPEARANCE_DEFAULT,
taskOverlayEnabled = false,
@@ -298,7 +317,7 @@ class TaskViewModelTest {
verify(isThumbnailValidUseCase).invoke(anyOrNull(), anyInt(), anyInt())
}
private fun TaskModel.toUiState() =
private fun TaskModel.toUiState(isLiveTile: Boolean = false) =
TaskData.Data(
taskId = id,
title = title,
@@ -307,6 +326,7 @@ class TaskViewModelTest {
thumbnailData = thumbnail,
backgroundColor = backgroundColor,
isLocked = isLocked,
isLiveTile = isLiveTile,
)
private fun createTaskViewModel(taskViewType: TaskViewType) =
@@ -337,7 +357,8 @@ class TaskViewModelTest {
ShapeDrawable(),
ThumbnailData(appearance = APPEARANCE_LIGHT_THEME),
Color.BLACK,
false,
/* isLocked= */ false,
/* isMinimized= */ false,
)
val TASK_MODEL_2 =
TaskModel(
@@ -347,7 +368,8 @@ class TaskViewModelTest {
ShapeDrawable(),
ThumbnailData(appearance = APPEARANCE_LIGHT_THEME),
Color.RED,
true,
/* isLocked= */ true,
/* isMinimized= */ false,
)
val TASK_MODEL_3 =
TaskModel(
@@ -357,7 +379,19 @@ class TaskViewModelTest {
ShapeDrawable(),
ThumbnailData(appearance = APPEARANCE_LIGHT_THEME),
Color.BLUE,
false,
/* isLocked= */ false,
/* isMinimized= */ false,
)
val TASK_MODEL_MINIMIZED =
TaskModel(
4,
"Title 4",
"Content Description 4",
ShapeDrawable(),
ThumbnailData(appearance = APPEARANCE_LIGHT_THEME),
Color.BLUE,
/* isLocked= */ false,
/* isMinimized= */ true,
)
}
}