Move cancellation of CoroutineScopes to bg thread as it can be slow.
Bug: 381317629
Fix: 383999850
Flag: com.android.launcher3.enable_refactor_task_thumbnail
Test: Manual - checking perfetto traces for improvement
Test: Performance tests
Change-Id: Ic796fe578f5aa98ce060ac22341a1bcfa68061df
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 3aae760..8c26d8f 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -96,7 +96,7 @@
taskRequests[taskId] =
Pair(
task.key,
- recentsCoroutineScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
Log.i(TAG, "requestTaskData: $taskId")
fetchIcon(task)
fetchThumbnail(task)
@@ -134,7 +134,7 @@
task.key,
object : TaskIconChangedCallback {
override fun onTaskIconChanged() {
- recentsCoroutineScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
updateIcon(task.key.id, getIconFromDataSource(task))
}
}
@@ -152,7 +152,7 @@
}
override fun onHighResLoadingStateChanged() {
- recentsCoroutineScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
updateThumbnail(task.key.id, getThumbnailFromDataSource(task))
}
}
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index b78e214..95ecbe9 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -39,7 +39,6 @@
import com.android.systemui.shared.recents.model.Task
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
internal typealias RecentsScopeId = String
@@ -58,10 +57,13 @@
private fun startDefaultScope(appContext: Context) {
createScope(DEFAULT_SCOPE_ID).apply {
set(RecentsViewData::class.java.simpleName, RecentsViewData())
+ val dispatcherProvider: DispatcherProvider = ProductionDispatchers
val recentsCoroutineScope =
- CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("RecentsView"))
+ CoroutineScope(
+ SupervisorJob() + dispatcherProvider.unconfined + CoroutineName("RecentsView")
+ )
set(CoroutineScope::class.java.simpleName, recentsCoroutineScope)
- set(DispatcherProvider::class.java.simpleName, ProductionDispatchers)
+ set(DispatcherProvider::class.java.simpleName, dispatcherProvider)
val recentsModel = RecentsModel.INSTANCE.get(appContext)
val taskVisualsChangedDelegate =
TaskVisualsChangedDelegateImpl(
@@ -170,18 +172,6 @@
log("linked scopes: ${getScope(scopeId).scopeIdsLinked}")
val instance: Any =
when (modelClass) {
- RecentTasksRepository::class.java -> {
- with(RecentsModel.INSTANCE.get(appContext)) {
- TasksRepository(
- this,
- thumbnailCache,
- iconCache,
- get(),
- get(),
- ProductionDispatchers,
- )
- }
- }
RecentsViewData::class.java -> RecentsViewData()
TaskContainerData::class.java -> TaskContainerData()
TaskThumbnailViewData::class.java -> TaskThumbnailViewData()
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index ea4602d..e334695 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -29,6 +29,7 @@
import androidx.core.view.isInvisible
import com.android.launcher3.R
import com.android.launcher3.util.ViewPool
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
@@ -45,8 +46,12 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
+ private val recentsCoroutineScope: CoroutineScope = RecentsDependencies.get()
+ private val dispatcherProvider: DispatcherProvider = RecentsDependencies.get()
+
private lateinit var viewData: TaskThumbnailViewData
private lateinit var viewModel: TaskThumbnailViewModel
@@ -119,7 +124,9 @@
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
- viewAttachedScope.cancel("TaskThumbnailView detaching from window")
+ recentsCoroutineScope.launch(dispatcherProvider.background) {
+ viewAttachedScope.cancel("TaskThumbnailView detaching from window")
+ }
}
override fun onRecycle() {
diff --git a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
index 203177a..e6c8d27 100644
--- a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
+++ b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
@@ -18,6 +18,7 @@
import android.util.Log
import android.view.View.OnLayoutChangeListener
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
@@ -33,12 +34,15 @@
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.launch
/**
* Helper for [TaskOverlayFactory.TaskOverlay] to interact with [TaskOverlayViewModel], this helper
* should merge with [TaskOverlayFactory.TaskOverlay] when it's migrated to MVVM.
*/
class TaskOverlayHelper(val task: Task, val overlay: TaskOverlayFactory.TaskOverlay<*>) {
+ private val recentsCoroutineScope: CoroutineScope = RecentsDependencies.get()
+ private val dispatcherProvider: DispatcherProvider = RecentsDependencies.get()
private lateinit var overlayInitializedScope: CoroutineScope
private var uiState: TaskOverlayUiState = Disabled
@@ -101,7 +105,9 @@
}
fun destroy() {
- overlayInitializedScope.cancel()
+ recentsCoroutineScope.launch(dispatcherProvider.background) {
+ overlayInitializedScope.cancel("TaskOverlay being destroyed")
+ }
uiState = Disabled
overlay.snapshotView.removeOnLayoutChangeListener(snapshotLayoutChangeListener)
reset()
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3b46367..15dbcc7 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -25,11 +25,11 @@
import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.clampToProgress;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
@@ -179,6 +179,7 @@
import com.android.launcher3.util.TranslateEdgeEffect;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
+import com.android.launcher3.util.coroutines.DispatcherProvider;
import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewCommandHelper;
@@ -238,6 +239,8 @@
import kotlin.Unit;
+import kotlinx.coroutines.CoroutineScope;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -871,7 +874,11 @@
recentsDependencies.inject(RecentTasksRepository.class),
recentsDependencies.inject(RecentsViewData.class)
);
- mHelper = new RecentsViewModelHelper(mRecentsViewModel);
+ mHelper = new RecentsViewModelHelper(
+ mRecentsViewModel,
+ recentsDependencies.inject(CoroutineScope.class),
+ recentsDependencies.inject(DispatcherProvider.class)
+ );
recentsDependencies.provide(RecentsRotationStateRepository.class,
() -> new RecentsRotationStateRepositoryImpl(mOrientationState));
@@ -1208,9 +1215,6 @@
if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
}
- if (enableRefactorTaskThumbnail()) {
- mHelper.onAttachedToWindow();
- }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
index 3616fbb..87771c6 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt
@@ -16,28 +16,24 @@
package com.android.quickstep.views
+import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.ViewUtils
import com.android.quickstep.recents.viewmodel.RecentsViewModel
import com.android.systemui.shared.recents.model.ThumbnailData
-import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
/** Helper for [RecentsView] to interact with the [RecentsViewModel]. */
-class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) {
- private lateinit var viewAttachedScope: CoroutineScope
-
- fun onAttachedToWindow() {
- viewAttachedScope =
- CoroutineScope(SupervisorJob() + Dispatchers.Default + CoroutineName("RecentsView"))
- }
-
+class RecentsViewModelHelper(
+ private val recentsViewModel: RecentsViewModel,
+ private val recentsCoroutineScope: CoroutineScope,
+ private val dispatcherProvider: DispatcherProvider,
+) {
fun onDetachedFromWindow() {
- viewAttachedScope.cancel("RecentsView detaching from window")
+ recentsCoroutineScope.cancel("RecentsView detaching from window")
}
fun switchToScreenshot(
@@ -48,7 +44,7 @@
// Update recentsViewModel and apply the thumbnailOverride ASAP, before waiting inside
// viewAttachedScope.
recentsViewModel.setRunningTaskShowScreenshot(true)
- viewAttachedScope.launch {
+ recentsCoroutineScope.launch(dispatcherProvider.main) {
recentsViewModel.waitForRunningTaskShowScreenshotToUpdate()
recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails)
withContext(Dispatchers.Main) { ViewUtils.postFrameDrawn(taskView, onFinishRunnable) }