From ac49e0cb58f45828a8d290dcc73ac898bedf16d3 Mon Sep 17 00:00:00 2001 From: Jordan Silva Date: Mon, 27 Jan 2025 07:14:08 -0800 Subject: [PATCH] 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 --- .../quickstep/recents/data/TasksRepository.kt | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt index 2f95413e5b..b3f83f35cd 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 @@ class TasksRepository( override fun getAllTaskData(forceRefresh: Boolean): Flow> { 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() }