From 1f09cd720d19be9afb7aa9de21e6b2296d83a3c3 Mon Sep 17 00:00:00 2001 From: Uwais Ashraf Date: Tue, 3 Dec 2024 14:54:48 +0000 Subject: [PATCH] Don't use flow for one-off get of ThumbnailData Bug: 381317629 Flag: com.android.launcher3.enable_refactor_task_thumbnail Test: TasksRepositoryTest Test: Performance tests Change-Id: I1990ad1972beea8c81b44cdd50c7f674f225c69d --- .../recents/data/RecentTasksRepository.kt | 6 +++ .../quickstep/recents/data/TasksRepository.kt | 2 + .../usecase/GetThumbnailPositionUseCase.kt | 11 +++-- .../recents/usecase/GetThumbnailUseCase.kt | 6 +-- .../usecase/SysUiStatusNavFlagsUseCase.kt | 5 +-- .../task/viewmodel/TaskOverlayViewModel.kt | 33 +++++++-------- .../viewmodel/TaskThumbnailViewModelImpl.kt | 18 ++++---- .../recents/data/FakeTasksRepository.kt | 3 ++ .../recents/data/TasksRepositoryTest.kt | 42 +++++++++++++++++++ 9 files changed, 82 insertions(+), 44 deletions(-) diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt index 3b59864b6d..53969c5219 100644 --- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt +++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt @@ -36,6 +36,12 @@ interface RecentTasksRepository { */ fun getThumbnailById(taskId: Int): Flow + /** + * Gets the [ThumbnailData] associated with a task that has id [taskId]. Flow will settle on + * null if the task was not found or is invisible. + */ + fun getCurrentThumbnailById(taskId: Int): ThumbnailData? + /** * Sets the tasks that are visible, indicating that properties relating to visuals need to be * populated e.g. icons/thumbnails etc. diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt index 6c627ef24c..3aae760a1a 100644 --- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt +++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt @@ -72,6 +72,8 @@ class TasksRepository( override fun getThumbnailById(taskId: Int) = getTaskDataById(taskId).map { it?.thumbnail }.distinctUntilChangedBy { it?.snapshotId } + override fun getCurrentThumbnailById(taskId: Int) = tasks.value[taskId]?.thumbnail + override fun setVisibleTasks(visibleTaskIdList: Set) { val tasksNoLongerVisible = taskRequests.keys.subtract(visibleTaskIdList) val newlyVisibleTasks = visibleTaskIdList.subtract(taskRequests.keys) diff --git a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt index f060d7deac..bea1d07042 100644 --- a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt +++ b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailPositionUseCase.kt @@ -24,18 +24,17 @@ import com.android.quickstep.recents.data.RecentsRotationStateRepository import com.android.quickstep.recents.usecase.ThumbnailPositionState.MatrixScaling import com.android.quickstep.recents.usecase.ThumbnailPositionState.MissingThumbnail import com.android.systemui.shared.recents.utilities.PreviewPositionHelper -import kotlinx.coroutines.flow.firstOrNull /** Use case for retrieving [Matrix] for positioning Thumbnail in a View */ class GetThumbnailPositionUseCase( private val deviceProfileRepository: RecentsDeviceProfileRepository, private val rotationStateRepository: RecentsRotationStateRepository, private val tasksRepository: RecentTasksRepository, - private val previewPositionHelper: PreviewPositionHelper = PreviewPositionHelper() + private val previewPositionHelper: PreviewPositionHelper = PreviewPositionHelper(), ) { - suspend fun run(taskId: Int, width: Int, height: Int, isRtl: Boolean): ThumbnailPositionState { + fun run(taskId: Int, width: Int, height: Int, isRtl: Boolean): ThumbnailPositionState { val thumbnailData = - tasksRepository.getThumbnailById(taskId).firstOrNull() ?: return MissingThumbnail + tasksRepository.getCurrentThumbnailById(taskId) ?: return MissingThumbnail val thumbnail = thumbnailData.thumbnail ?: return MissingThumbnail previewPositionHelper.updateThumbnailMatrix( Rect(0, 0, thumbnail.width, thumbnail.height), @@ -44,11 +43,11 @@ class GetThumbnailPositionUseCase( height, deviceProfileRepository.getRecentsDeviceProfile().isLargeScreen, rotationStateRepository.getRecentsRotationState().activityRotation, - isRtl + isRtl, ) return MatrixScaling( previewPositionHelper.matrix, - previewPositionHelper.isOrientationChanged + previewPositionHelper.isOrientationChanged, ) } } diff --git a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt index 3aa808ebd1..b9e9e026bc 100644 --- a/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt +++ b/quickstep/src/com/android/quickstep/recents/usecase/GetThumbnailUseCase.kt @@ -18,13 +18,9 @@ package com.android.quickstep.recents.usecase import android.graphics.Bitmap import com.android.quickstep.recents.data.RecentTasksRepository -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.runBlocking /** Use case for retrieving thumbnail. */ class GetThumbnailUseCase(private val taskRepository: RecentTasksRepository) { /** Returns the latest thumbnail associated with [taskId] if loaded, or null otherwise */ - fun run(taskId: Int): Bitmap? = runBlocking { - taskRepository.getThumbnailById(taskId).firstOrNull()?.thumbnail - } + fun run(taskId: Int): Bitmap? = taskRepository.getCurrentThumbnailById(taskId)?.thumbnail } diff --git a/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt b/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt index 1d19c7d332..5be5f4a7ba 100644 --- a/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt +++ b/quickstep/src/com/android/quickstep/recents/usecase/SysUiStatusNavFlagsUseCase.kt @@ -22,14 +22,11 @@ import com.android.launcher3.util.SystemUiController.FLAG_DARK_STATUS import com.android.launcher3.util.SystemUiController.FLAG_LIGHT_NAV import com.android.launcher3.util.SystemUiController.FLAG_LIGHT_STATUS import com.android.quickstep.recents.data.RecentTasksRepository -import kotlinx.coroutines.flow.firstOrNull -import kotlinx.coroutines.runBlocking /** UseCase to calculate flags for status bar and navigation bar */ class SysUiStatusNavFlagsUseCase(private val taskRepository: RecentTasksRepository) { fun getSysUiStatusNavFlags(taskId: Int): Int { - val thumbnailData = - runBlocking { taskRepository.getThumbnailById(taskId).firstOrNull() } ?: return 0 + val thumbnailData = taskRepository.getCurrentThumbnailById(taskId) ?: return 0 val thumbnailAppearance = thumbnailData.appearance var flags = 0 diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt index 4e13d1ce26..14359dbb30 100644 --- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt +++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt @@ -28,7 +28,6 @@ import com.android.systemui.shared.recents.model.Task import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map -import kotlinx.coroutines.runBlocking /** View model for TaskOverlay */ class TaskOverlayViewModel( @@ -41,7 +40,7 @@ class TaskOverlayViewModel( combine( recentsViewData.overlayEnabled, recentsViewData.settledFullyVisibleTaskIds.map { it.contains(task.key.id) }, - recentTasksRepository.getThumbnailById(task.key.id) + recentTasksRepository.getThumbnailById(task.key.id), ) { isOverlayEnabled, isFullyVisible, thumbnailData -> if (isOverlayEnabled && isFullyVisible) { Enabled( @@ -55,24 +54,22 @@ class TaskOverlayViewModel( .distinctUntilChanged() fun getThumbnailPositionState(width: Int, height: Int, isRtl: Boolean): ThumbnailPositionState { - return runBlocking { - val matrix: Matrix - val isRotated: Boolean - when ( - val thumbnailPositionState = - getThumbnailPositionUseCase.run(task.key.id, width, height, isRtl) - ) { - is MatrixScaling -> { - matrix = thumbnailPositionState.matrix - isRotated = thumbnailPositionState.isRotated - } - is MissingThumbnail -> { - matrix = Matrix.IDENTITY_MATRIX - isRotated = false - } + val matrix: Matrix + val isRotated: Boolean + when ( + val thumbnailPositionState = + getThumbnailPositionUseCase.run(task.key.id, width, height, isRtl) + ) { + is MatrixScaling -> { + matrix = thumbnailPositionState.matrix + isRotated = thumbnailPositionState.isRotated + } + is MissingThumbnail -> { + matrix = Matrix.IDENTITY_MATRIX + isRotated = false } - ThumbnailPositionState(matrix, isRotated) } + return ThumbnailPositionState(matrix, isRotated) } data class ThumbnailPositionState(val matrix: Matrix, val isRotated: Boolean) diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt index e5bad67c64..b5b2fc9407 100644 --- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt +++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModelImpl.kt @@ -44,7 +44,6 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.runBlocking @OptIn(ExperimentalCoroutinesApi::class) class TaskThumbnailViewModelImpl( @@ -109,17 +108,14 @@ class TaskThumbnailViewModelImpl( splashProgress.value = splashAlphaUseCase.execute(taskId) } - override fun getThumbnailPositionState(width: Int, height: Int, isRtl: Boolean): Matrix { - return runBlocking { - when ( - val thumbnailPositionState = - getThumbnailPositionUseCase.run(taskId, width, height, isRtl) - ) { - is ThumbnailPositionState.MatrixScaling -> thumbnailPositionState.matrix - is ThumbnailPositionState.MissingThumbnail -> Matrix.IDENTITY_MATRIX - } + override fun getThumbnailPositionState(width: Int, height: Int, isRtl: Boolean): Matrix = + when ( + val thumbnailPositionState = + getThumbnailPositionUseCase.run(taskId, width, height, isRtl) + ) { + is ThumbnailPositionState.MatrixScaling -> thumbnailPositionState.matrix + is ThumbnailPositionState.MissingThumbnail -> Matrix.IDENTITY_MATRIX } - } private fun isBackgroundOnly(task: Task): Boolean = task.isLocked || task.thumbnail == null diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt index d6688d6721..1c9ce0bbec 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt @@ -49,6 +49,9 @@ class FakeTasksRepository : RecentTasksRepository { override fun getThumbnailById(taskId: Int): Flow = getTaskDataById(taskId).map { it?.thumbnail } + override fun getCurrentThumbnailById(taskId: Int): ThumbnailData? = + tasks.value.firstOrNull { it.key.id == taskId }?.thumbnail + override fun setVisibleTasks(visibleTaskIdList: Set) { visibleTasks.value = visibleTaskIdList tasks.value = diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt index 357df6efc8..e0e7f2827a 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt @@ -86,6 +86,48 @@ class TasksRepositoryTest { assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2]) } + @Test + fun getThumbnailByIdReturnsNullWithNoLoadedThumbnails() = + testScope.runTest { + recentsModel.seedTasks(defaultTaskList) + systemUnderTest.getAllTaskData(forceRefresh = true) + + assertThat(systemUnderTest.getThumbnailById(1).first()).isNull() + } + + @Test + fun getCurrentThumbnailByIdReturnsNullWithNoLoadedThumbnails() = + testScope.runTest { + recentsModel.seedTasks(defaultTaskList) + systemUnderTest.getAllTaskData(forceRefresh = true) + + assertThat(systemUnderTest.getCurrentThumbnailById(1)).isNull() + } + + @Test + fun getThumbnailByIdReturnsThumbnailWithLoadedThumbnails() = + testScope.runTest { + recentsModel.seedTasks(defaultTaskList) + systemUnderTest.getAllTaskData(forceRefresh = true) + val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1] + + systemUnderTest.setVisibleTasks(setOf(1)) + + assertThat(systemUnderTest.getThumbnailById(1).first()!!.thumbnail).isEqualTo(bitmap1) + } + + @Test + fun getCurrentThumbnailByIdReturnsThumbnailWithLoadedThumbnails() = + testScope.runTest { + recentsModel.seedTasks(defaultTaskList) + systemUnderTest.getAllTaskData(forceRefresh = true) + val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1] + + systemUnderTest.setVisibleTasks(setOf(1)) + + assertThat(systemUnderTest.getCurrentThumbnailById(1)?.thumbnail).isEqualTo(bitmap1) + } + @Test fun setVisibleTasksPopulatesThumbnails() = testScope.runTest {