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
This commit is contained in:
Uwais Ashraf
2025-03-19 01:32:09 +00:00
parent b307f55a19
commit 7fd33ebde5
8 changed files with 85 additions and 29 deletions
@@ -37,6 +37,7 @@ data class TaskTileUiState(
val hasHeader: Boolean,
val sysUiStatusNavFlags: Int,
val taskOverlayEnabled: Boolean,
val isCentralTask: Boolean,
)
sealed class TaskData {
@@ -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<TaskTileUiState> =
combine(taskData, isLiveTile, overlayEnabled, ::mapToTaskTile)
combine(taskData, isLiveTile, overlayEnabled, isCentralTask, ::mapToTaskTile)
.distinctUntilChanged()
.flowOn(dispatcherProvider.background)
@@ -114,6 +117,7 @@ class TaskViewModel(
tasks: List<TaskData>,
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,
)
}
@@ -27,6 +27,9 @@ class RecentsViewData {
// The settled set of visible taskIds that is updated after RecentsView scroll settles.
val settledFullyVisibleTaskIds = MutableStateFlow(emptySet<Int>())
// The id for the task ids in the TaskView that controls the Actions View
val centralTaskIds = MutableStateFlow(emptySet<Int>())
// A list of taskIds that are associated with a RecentsAnimationController. */
val runningTaskIds = MutableStateFlow(emptySet<Int>())
@@ -38,6 +38,10 @@ class RecentsViewModel(
recentsViewData.settledFullyVisibleTaskIds.value = taskIds
}
fun updateCentralTaskIds(taskIds: Set<Int>) {
recentsViewData.centralTaskIds.value = taskIds
}
fun setOverlayEnabled(isOverlayEnabled: Boolean) {
recentsViewData.overlayEnabled.value = isOverlayEnabled
}
@@ -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
@@ -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<Int> =
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
@@ -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)
@@ -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)