Fetch icon and thumbnail for completed task to prevent stale data
The data returned from getAllTaskData can sometimes replace recently fetched thumbnail and icon data with a null value due to a race condition. This occurs when getAllTaskData results are returned after, or at the same time as, the thumbnail and icon data is fetched. Consequently, the information displayed to the user is incorrect and remains so until the user re-enters Overview or scrolls. To address this issue, we propose to re-request the task data for requests that have already been completed.
Change-Id: I99ee7f38abab3c283c9f82bce7b1d069575ddc6e
Fix: 392069389
Doc: go/launcher-overview-unified-taskviewmodel
Flag: com.android.launcher3.enable_refactor_task_thumbnail
Test: OverviewImageTests
Test: TasksRepositoryTest
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 2f95413..b3f83f3 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -52,37 +52,29 @@
override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
if (forceRefresh) {
recentsModel.getTasks { newTaskList ->
- val oldTaskMap = tasks.value
val recentTasks =
newTaskList
.flatMap { groupTask -> groupTask.tasks }
.associateBy { it.key.id }
.also { newTaskMap ->
// Clean tasks that are not in the latest group tasks list.
- val tasksNoLongerVisible = oldTaskMap.keys.subtract(newTaskMap.keys)
+ val tasksNoLongerVisible = tasks.value.keys.subtract(newTaskMap.keys)
removeTasks(tasksNoLongerVisible)
-
- // Use pre-loaded thumbnail data and icon from the previous list.
- // This reduces the Thumbnail loading time in the Overview and prevent
- // empty thumbnail and icon.
- val cache =
- taskRequests.keys
- .mapNotNull { key ->
- val task = oldTaskMap[key] ?: return@mapNotNull null
- key to Pair(task.thumbnail, task.icon)
- }
- .toMap()
-
- newTaskMap.values.forEach { task ->
- task.thumbnail = task.thumbnail ?: cache[task.key.id]?.first
- task.icon = task.icon ?: cache[task.key.id]?.second
- }
}
- tasks.value = MapForStateFlow(recentTasks)
Log.d(
TAG,
- "getAllTaskData: oldTasks ${oldTaskMap.keys}, newTasks: ${recentTasks.keys}",
+ "getAllTaskData: oldTasks ${tasks.value.keys}, newTasks: ${recentTasks.keys}",
)
+ tasks.value = MapForStateFlow(recentTasks)
+
+ // Request data for completed tasks to prevent stale data.
+ // This will prevent thumbnail and icon from being replaced and
+ // null due to race condition.
+ taskRequests.values.forEach { (taskKey, job) ->
+ if (job.isCompleted) {
+ requestTaskData(taskKey.id)
+ }
+ }
}
}
return tasks.map { it.values.toList() }