Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index b1a6202..e31f462 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -124,23 +124,15 @@
     </LinearLayout>
 
     <!-- Unused. Included only for compatibility with parent class. -->
-    <LinearLayout
-        android:id="@+id/group_action_buttons"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/overview_actions_height"
+    <Button
+        android:id="@+id/action_save_app_pair"
+        style="@style/GoOverviewActionButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
         android:layout_gravity="top|center_horizontal"
-        android:orientation="horizontal"
-        android:visibility="gone">
-
-        <Button
-            android:id="@+id/action_save_app_pair"
-            style="@style/GoOverviewActionButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:drawableStart="@drawable/ic_save_app_pair_up_down"
-            android:text="@string/action_save_app_pair"
-            android:theme="@style/ThemeControlHighlightWorkspaceColor" />
-
-    </LinearLayout>
+        android:drawableStart="@drawable/ic_save_app_pair_up_down"
+        android:text="@string/action_save_app_pair"
+        android:theme="@style/ThemeControlHighlightWorkspaceColor"
+        android:visibility="gone" />
 
 </com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 7aaf744..fcd2e54 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -47,22 +47,16 @@
 
     </LinearLayout>
 
-    <LinearLayout
-        android:id="@+id/group_action_buttons"
+    <!-- Currently, the only "group action button" is this save app pair button. If more are added,
+    a new LinearLayout may be needed to contain them, but beware of increased memory usage. -->
+    <Button
+        android:id="@+id/action_save_app_pair"
+        style="@style/OverviewActionButton"
         android:layout_width="wrap_content"
-        android:layout_height="@dimen/overview_actions_height"
+        android:layout_height="wrap_content"
+        android:text="@string/action_save_app_pair"
+        android:theme="@style/ThemeControlHighlightWorkspaceColor"
         android:layout_gravity="bottom|center_horizontal"
-        android:orientation="horizontal"
-        android:visibility="gone">
-
-        <Button
-            android:id="@+id/action_save_app_pair"
-            style="@style/OverviewActionButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/action_save_app_pair"
-            android:theme="@style/ThemeControlHighlightWorkspaceColor" />
-
-    </LinearLayout>
+        android:visibility="gone" />
 
 </com.android.quickstep.views.OverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
new file mode 100644
index 0000000..c1eef0b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.flow.Flow
+
+interface RecentTasksRepository {
+    /** Gets all the recent tasks, refreshing from data sources if [forceRefresh] is true. */
+    fun getAllTaskData(forceRefresh: Boolean = false): Flow<List<Task>>
+
+    /**
+     * Gets the data associated with a task that has id [taskId]. Flow will settle on null if the
+     * task was not found.
+     */
+    fun getTaskDataById(taskId: Int): Flow<Task?>
+
+    /**
+     * Sets the tasks that are visible, indicating that properties relating to visuals need to be
+     * populated e.g. icons/thumbnails etc.
+     */
+    fun setVisibleTasks(visibleTaskIdList: List<Int>)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index ad8ae20..b21a1b4 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -38,7 +38,7 @@
     private val recentsModel: RecentTasksDataSource,
     private val taskThumbnailDataSource: TaskThumbnailDataSource,
     private val taskIconCache: TaskIconCache,
-) {
+) : RecentTasksRepository {
     private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
     private val _taskData =
         groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
@@ -53,17 +53,17 @@
             tasks
         }
 
-    fun getAllTaskData(forceRefresh: Boolean = false): Flow<List<Task>> {
+    override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
         if (forceRefresh) {
             recentsModel.getTasks { groupedTaskData.value = it }
         }
         return taskData
     }
 
-    fun getTaskDataById(taskId: Int): Flow<Task?> =
+    override fun getTaskDataById(taskId: Int): Flow<Task?> =
         taskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
 
-    fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+    override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
         this.visibleTaskIds.value = visibleTaskIdList.toSet()
     }
 
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
index 0843ae3..40f9b28 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -16,11 +16,19 @@
 
 package com.android.quickstep.task.thumbnail
 
-import com.android.systemui.shared.recents.model.Task
+import android.graphics.Bitmap
+import android.graphics.Rect
+import androidx.annotation.ColorInt
 
 sealed class TaskThumbnailUiState {
     data object Uninitialized : TaskThumbnailUiState()
     data object LiveTile : TaskThumbnailUiState()
+    data class BackgroundOnly(@ColorInt val backgroundColor: Int) : TaskThumbnailUiState()
+    data class Snapshot(
+        val bitmap: Bitmap,
+        val drawnRect: Rect,
+        @ColorInt val backgroundColor: Int
+    ) : TaskThumbnailUiState()
 }
 
-data class TaskThumbnail(val task: Task, val isRunning: Boolean)
+data class TaskThumbnail(val taskId: Int, val isRunning: Boolean)
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 8762976..2836c89 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -19,15 +19,20 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.graphics.Canvas
+import android.graphics.Color
 import android.graphics.Outline
 import android.graphics.Paint
 import android.graphics.PorterDuff
 import android.graphics.PorterDuffXfermode
+import android.graphics.Rect
 import android.util.AttributeSet
 import android.view.View
 import android.view.ViewOutlineProvider
+import androidx.annotation.ColorInt
 import com.android.launcher3.Utilities
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
 import com.android.quickstep.util.TaskCornerRadius
 import com.android.quickstep.views.RecentsView
@@ -42,17 +47,26 @@
     //  to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
     //  This is using a lazy for now because the dependencies cannot be obtained without DI.
     val viewModel by lazy {
-        TaskThumbnailViewModel(
+        val recentsView =
             RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
                 .getOverviewPanel<RecentsView<*, *>>()
-                .mRecentsViewData,
-            (parent as TaskView).taskViewData
+        TaskThumbnailViewModel(
+            recentsView.mRecentsViewData,
+            (parent as TaskView).taskViewData,
+            recentsView.mTasksRepository,
         )
     }
 
     private var uiState: TaskThumbnailUiState = Uninitialized
     private var inheritedScale: Float = 1f
 
+    private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+    private val _measuredBounds = Rect()
+    private val measuredBounds: Rect
+        get() {
+            _measuredBounds.set(0, 0, measuredWidth, measuredHeight)
+            return _measuredBounds
+        }
     private var cornerRadius: Float = TaskCornerRadius.get(context)
     private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
 
@@ -85,24 +99,25 @@
         outlineProvider =
             object : ViewOutlineProvider() {
                 override fun getOutline(view: View, outline: Outline) {
-                    outline.setRoundRect(
-                        0,
-                        0,
-                        view.measuredWidth,
-                        view.measuredHeight,
-                        getCurrentCornerRadius()
-                    )
+                    outline.setRoundRect(measuredBounds, getCurrentCornerRadius())
                 }
             }
     }
 
     override fun onDraw(canvas: Canvas) {
-        when (uiState) {
-            is Uninitialized -> {}
+        when (val uiStateVal = uiState) {
+            is Uninitialized -> drawBackgroundOnly(canvas, Color.BLACK)
             is LiveTile -> drawTransparentUiState(canvas)
+            is Snapshot -> drawSnapshotState(canvas, uiStateVal)
+            is BackgroundOnly -> drawBackgroundOnly(canvas, uiStateVal.backgroundColor)
         }
     }
 
+    private fun drawBackgroundOnly(canvas: Canvas, @ColorInt backgroundColor: Int) {
+        backgroundPaint.color = backgroundColor
+        canvas.drawRect(measuredBounds, backgroundPaint)
+    }
+
     override fun onConfigurationChanged(newConfig: Configuration?) {
         super.onConfigurationChanged(newConfig)
 
@@ -112,7 +127,12 @@
     }
 
     private fun drawTransparentUiState(canvas: Canvas) {
-        canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+        canvas.drawRect(measuredBounds, CLEAR_PAINT)
+    }
+
+    private fun drawSnapshotState(canvas: Canvas, snapshot: Snapshot) {
+        drawBackgroundOnly(canvas, snapshot.backgroundColor)
+        canvas.drawBitmap(snapshot.bitmap, snapshot.drawnRect, measuredBounds, null)
     }
 
     private fun getCurrentCornerRadius() =
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
index 71bc865..4511ea7 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
@@ -16,32 +16,76 @@
 
 package com.android.quickstep.task.thumbnail
 
+import android.annotation.ColorInt
+import android.graphics.Rect
+import androidx.core.graphics.ColorUtils
+import com.android.quickstep.recents.data.RecentTasksRepository
 import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
 import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
 import com.android.quickstep.task.viewmodel.TaskViewData
+import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 
-class TaskThumbnailViewModel(recentsViewData: RecentsViewData, taskViewData: TaskViewData) {
-    private val task = MutableStateFlow<TaskThumbnail?>(null)
+@OptIn(ExperimentalCoroutinesApi::class)
+class TaskThumbnailViewModel(
+    recentsViewData: RecentsViewData,
+    taskViewData: TaskViewData,
+    private val tasksRepository: RecentTasksRepository,
+) {
+    private val task = MutableStateFlow<Flow<Task?>>(flowOf(null))
+    private var boundTaskIsRunning = false
 
     val recentsFullscreenProgress = recentsViewData.fullscreenProgress
     val inheritedScale =
         combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
             recentsScale * taskScale
         }
-    val uiState =
-        task.map { taskVal ->
-            when {
-                taskVal == null -> Uninitialized
-                taskVal.isRunning -> LiveTile
-                else -> Uninitialized
+    val uiState: Flow<TaskThumbnailUiState> =
+        task
+            .flatMapLatest { taskFlow ->
+                taskFlow.map { taskVal ->
+                    when {
+                        taskVal == null -> Uninitialized
+                        boundTaskIsRunning -> LiveTile
+                        isBackgroundOnly(taskVal) ->
+                            BackgroundOnly(taskVal.colorBackground.removeAlpha())
+                        isSnapshotState(taskVal) -> {
+                            val bitmap = taskVal.thumbnail?.thumbnail!!
+                            Snapshot(
+                                bitmap,
+                                Rect(0, 0, bitmap.width, bitmap.height),
+                                taskVal.colorBackground.removeAlpha()
+                            )
+                        }
+                        else -> Uninitialized
+                    }
+                }
             }
-        }
+            .distinctUntilChanged()
 
-    fun bind(task: TaskThumbnail) {
-        this.task.value = task
+    fun bind(taskThumbnail: TaskThumbnail) {
+        boundTaskIsRunning = taskThumbnail.isRunning
+        task.value = tasksRepository.getTaskDataById(taskThumbnail.taskId)
     }
+
+    private fun isBackgroundOnly(task: Task): Boolean = task.isLocked || task.thumbnail == null
+
+    private fun isSnapshotState(task: Task): Boolean {
+        val thumbnailPresent = task.thumbnail?.thumbnail != null
+        val taskLocked = task.isLocked
+
+        return thumbnailPresent && !taskLocked
+    }
+
+    @ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
 }
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 83a2ceb..d729bdc 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -110,9 +110,11 @@
 
     /** Container for the action buttons below a focused, non-split Overview tile. */
     protected LinearLayout mActionButtons;
-    /** Container for the action buttons below a focused, split Overview tile. */
-    protected LinearLayout mGroupActionButtons;
     private Button mSplitButton;
+    /**
+     * The "save app pair" button. Currently this is the only button that is not contained in
+     * mActionButtons, since it is the sole button that appears for a grouped task.
+     */
     private Button mSaveAppPairButton;
 
     @ActionsHiddenFlags
@@ -150,15 +152,16 @@
         super.onFinishInflate();
         // Initialize 2 view containers: one for single tasks, one for grouped tasks.
         // These will take up the same space on the screen and alternate visibility as needed.
+        // Currently, the only grouped task action is "save app pairs".
         mActionButtons = findViewById(R.id.action_buttons);
-        mGroupActionButtons = findViewById(R.id.group_action_buttons);
-        // Initialize a list to hold alphas for mActionButtons and mGroupActionButtons.
+        mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
+        // Initialize a list to hold alphas for mActionButtons and any group action buttons.
         mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
         mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
-                new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
+                new MultiValueAlpha(mSaveAppPairButton, NUM_ALPHAS);
         Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
-        // To control alpha simultaneously on mActionButtons and mGroupActionButtons, we set up an
-        // AnimatedFloat for each alpha property.
+        // To control alpha simultaneously on mActionButtons and any group action buttons, we set up
+        // an AnimatedFloat for each alpha property.
         for (int i = 0; i < NUM_ALPHAS; i++) {
             final int index = i;
             mAlphaProperties[index] = new AnimatedFloat(() -> {
@@ -175,7 +178,6 @@
         screenshotButton.setOnClickListener(this);
         mSplitButton = findViewById(R.id.action_split);
         mSplitButton.setOnClickListener(this);
-        mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
         mSaveAppPairButton.setOnClickListener(this);
     }
 
@@ -336,7 +338,7 @@
      */
     public boolean areActionsButtonsVisible() {
         return mActionButtons.getVisibility() == View.VISIBLE
-                || mGroupActionButtons.getVisibility() == View.VISIBLE;
+                || mSaveAppPairButton.getVisibility() == View.VISIBLE;
     }
 
     /**
@@ -350,11 +352,11 @@
     /** Updates vertical margins for different navigation mode or configuration changes. */
     public void updateVerticalMargin(NavigationMode mode) {
         updateActionBarPosition(mActionButtons);
-        updateActionBarPosition(mGroupActionButtons);
+        updateActionBarPosition(mSaveAppPairButton);
     }
 
     /** Positions actions buttons according to device settings and insets. */
-    private void updateActionBarPosition(LinearLayout actionBar) {
+    private void updateActionBarPosition(View actionBar) {
         if (mDp == null) {
             return;
         }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5eee64d..4804e56 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -188,6 +188,7 @@
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.ViewUtils;
 import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.recents.data.TasksRepository;
 import com.android.quickstep.recents.viewmodel.RecentsViewData;
 import com.android.quickstep.util.ActiveGestureErrorDetector;
 import com.android.quickstep.util.ActiveGestureLog;
@@ -305,6 +306,7 @@
     public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
     public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
             VibrationConstants.EFFECT_TEXTURE_TICK;
+    public static final int UNBOUND_TASK_VIEW_ID = -1;
 
     /**
      * Can be used to tint the color of the RecentsView to simulate a scrim that can views
@@ -456,6 +458,7 @@
     private static final float FOREGROUND_SCRIM_TINT = 0.32f;
 
     public final RecentsViewData mRecentsViewData = new RecentsViewData();
+    public final TasksRepository mTasksRepository;
 
     protected final RecentsOrientedState mOrientationState;
     protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
@@ -800,6 +803,12 @@
                 .getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
         mModel = RecentsModel.INSTANCE.get(context);
         mIdp = InvariantDeviceProfile.INSTANCE.get(context);
+        if (enableRefactorTaskThumbnail()) {
+            mTasksRepository = new TasksRepository(
+                    mModel, mModel.getThumbnailCache(), mModel.getIconCache());
+        } else {
+            mTasksRepository = null;
+        }
 
         mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
                 .inflate(R.layout.overview_clear_all_button, this, false);
@@ -1165,7 +1174,6 @@
             } else {
                 mTaskViewPool.recycle(taskView);
             }
-            taskView.setTaskViewId(-1);
             mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
         }
     }
@@ -2362,6 +2370,8 @@
             upper = Math.min(centerPageIndex + 2, numChildren - 1);
         }
 
+        List<Integer> visibleTaskIds = new ArrayList<>();
+
         // Update the task data for the in/visible children
         for (int i = 0; i < getTaskViewCount(); i++) {
             TaskView taskView = requireTaskViewAt(i);
@@ -2381,6 +2391,10 @@
                 List<Task> tasksToUpdate = containers.stream()
                         .map(TaskContainer::getTask)
                         .collect(Collectors.toCollection(ArrayList::new));
+                if (enableRefactorTaskThumbnail()) {
+                    visibleTaskIds.addAll(
+                            tasksToUpdate.stream().map((task) -> task.key.id).toList());
+                }
                 if (mTmpRunningTasks != null) {
                     for (Task t : mTmpRunningTasks) {
                         // Skip loading if this is the task that we are animating into
@@ -2416,6 +2430,9 @@
                 }
             }
         }
+        if (enableRefactorTaskThumbnail()) {
+            mTasksRepository.setVisibleTasks(visibleTaskIds);
+        }
     }
 
     /**
@@ -2602,6 +2619,9 @@
         if (!mModel.isTaskListValid(mTaskListChangeId)) {
             mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
                     .getFilter(mFilterState.getPackageNameToFilter()));
+            if (enableRefactorTaskThumbnail()) {
+                mTasksRepository.getAllTaskData(/* forceRefresh = */ true);
+            }
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 05b9d40..4045ad7 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -93,6 +93,7 @@
 import com.android.quickstep.util.RecentsOrientedState
 import com.android.quickstep.util.TaskCornerRadius
 import com.android.quickstep.util.TaskRemovedDuringLaunchListener
+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
 import com.android.systemui.shared.system.ActivityManagerWrapper
@@ -235,7 +236,7 @@
         protected set
     lateinit var orientedState: RecentsOrientedState
 
-    var taskViewId = -1
+    var taskViewId = UNBOUND_TASK_VIEW_ID
     var isEndQuickSwitchCuj = false
 
     // Various animation progress variables.
@@ -502,7 +503,6 @@
         resetPersistentViewTransforms()
         // Clear any references to the thumbnail (it will be re-read either from the cache or the
         // system on next bind)
-        // TODO(b/334825222): Implement thumbnail/snapshot for the new [TaskThumbnailView].
         if (enableRefactorTaskThumbnail()) {
             notifyIsRunningTaskUpdated()
         } else {
@@ -511,6 +511,7 @@
         setOverlayEnabled(false)
         onTaskListVisibilityChanged(false)
         borderEnabled = false
+        taskViewId = UNBOUND_TASK_VIEW_ID
     }
 
     // TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
@@ -780,22 +781,19 @@
         val recentsModel = RecentsModel.INSTANCE.get(context)
         // These calls are no-ops if the data is already loaded, try and load the high
         // resolution thumbnail if the state permits
-        if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
-            if (!enableRefactorTaskThumbnail()) {
-                // TODO(b/334825222) add thumbnail state
-                taskContainers.forEach {
-                    if (visible) {
-                        recentsModel.thumbnailCache
-                            .updateThumbnailInBackground(it.task) { thumbnailData ->
-                                it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData)
-                            }
-                            ?.also { request -> pendingThumbnailLoadRequests.add(request) }
-                    } else {
-                        it.thumbnailViewDeprecated.setThumbnail(null, null)
-                        // Reset the task thumbnail reference as well (it will be fetched from the
-                        // cache or reloaded next time we need it)
-                        it.task.thumbnail = null
-                    }
+        if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL) && !enableRefactorTaskThumbnail()) {
+            taskContainers.forEach {
+                if (visible) {
+                    recentsModel.thumbnailCache
+                        .updateThumbnailInBackground(it.task) { thumbnailData ->
+                            it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData)
+                        }
+                        ?.also { request -> pendingThumbnailLoadRequests.add(request) }
+                } else {
+                    it.thumbnailViewDeprecated.setThumbnail(null, null)
+                    // Reset the task thumbnail reference as well (it will be fetched from the
+                    // cache or reloaded next time we need it)
+                    it.task.thumbnail = null
                 }
             }
         }
@@ -861,7 +859,7 @@
 
     open fun refreshThumbnails(thumbnailDatas: HashMap<Int, ThumbnailData?>?) {
         if (enableRefactorTaskThumbnail()) {
-            // TODO(b/334825222) add thumbnail logic
+            // TODO(b/342560598) add thumbnail logic
             return
         }
 
@@ -1591,7 +1589,9 @@
         // TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
         //  so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
         fun bindThumbnailView() {
-            thumbnailView?.viewModel?.bind(TaskThumbnail(task, isRunningTask))
+            // TODO(b/343364498): Existing view has shouldShowScreenshot as an override as well but
+            //  this should be decided inside TaskThumbnailViewModel.
+            thumbnailView?.viewModel?.bind(TaskThumbnail(task.key.id, isRunningTask))
         }
     }
 
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
new file mode 100644
index 0000000..e160627
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeTasksRepository : RecentTasksRepository {
+    private var thumbnailDataMap: Map<Int, ThumbnailData> = emptyMap()
+    private var tasks: MutableStateFlow<List<Task>> = MutableStateFlow(emptyList())
+    private var visibleTasks: MutableStateFlow<List<Int>> = MutableStateFlow(emptyList())
+
+    override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> = tasks
+
+    override fun getTaskDataById(taskId: Int): Flow<Task?> =
+        getAllTaskData().map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+
+    override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+        visibleTasks.value = visibleTaskIdList
+        tasks.value = tasks.value.map { it.apply { thumbnail = thumbnailDataMap[it.key.id] } }
+    }
+
+    fun seedTasks(tasks: List<Task>) {
+        this.tasks.value = tasks
+    }
+
+    fun seedThumbnailData(thumbnailDataMap: Map<Int, ThumbnailData>) {
+        this.thumbnailDataMap = thumbnailDataMap
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
index efd7bec..3b8754c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -16,33 +16,51 @@
 
 package com.android.quickstep.task.thumbnail
 
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Rect
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.quickstep.recents.data.FakeTasksRepository
 import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
 import com.android.quickstep.task.viewmodel.TaskViewData
 import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class TaskThumbnailViewModelTest {
     private val recentsViewData = RecentsViewData()
     private val taskViewData = TaskViewData()
-    private val systemUnderTest = TaskThumbnailViewModel(recentsViewData, taskViewData)
+    private val tasksRepository = FakeTasksRepository()
+    private val systemUnderTest =
+        TaskThumbnailViewModel(recentsViewData, taskViewData, tasksRepository)
+
+    private val tasks = (0..5).map(::createTaskWithId)
 
     @Test
     fun initialStateIsUninitialized() = runTest {
-        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+        assertThat(systemUnderTest.uiState.first()).isEqualTo(Uninitialized)
     }
 
     @Test
     fun bindRunningTask_thenStateIs_LiveTile() = runTest {
-        val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
+        tasksRepository.seedTasks(tasks)
+        val taskThumbnail = TaskThumbnail(taskId = 1, isRunning = true)
         systemUnderTest.bind(taskThumbnail)
 
-        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+        assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
     }
 
     @Test
@@ -65,15 +83,96 @@
     }
 
     @Test
-    fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() = runTest {
-        // TODO(b/334825222): Change the expectation here when snapshot state is implemented
-        val task = Task()
-        val runningTask = TaskThumbnail(task, isRunning = true)
-        val stoppedTask = TaskThumbnail(task, isRunning = false)
-        systemUnderTest.bind(runningTask)
-        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+    fun bindRunningTaskThenStoppedTaskWithoutThumbnail_thenStateChangesToBackgroundOnly() =
+        runTest {
+            tasksRepository.seedTasks(tasks)
+            val runningTask = TaskThumbnail(taskId = 1, isRunning = true)
+            val stoppedTask = TaskThumbnail(taskId = 2, isRunning = false)
+            systemUnderTest.bind(runningTask)
+            assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
+
+            systemUnderTest.bind(stoppedTask)
+            assertThat(systemUnderTest.uiState.first())
+                .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+        }
+
+    @Test
+    fun bindStoppedTaskWithoutThumbnail_thenStateIs_BackgroundOnly_withAlphaRemoved() = runTest {
+        tasksRepository.seedTasks(tasks)
+        val stoppedTask = TaskThumbnail(taskId = 2, isRunning = false)
 
         systemUnderTest.bind(stoppedTask)
-        assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+        assertThat(systemUnderTest.uiState.first())
+            .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+    }
+
+    @Test
+    fun bindLockedTaskWithThumbnail_thenStateIs_BackgroundOnly() = runTest {
+        tasksRepository.seedThumbnailData(mapOf(2 to createThumbnailData()))
+        tasks[2].isLocked = true
+        tasksRepository.seedTasks(tasks)
+        val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+        systemUnderTest.bind(recentTask)
+        assertThat(systemUnderTest.uiState.first())
+            .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+    }
+
+    @Test
+    fun bindStoppedTaskWithThumbnail_thenStateIs_Snapshot_withAlphaRemoved() = runTest {
+        val expectedThumbnailData = createThumbnailData()
+        tasksRepository.seedThumbnailData(mapOf(2 to expectedThumbnailData))
+        tasksRepository.seedTasks(tasks)
+        tasksRepository.setVisibleTasks(listOf(2))
+        val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+        systemUnderTest.bind(recentTask)
+        assertThat(systemUnderTest.uiState.first())
+            .isEqualTo(
+                Snapshot(
+                    backgroundColor = Color.rgb(2, 2, 2),
+                    bitmap = expectedThumbnailData.thumbnail!!,
+                    drawnRect = Rect(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
+                )
+            )
+    }
+
+    @Test
+    fun bindNonVisibleStoppedTask_whenMadeVisible_thenStateIsSnapshot() = runTest {
+        val expectedThumbnailData = createThumbnailData()
+        tasksRepository.seedThumbnailData(mapOf(2 to expectedThumbnailData))
+        tasksRepository.seedTasks(tasks)
+        val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+        systemUnderTest.bind(recentTask)
+        assertThat(systemUnderTest.uiState.first())
+            .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+        tasksRepository.setVisibleTasks(listOf(2))
+        assertThat(systemUnderTest.uiState.first())
+            .isEqualTo(
+                Snapshot(
+                    backgroundColor = Color.rgb(2, 2, 2),
+                    bitmap = expectedThumbnailData.thumbnail!!,
+                    drawnRect = Rect(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
+                )
+            )
+    }
+
+    private fun createTaskWithId(taskId: Int) =
+        Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+            colorBackground = Color.argb(taskId, taskId, taskId, taskId)
+        }
+
+    private fun createThumbnailData(): ThumbnailData {
+        val bitmap = mock<Bitmap>()
+        whenever(bitmap.width).thenReturn(THUMBNAIL_WIDTH)
+        whenever(bitmap.height).thenReturn(THUMBNAIL_HEIGHT)
+
+        return ThumbnailData(thumbnail = bitmap)
+    }
+
+    companion object {
+        const val THUMBNAIL_WIDTH = 100
+        const val THUMBNAIL_HEIGHT = 200
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index bfd7bdb..6be082a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -129,8 +129,6 @@
                     overview.getCurrentTask()
                             .tapMenu()
                             .hasMenuItem("Save app pair"));
-        } else {
-            overview.getOverviewGroupActions().assertHasAction("Save app pair");
         }
     }
 
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 1c41ded..d43402b 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -221,24 +221,7 @@
     public void testDragAppIconToMultipleWorkspaceCells() throws Exception {
         long startTime, endTime, elapsedTime;
         Point[] targets = TestUtil.getCornersAndCenterPositions(mLauncher);
-
-        for (Point target : targets) {
-            startTime = SystemClock.uptimeMillis();
-            final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
-            allApps.freeze();
-            try {
-                allApps.getAppIcon(TEST_APP_NAME).dragToWorkspace(target.x, target.y);
-            } finally {
-                allApps.unfreeze();
-            }
-            // Reset the workspace for the next shortcut creation.
-            reinitializeLauncherData(true);
-            endTime = SystemClock.uptimeMillis();
-            elapsedTime = endTime - startTime;
-            Log.d("testDragAppIconToWorkspaceCellTime",
-                    "Milliseconds taken to drag app icon to workspace cell: " + elapsedTime);
-        }
-
+        reinitializeLauncherData(true);
         // test to move a shortcut to other cell.
         final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(TEST_APP_NAME);
         for (Point target : targets) {
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 2e3944d..e10893e 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -359,21 +359,6 @@
     }
 
     /**
-     * Gets Overview Actions specific to grouped tasks.
-     *
-     * @return The Overview group actions bar
-     */
-    @NonNull
-    public OverviewActions getOverviewGroupActions() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to get overview group actions")) {
-            verifyActiveContainer();
-            UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
-            return new OverviewActions(groupActions, mLauncher);
-        }
-    }
-
-    /**
      * Returns if clear all button is visible.
      */
     public boolean isClearAllVisible() {
@@ -469,13 +454,13 @@
 
             if (isActionsViewVisible()) {
                 if (task.isTaskSplit()) {
-                    mLauncher.waitForOverviewObject("group_action_buttons");
+                    mLauncher.waitForOverviewObject("action_save_app_pair");
                 } else {
                     mLauncher.waitForOverviewObject("action_buttons");
                 }
             } else {
                 mLauncher.waitUntilOverviewObjectGone("action_buttons");
-                mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
+                mLauncher.waitUntilOverviewObjectGone("action_save_app_pair");
             }
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 68b0a36..d85f630 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -711,7 +711,7 @@
             final LogEventChecker eventChecker = mEventChecker;
             mEventChecker = null;
             if (checkEvents) {
-                final String eventMismatch = eventChecker.verify(0, false);
+                final String eventMismatch = eventChecker.verify(0);
                 if (eventMismatch != null) {
                     message = message + ";\n" + eventMismatch;
                 }
@@ -2408,7 +2408,7 @@
             if (mEventChecker != null) {
                 mEventChecker = null;
                 if (mCheckEventsForSuccessfulGestures) {
-                    final String message = eventChecker.verify(WAIT_TIME_MS, true);
+                    final String message = eventChecker.verify(WAIT_TIME_MS);
                     if (message != null) {
                         dumpDiagnostics(message);
                         checkForAnomaly();
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 672c6e0..055a357 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -15,10 +15,6 @@
  */
 package com.android.launcher3.tapl;
 
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_MAIN;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_PILFER;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_TIS;
-
 import android.os.SystemClock;
 
 import com.android.launcher3.testing.shared.TestProtocol;
@@ -87,25 +83,11 @@
         mLauncher.getTestInfo(TestProtocol.REQUEST_STOP_EVENT_LOGGING);
     }
 
-    String verify(long waitForExpectedCountMs, boolean successfulGesture) {
+    String verify(long waitForExpectedCountMs) {
         final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
         if (actualEvents == null) return "null event sequences because launcher likely died";
 
-        final String lowLevelDiags = lowLevelMismatchDiagnostics(actualEvents);
-        // If we have a sequence mismatch for a successful gesture, we want to provide all low-level
-        // details.
-        if (successfulGesture) {
-            return lowLevelDiags;
-        }
-
-        final String sequenceMismatchInEnglish = highLevelMismatchDiagnostics(actualEvents);
-
-        if (sequenceMismatchInEnglish != null) {
-            LauncherInstrumentation.log(lowLevelDiags);
-            return "Hint: " + sequenceMismatchInEnglish;
-        } else {
-            return lowLevelDiags;
-        }
+        return lowLevelMismatchDiagnostics(actualEvents);
     }
 
     private String lowLevelMismatchDiagnostics(ListMap<String> actualEvents) {
@@ -140,42 +122,6 @@
         return hasMismatches ? "Mismatching events: " + sb.toString() : null;
     }
 
-    private String highLevelMismatchDiagnostics(ListMap<String> actualEvents) {
-        if (!mExpectedEvents.getNonNull(SEQUENCE_TIS).isEmpty()
-                && actualEvents.getNonNull(SEQUENCE_TIS).isEmpty()) {
-            return "TouchInteractionService didn't receive any of the touch events sent by the "
-                    + "test";
-        }
-        if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_TIS),
-                actualEvents.getNonNull(SEQUENCE_TIS)) != -1) {
-            // If TIS has a mismatch that we can't convert to high-level diags, don't convert
-            // other sequences either.
-            return null;
-        }
-
-        if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).size() == 1
-                && actualEvents.getNonNull(SEQUENCE_PILFER).isEmpty()) {
-            return "Launcher didn't detect the navigation gesture sent by the test";
-        }
-        if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).isEmpty()
-                && actualEvents.getNonNull(SEQUENCE_PILFER).size() == 1) {
-            return "Launcher detected a navigation gesture, but the test didn't send one";
-        }
-        if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_PILFER),
-                actualEvents.getNonNull(SEQUENCE_PILFER)) != -1) {
-            // If Pilfer has a mismatch that we can't convert to high-level diags, don't analyze
-            // other sequences.
-            return null;
-        }
-
-        if (!mExpectedEvents.getNonNull(SEQUENCE_MAIN).isEmpty()
-                && actualEvents.getNonNull(SEQUENCE_MAIN).isEmpty()) {
-            return "None of the touch or keyboard events sent by the test was received by "
-                    + "Launcher's main thread";
-        }
-        return null;
-    }
-
     // If the list of actual events matches the list of expected events, returns -1, otherwise
     // the position of the mismatch.
     private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index 486a63b..d7c40a0 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -17,7 +17,6 @@
 package com.android.launcher3.tapl;
 
 import androidx.annotation.NonNull;
-import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.UiObject2;
 
 /**
@@ -111,12 +110,4 @@
             }
         }
     }
-
-    /** Asserts that an item matching the given string is present in the overview actions. */
-    public void assertHasAction(String text) {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to check if the action [" + text + "] is present")) {
-            mLauncher.waitForObjectInContainer(mOverviewActions, By.text(text));
-        }
-    }
 }