From 641ffe50d81957a268b681805c06ad8d4bd2baca Mon Sep 17 00:00:00 2001 From: Daniel Andersson Date: Mon, 10 Mar 2025 11:24:53 -0700 Subject: [PATCH] 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 --- .../recents/domain/model/TaskModel.kt | 2 + .../recents/domain/usecase/GetTaskUseCase.kt | 1 + .../recents/ui/mapper/TaskUiStateMapper.kt | 3 +- .../recents/ui/viewmodel/TaskTileUiState.kt | 3 +- .../recents/ui/viewmodel/TaskViewModel.kt | 21 ++++--- .../task/thumbnail/TaskThumbnailView.kt | 1 + .../quickstep/views/DesktopTaskView.kt | 15 +++-- .../android/quickstep/views/TaskContainer.kt | 14 +---- .../com/android/quickstep/views/TaskView.kt | 1 - .../domain/usecase/GetTaskUseCaseTest.kt | 2 + .../ui/mapper/TaskUiStateMapperTest.kt | 30 ++++----- .../recents/ui/viewmodel/TaskViewModelTest.kt | 62 ++++++++++++++----- 12 files changed, 94 insertions(+), 61 deletions(-) diff --git a/quickstep/src/com/android/quickstep/recents/domain/model/TaskModel.kt b/quickstep/src/com/android/quickstep/recents/domain/model/TaskModel.kt index bf29b1d692..9af3997126 100644 --- a/quickstep/src/com/android/quickstep/recents/domain/model/TaskModel.kt +++ b/quickstep/src/com/android/quickstep/recents/domain/model/TaskModel.kt @@ -35,6 +35,7 @@ import com.android.systemui.shared.recents.model.ThumbnailData * @property backgroundColor The background color of the task, represented as an integer color * value. * @property isLocked Indicates whether the [Task] is locked. + * @property isMinimized Indicates whether the [Task] is minimized. */ data class TaskModel( val id: TaskId, @@ -44,6 +45,7 @@ data class TaskModel( val thumbnail: ThumbnailData?, val backgroundColor: Int, val isLocked: Boolean, + val isMinimized: Boolean, ) typealias TaskId = Int diff --git a/quickstep/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCase.kt b/quickstep/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCase.kt index a60144ba38..f1d455c10a 100644 --- a/quickstep/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCase.kt +++ b/quickstep/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCase.kt @@ -33,6 +33,7 @@ class GetTaskUseCase(private val repository: RecentTasksRepository) { thumbnail = task.thumbnail, backgroundColor = task.colorBackground, isLocked = task.isLocked, + isMinimized = task.isMinimized, ) } else { null diff --git a/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt b/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt index 619075ff83..3f6ea0f386 100644 --- a/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt +++ b/quickstep/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapper.kt @@ -42,13 +42,12 @@ object TaskUiStateMapper { */ fun toTaskThumbnailUiState( taskData: TaskData?, - isLiveTile: Boolean, hasHeader: Boolean, clickCloseListener: OnClickListener?, ): TaskThumbnailUiState = when { taskData !is TaskData.Data -> Uninitialized - isLiveTile -> createLiveTileState(taskData, hasHeader, clickCloseListener) + taskData.isLiveTile -> createLiveTileState(taskData, hasHeader, clickCloseListener) isBackgroundOnly(taskData) -> BackgroundOnly(taskData.backgroundColor) isSnapshotSplash(taskData) -> SnapshotSplash( diff --git a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskTileUiState.kt b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskTileUiState.kt index 863d30b2e4..dd55b09181 100644 --- a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskTileUiState.kt +++ b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskTileUiState.kt @@ -33,7 +33,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData */ data class TaskTileUiState( val tasks: List, - val isLiveTile: Boolean, val hasHeader: Boolean, val sysUiStatusNavFlags: Int, val taskOverlayEnabled: Boolean, @@ -56,6 +55,7 @@ sealed class TaskData { * @property thumbnailData Information related to the last snapshot retrieved from the app * @property backgroundColor The background color of the task. * @property isLocked Indicates whether the task is locked or not. + * @property isLiveTile Indicates whether the task is shown with a live tile or not. */ data class Data( override val taskId: Int, @@ -65,5 +65,6 @@ sealed class TaskData { val thumbnailData: ThumbnailData?, val backgroundColor: Int, val isLocked: Boolean, + val isLiveTile: Boolean, ) : TaskData() } diff --git a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt index 9f762e724c..faf2cc2eae 100644 --- a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt +++ b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt @@ -75,10 +75,10 @@ class TaskViewModel( private val taskData = taskIds.flatMapLatest { ids -> // Combine Tasks requests - combine( - ids.map { id -> getTaskUseCase(id).map { taskModel -> id to taskModel } }, - ::mapToTaskData, - ) + val taskFlows = + ids.map { id -> getTaskUseCase(id).map { taskModel -> id to taskModel } } + val combinedTaskFlows = combine(taskFlows) { taskArray -> taskArray } + combine(combinedTaskFlows, isLiveTile, ::mapToTaskData) } private val overlayEnabled = @@ -90,7 +90,7 @@ class TaskViewModel( .distinctUntilChanged() val state: Flow = - combine(taskData, isLiveTile, overlayEnabled, isCentralTask, ::mapToTaskTile) + combine(taskData, overlayEnabled, isCentralTask, ::mapToTaskTile) .distinctUntilChanged() .debounce { state -> // Debouncing only when thumbnails are not present gives the best results. @@ -126,14 +126,12 @@ class TaskViewModel( private fun mapToTaskTile( tasks: List, - isLiveTile: Boolean, overlayEnabled: Boolean, isCentralTask: Boolean, ): TaskTileUiState { val firstThumbnailData = (tasks.firstOrNull() as? TaskData.Data)?.thumbnailData return TaskTileUiState( tasks = tasks, - isLiveTile = isLiveTile, hasHeader = taskViewType == TaskViewType.DESKTOP, sysUiStatusNavFlags = getSysUiStatusNavFlagsUseCase(firstThumbnailData), taskOverlayEnabled = overlayEnabled, @@ -141,10 +139,12 @@ class TaskViewModel( ) } - private fun mapToTaskData(result: Array>): List = - result.map { mapToTaskData(it.first, it.second) } + private fun mapToTaskData( + result: Array>, + isLiveTile: Boolean, + ): List = result.map { mapToTaskData(it.first, it.second, isLiveTile) } - private fun mapToTaskData(taskId: TaskId, result: TaskModel?): TaskData = + private fun mapToTaskData(taskId: TaskId, result: TaskModel?, isLiveTile: Boolean): TaskData = result?.let { TaskData.Data( taskId = taskId, @@ -154,6 +154,7 @@ class TaskViewModel( thumbnailData = result.thumbnail, backgroundColor = result.backgroundColor.removeAlpha(), isLocked = result.isLocked, + isLiveTile = isLiveTile && !result.isMinimized, ) } ?: TaskData.NoData(taskId) diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt index 98d0efa096..52e2fcdf6c 100644 --- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt +++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt @@ -115,6 +115,7 @@ class TaskThumbnailView : FrameLayout, ViewPool.Reusable { uiState = Uninitialized onSizeChanged = null outlineBounds = null + alpha = 1.0f resetViews() } diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt index 000455be2d..6d77b424f0 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt @@ -285,6 +285,10 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu scaleX = currentTaskWidth / overviewTaskWidth scaleY = currentTaskHeight / overviewTaskHeight } + + if (taskContainer.task.isMinimized) { + taskContainer.snapshotView.alpha = explodeProgress + } } } @@ -295,10 +299,13 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu taskOverlayFactory: TaskOverlayFactory, ) { this.desktopTask = desktopTask - // TODO(b/370495260): Minimized tasks should not be filtered with desktop exploded view - // support. - // Minimized tasks should not be shown in Overview. - val tasks = desktopTask.tasks.filterNot { it.isMinimized } + // Minimized tasks are shown in Overview when exploded view is enabled. + val tasks = + if (enableDesktopExplodedView()) { + desktopTask.tasks + } else { + desktopTask.tasks.filterNot { it.isMinimized } + } if (DEBUG) { val sb = StringBuilder() sb.append("bind tasks=").append(tasks.size).append("\n") diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index 901fae6081..0998bd429b 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -165,20 +165,10 @@ class TaskContainer( overlay.addChildForAccessibility(outChildren) } - fun setState( - state: TaskData?, - liveTile: Boolean, - hasHeader: Boolean, - clickCloseListener: OnClickListener?, - ) = + fun setState(state: TaskData?, hasHeader: Boolean, clickCloseListener: OnClickListener?) = traceSection("TaskContainer.setState") { thumbnailView.setState( - TaskUiStateMapper.toTaskThumbnailUiState( - state, - liveTile, - hasHeader, - clickCloseListener, - ), + TaskUiStateMapper.toTaskThumbnailUiState(state, hasHeader, clickCloseListener), state?.taskId, ) thumbnailData = if (state is TaskData.Data) state.thumbnailData else null diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index e97c29009e..c9a60a72c5 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -826,7 +826,6 @@ constructor( val shouldHaveHeader = (type == TaskViewType.DESKTOP) && enableDesktopExplodedView() container.setState( state = containerState, - liveTile = state.isLiveTile, hasHeader = shouldHaveHeader, clickCloseListener = if (shouldHaveHeader) { diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCaseTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCaseTest.kt index b036bceea7..e436b60bab 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCaseTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/domain/usecase/GetTaskUseCaseTest.kt @@ -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 } } } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt index 7ca194afcf..cc658c7afc 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/mapper/TaskUiStateMapperTest.kt @@ -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, ) } } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt index 333c2856e6..9a2824173d 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModelTest.kt @@ -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, ) } }