From 7fd33ebde5ae4d08cd3af39f1aef099a596703b8 Mon Sep 17 00:00:00 2001 From: Uwais Ashraf Date: Wed, 19 Mar 2025 01:32:09 +0000 Subject: [PATCH] Change actions view disabling logic 1. Introduces "central task" - the task relating to the actions view 2. Decouple the overlay and actions view 3. Undo filter of taskViewType == SINGLE for overlay as it can be enabled for split tasks as well Bug: 402351284 Flag: com.android.launcher3.enable_refactor_task_thumbnail Test: OverviewImageTest (attached abtd run) Test: OverviewMenuImageTest (attached abtd run) Change-Id: Id7bc5c9c6620183d91e99d9dc5d2980eb8e3ec36 --- .../recents/ui/viewmodel/TaskTileUiState.kt | 1 + .../recents/ui/viewmodel/TaskViewModel.kt | 15 ++++-- .../recents/viewmodel/RecentsViewData.kt | 3 ++ .../recents/viewmodel/RecentsViewModel.kt | 4 ++ .../android/quickstep/views/RecentsView.java | 7 ++- .../quickstep/views/RecentsViewUtils.kt | 21 +++++++++ .../com/android/quickstep/views/TaskView.kt | 16 +++++++ .../recents/ui/viewmodel/TaskViewModelTest.kt | 47 ++++++++++--------- 8 files changed, 85 insertions(+), 29 deletions(-) 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 8a6a8051f1..863d30b2e4 100644 --- a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskTileUiState.kt +++ b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskTileUiState.kt @@ -37,6 +37,7 @@ data class TaskTileUiState( val hasHeader: Boolean, val sysUiStatusNavFlags: Int, val taskOverlayEnabled: Boolean, + val isCentralTask: Boolean, ) sealed class 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 09e20711d0..fac0c0a0bb 100644 --- a/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt +++ b/quickstep/src/com/android/quickstep/recents/ui/viewmodel/TaskViewModel.kt @@ -29,7 +29,6 @@ import com.android.quickstep.recents.domain.usecase.IsThumbnailValidUseCase import com.android.quickstep.recents.domain.usecase.ThumbnailPosition import com.android.quickstep.recents.viewmodel.RecentsViewData import com.android.quickstep.views.TaskViewType -import com.android.quickstep.views.TaskViewType.SINGLE import com.android.systemui.shared.recents.model.ThumbnailData import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow @@ -66,6 +65,12 @@ class TaskViewModel( } .distinctUntilChanged() + private val isCentralTask = + combine(taskIds, recentsViewData.centralTaskIds) { taskIds, centralTaskIds -> + taskIds == centralTaskIds + } + .distinctUntilChanged() + private val taskData = taskIds.flatMapLatest { ids -> // Combine Tasks requests @@ -79,14 +84,12 @@ class TaskViewModel( combine(recentsViewData.overlayEnabled, recentsViewData.settledFullyVisibleTaskIds) { isOverlayEnabled, settledFullyVisibleTaskIds -> - taskViewType == SINGLE && - isOverlayEnabled && - settledFullyVisibleTaskIds.any { it in taskIds.value } + isOverlayEnabled && settledFullyVisibleTaskIds.any { it in taskIds.value } } .distinctUntilChanged() val state: Flow = - combine(taskData, isLiveTile, overlayEnabled, ::mapToTaskTile) + combine(taskData, isLiveTile, overlayEnabled, isCentralTask, ::mapToTaskTile) .distinctUntilChanged() .flowOn(dispatcherProvider.background) @@ -114,6 +117,7 @@ class TaskViewModel( tasks: List, isLiveTile: Boolean, overlayEnabled: Boolean, + isCentralTask: Boolean, ): TaskTileUiState { val firstThumbnailData = (tasks.firstOrNull() as? TaskData.Data)?.thumbnailData return TaskTileUiState( @@ -122,6 +126,7 @@ class TaskViewModel( hasHeader = taskViewType == TaskViewType.DESKTOP, sysUiStatusNavFlags = getSysUiStatusNavFlagsUseCase(firstThumbnailData), taskOverlayEnabled = overlayEnabled, + isCentralTask = isCentralTask, ) } diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt index 2465a4671b..803fb354ff 100644 --- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt +++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewData.kt @@ -27,6 +27,9 @@ class RecentsViewData { // The settled set of visible taskIds that is updated after RecentsView scroll settles. val settledFullyVisibleTaskIds = MutableStateFlow(emptySet()) + // The id for the task ids in the TaskView that controls the Actions View + val centralTaskIds = MutableStateFlow(emptySet()) + // A list of taskIds that are associated with a RecentsAnimationController. */ val runningTaskIds = MutableStateFlow(emptySet()) diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt index 5ff8aaa840..4d168c7476 100644 --- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt +++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt @@ -38,6 +38,10 @@ class RecentsViewModel( recentsViewData.settledFullyVisibleTaskIds.value = taskIds } + fun updateCentralTaskIds(taskIds: Set) { + recentsViewData.centralTaskIds.value = taskIds + } + fun setOverlayEnabled(isOverlayEnabled: Boolean) { recentsViewData.overlayEnabled.value = isOverlayEnabled } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index aa25738eb2..b190c019b0 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -859,7 +859,7 @@ public abstract class RecentsView< */ private boolean mAnyTaskHasBeenDismissed; - private final RecentsViewModel mRecentsViewModel; + protected final RecentsViewModel mRecentsViewModel; private final RecentsViewModelHelper mHelper; protected final RecentsViewUtils mUtils = new RecentsViewUtils(this); protected final RecentsDismissUtils mDismissUtils = new RecentsDismissUtils(this); @@ -1595,7 +1595,7 @@ public abstract class RecentsView< /** * Returns true if the given TaskView is in expected scroll position. */ - public boolean isTaskInExpectedScrollPosition(TaskView taskView) { + public boolean isTaskInExpectedScrollPosition(@NonNull TaskView taskView) { return getScrollForPage(indexOfChild(taskView)) == getPagedOrientationHandler().getPrimaryScroll(this); } @@ -5993,6 +5993,9 @@ public abstract class RecentsView< updateCurrentTaskActionsVisibility(); loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL); updateEnabledOverlays(); + if (enableRefactorTaskThumbnail()) { + mUtils.updateCentralTask(); + } } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt index 51a5d0f0d6..50941fefa8 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewUtils.kt @@ -391,6 +391,27 @@ class RecentsViewUtils(private val recentsView: RecentsView<*, *>) { } } + fun updateCentralTask() { + val isTablet: Boolean = getDeviceProfile().isTablet + val actionsViewCanRelateToTaskView = !(isTablet && enableGridOnlyOverview()) + val focusedTaskView = recentsView.focusedTaskView + val currentPageTaskView = recentsView.currentPageTaskView + + fun isInExpectedScrollPosition(taskView: TaskView?) = + taskView?.let { recentsView.isTaskInExpectedScrollPosition(it) } ?: false + + val centralTaskIds: Set = + when { + !actionsViewCanRelateToTaskView -> emptySet() + isTablet && isInExpectedScrollPosition(focusedTaskView) -> + focusedTaskView!!.taskIdSet + isInExpectedScrollPosition(currentPageTaskView) -> currentPageTaskView!!.taskIdSet + else -> emptySet() + } + + recentsView.mRecentsViewModel.updateCentralTaskIds(centralTaskIds) + } + var deskExplodeProgress: Float = 0f set(value) { field = value diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index e6ef70868e..b1561fa769 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -100,6 +100,8 @@ import com.android.quickstep.util.TaskRemovedDuringLaunchListener import com.android.quickstep.util.displayId import com.android.quickstep.util.isExternalDisplay import com.android.quickstep.views.IconAppChipView.AppChipStatus +import com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBNAIL +import com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED import com.android.quickstep.views.RecentsView.UNBOUND_TASK_VIEW_ID import com.android.systemui.shared.recents.model.Task import com.android.systemui.shared.recents.model.ThumbnailData @@ -829,6 +831,20 @@ constructor( height = container.thumbnailView.height, ) container.setOverlayEnabled(state.taskOverlayEnabled, thumbnailPosition) + if (state.isCentralTask) { + this.container.actionsView.let { + it.updateDisabledFlags( + DISABLED_ROTATED, + thumbnailPosition?.isRotated ?: false, + ) + it.updateDisabledFlags( + DISABLED_NO_THUMBNAIL, + state.tasks.any { taskData -> + (taskData as? TaskData.Data)?.thumbnailData?.thumbnail == null + }, + ) + } + } if (enableOverviewIconMenu()) { setIconState(container, containerState) 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 18b9fe9685..333c2856e6 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 @@ -85,6 +85,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -132,6 +133,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -155,6 +157,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -178,6 +181,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -200,6 +204,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -218,6 +223,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_LIGHT_THEME, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -233,6 +239,7 @@ class TaskViewModelTest { hasHeader = false, sysUiStatusNavFlags = FLAGS_APPEARANCE_DEFAULT, taskOverlayEnabled = false, + isCentralTask = false, ) assertThat(sut.state.first()).isEqualTo(expectedResult) } @@ -247,28 +254,6 @@ class TaskViewModelTest { assertThat(sut.state.first().taskOverlayEnabled).isTrue() } - @Test - fun taskOverlayDisabled_when_usingGroupedTask() = - testScope.runTest { - sut = createTaskViewModel(TaskViewType.GROUPED) - sut.bind(TASK_MODEL_1.id) - recentsViewData.overlayEnabled.value = true - recentsViewData.settledFullyVisibleTaskIds.value = setOf(1) - - assertThat(sut.state.first().taskOverlayEnabled).isFalse() - } - - @Test - fun taskOverlayDisabled_when_usingDesktopTask() = - testScope.runTest { - sut = createTaskViewModel(TaskViewType.DESKTOP) - sut.bind(TASK_MODEL_1.id) - recentsViewData.overlayEnabled.value = true - recentsViewData.settledFullyVisibleTaskIds.value = setOf(1) - - assertThat(sut.state.first().taskOverlayEnabled).isFalse() - } - @Test fun taskOverlayDisabled_when_OverlayIsEnabledForInvisibleTask() = testScope.runTest { @@ -289,6 +274,24 @@ class TaskViewModelTest { assertThat(sut.state.first().taskOverlayEnabled).isFalse() } + @Test + fun isCentralTask_when_CentralTaskIdsMatchTaskIds() = + testScope.runTest { + sut.bind(TASK_MODEL_1.id, TASK_MODEL_2.id) + recentsViewData.centralTaskIds.value = setOf(TASK_MODEL_1.id, TASK_MODEL_2.id) + + assertThat(sut.state.first().isCentralTask).isTrue() + } + + @Test + fun isNotCentralTask_when_CentralTaskIdsDoMatchTaskIds() = + testScope.runTest { + sut.bind(TASK_MODEL_1.id, TASK_MODEL_2.id) + recentsViewData.centralTaskIds.value = setOf(TASK_MODEL_3.id) + + assertThat(sut.state.first().isCentralTask).isFalse() + } + @Test fun shouldShowSplash_calls_useCase() { sut.isThumbnailValid(null, 0, 0)