Merge "Removing some redundant resource definitions" into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 25593e6..b3b1c82 100644
--- a/Android.mk
+++ b/Android.mk
@@ -16,6 +16,15 @@
 
 LOCAL_PATH := $(call my-dir)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := libPluginCore
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := libs/plugin_core.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_SDK_VERSION := current
+include $(BUILD_PREBUILT)
+
 #
 # Build rule for plugin lib (needed to write a plugin).
 #
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index d7cba39..29e650c 100644
--- a/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/go/quickstep/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -28,6 +28,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.views.IconRecentsView;
 
 import java.util.ArrayList;
 
@@ -35,7 +36,7 @@
  * Provides recents-related {@link UiFactory} logic and classes.
  */
 public abstract class RecentsUiFactory {
-    
+
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = true;
     // Scale recents takes before animating in
     private static final float RECENTS_PREPARE_SCALE = 1.33f;
@@ -87,7 +88,10 @@
      *
      * @param launcher the launcher activity
      */
-    public static void resetOverview(Launcher launcher) {}
+    public static void resetOverview(Launcher launcher) {
+        IconRecentsView recentsView = launcher.getOverviewPanel();
+        recentsView.setTransitionedFromApp(false);
+    }
 
     /**
      * Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
diff --git a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index defed84..051c80f 100644
--- a/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/go/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
 import com.android.quickstep.views.IconRecentsView;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@@ -100,6 +101,10 @@
             return anim;
         }
 
+        RemoteAnimationTargetSet targetSet =
+                new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING);
+        mRecentsView.setTransitionedFromApp(!targetSet.isAnimatingHome());
+
         RemoteAnimationTargetCompat recentsTarget = null;
         RemoteAnimationTargetCompat closingAppTarget = null;
 
diff --git a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index d9873fe..379cc10 100644
--- a/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/go/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -96,7 +96,7 @@
             if (recents == null) {
                 return false;
             }
-            //TODO: Launch last running task or go to home.
+            recents.handleOverviewCommand();
             return true;
         }
     }
@@ -146,7 +146,7 @@
         protected boolean handleCommand(long elapsedTime) {
             IconRecentsView recents = mHelper.getVisibleRecentsView();
             if (recents != null) {
-                //TODO: Launch next task in icon recents.
+                recents.handleOverviewCommand();
                 return true;
             } else if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
                 // The user tried to launch back into overview too quickly, either after
diff --git a/go/quickstep/src/com/android/quickstep/TaskInputController.java b/go/quickstep/src/com/android/quickstep/TaskActionController.java
similarity index 74%
rename from go/quickstep/src/com/android/quickstep/TaskInputController.java
rename to go/quickstep/src/com/android/quickstep/TaskActionController.java
index 10de5c8..b2d495b 100644
--- a/go/quickstep/src/com/android/quickstep/TaskInputController.java
+++ b/go/quickstep/src/com/android/quickstep/TaskActionController.java
@@ -23,24 +23,25 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 /**
- * Controller responsible for task logic that occurs on various input to the recents view.
+ * Controller that provides logic for task-related commands on recents and updating the model/view
+ * as appropriate.
  */
-public final class TaskInputController {
+public final class TaskActionController {
 
     private final TaskListLoader mLoader;
     private final TaskAdapter mAdapter;
 
-    public TaskInputController(TaskListLoader loader,TaskAdapter adapter) {
+    public TaskActionController(TaskListLoader loader, TaskAdapter adapter) {
         mLoader = loader;
         mAdapter = adapter;
     }
 
     /**
-     * Logic that occurs when a task view is tapped. Launches the respective task.
+     * Launch the task associated with the task holder, animating into the app.
      *
-     * @param viewHolder the task view holder that has been tapped
+     * @param viewHolder the task view holder to launch
      */
-    public void onTaskClicked(TaskHolder viewHolder) {
+    public void launchTask(TaskHolder viewHolder) {
         TaskItemView itemView = (TaskItemView) (viewHolder.itemView);
         View v = itemView.getThumbnailView();
         int left = 0;
@@ -53,7 +54,12 @@
                 opts, null /* resultCallback */, null /* resultCallbackHandler */);
     }
 
-    public void onTaskSwiped(TaskHolder viewHolder) {
+    /**
+     * Removes the task holder and the task, updating the model and the view.
+     *
+     * @param viewHolder the task view holder to remove
+     */
+    public void removeTask(TaskHolder viewHolder) {
         int position = viewHolder.getAdapterPosition();
         Task task = viewHolder.getTask();
         ActivityManagerWrapper.getInstance().removeTask(task.key.id);
@@ -62,9 +68,9 @@
     }
 
     /**
-     * Logic that occurs when clear all is triggered.
+     * Clears all tasks and updates the model and view.
      */
-    public void onClearAllClicked(View view) {
+    public void clearAllTasks() {
         // TODO: Play an animation so transition is more natural.
         int count = mAdapter.getItemCount();
         ActivityManagerWrapper.getInstance().removeAllRecentTasks();
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index 9a2c0f8..e56cc51 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -39,14 +39,14 @@
     private static final String TAG = "TaskAdapter";
     private final TaskListLoader mLoader;
     private final ArrayMap<Integer, TaskItemView> mTaskIdToViewMap = new ArrayMap<>();
-    private TaskInputController mInputController;
+    private TaskActionController mTaskActionController;
 
     public TaskAdapter(@NonNull TaskListLoader loader) {
         mLoader = loader;
     }
 
-    public void setInputController(TaskInputController inputController) {
-        mInputController = inputController;
+    public void setActionController(TaskActionController taskActionController) {
+        mTaskActionController = taskActionController;
     }
 
     /**
@@ -64,7 +64,7 @@
         TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
                 .inflate(R.layout.task_item_view, parent, false);
         TaskHolder holder = new TaskHolder(itemView);
-        itemView.setOnClickListener(view -> mInputController.onTaskClicked(holder));
+        itemView.setOnClickListener(view -> mTaskActionController.launchTask(holder));
         return holder;
     }
 
diff --git a/go/quickstep/src/com/android/quickstep/TaskHolder.java b/go/quickstep/src/com/android/quickstep/TaskHolder.java
index 8d5e4d5..a89229f 100644
--- a/go/quickstep/src/com/android/quickstep/TaskHolder.java
+++ b/go/quickstep/src/com/android/quickstep/TaskHolder.java
@@ -25,7 +25,7 @@
  * A recycler view holder that holds the task view and binds {@link Task} content (app title, icon,
  * etc.) to the view.
  */
-final class TaskHolder extends ViewHolder {
+public final class TaskHolder extends ViewHolder {
 
     private final TaskItemView mTaskItemView;
     private Task mTask;
diff --git a/go/quickstep/src/com/android/quickstep/TaskSwipeCallback.java b/go/quickstep/src/com/android/quickstep/TaskSwipeCallback.java
index 2a53917..98407d8 100644
--- a/go/quickstep/src/com/android/quickstep/TaskSwipeCallback.java
+++ b/go/quickstep/src/com/android/quickstep/TaskSwipeCallback.java
@@ -26,11 +26,11 @@
  */
 public final class TaskSwipeCallback extends ItemTouchHelper.SimpleCallback {
 
-    private final TaskInputController mTaskInputController;
+    private final TaskActionController mTaskActionController;
 
-    public TaskSwipeCallback(TaskInputController inputController) {
+    public TaskSwipeCallback(TaskActionController taskActionController) {
         super(0 /* dragDirs */, RIGHT);
-        mTaskInputController = inputController;
+        mTaskActionController = taskActionController;
     }
 
     @Override
@@ -42,7 +42,7 @@
     @Override
     public void onSwiped(ViewHolder viewHolder, int direction) {
         if (direction == RIGHT) {
-            mTaskInputController.onTaskSwiped((TaskHolder) viewHolder);
+            mTaskActionController.removeTask((TaskHolder) viewHolder);
         }
     }
 }
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index 94f3e66..a1d62c2 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -35,8 +35,9 @@
 
 import com.android.launcher3.R;
 import com.android.quickstep.RecentsToActivityHelper;
+import com.android.quickstep.TaskActionController;
 import com.android.quickstep.TaskAdapter;
-import com.android.quickstep.TaskInputController;
+import com.android.quickstep.TaskHolder;
 import com.android.quickstep.TaskListLoader;
 import com.android.quickstep.TaskSwipeCallback;
 
@@ -74,20 +75,21 @@
     private final Context mContext;
     private final TaskListLoader mTaskLoader;
     private final TaskAdapter mTaskAdapter;
-    private final TaskInputController mTaskInputController;
+    private final TaskActionController mTaskActionController;
 
     private RecentsToActivityHelper mActivityHelper;
     private RecyclerView mTaskRecyclerView;
     private View mEmptyView;
     private View mContentView;
+    private boolean mTransitionedFromApp;
 
     public IconRecentsView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
         mTaskLoader = new TaskListLoader(mContext);
         mTaskAdapter = new TaskAdapter(mTaskLoader);
-        mTaskInputController = new TaskInputController(mTaskLoader, mTaskAdapter);
-        mTaskAdapter.setInputController(mTaskInputController);
+        mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
+        mTaskAdapter.setActionController(mTaskActionController);
     }
 
     @Override
@@ -99,7 +101,7 @@
             mTaskRecyclerView.setLayoutManager(
                     new LinearLayoutManager(mContext, VERTICAL, true /* reverseLayout */));
             ItemTouchHelper helper = new ItemTouchHelper(
-                    new TaskSwipeCallback(mTaskInputController));
+                    new TaskSwipeCallback(mTaskActionController));
             helper.attachToRecyclerView(mTaskRecyclerView);
 
             mEmptyView = findViewById(R.id.recent_task_empty_view);
@@ -117,7 +119,7 @@
             });
 
             View clearAllView = findViewById(R.id.clear_all_button);
-            clearAllView.setOnClickListener(mTaskInputController::onClearAllClicked);
+            clearAllView.setOnClickListener(v -> mTaskActionController.clearAllTasks());
         }
     }
 
@@ -147,6 +149,38 @@
     }
 
     /**
+     * Set whether we transitioned to recents from the most recent app.
+     *
+     * @param transitionedFromApp true if transitioned from the most recent app, false otherwise
+     */
+    public void setTransitionedFromApp(boolean transitionedFromApp) {
+        mTransitionedFromApp = transitionedFromApp;
+    }
+
+    /**
+     * Handles input from the overview button. Launch the most recent task unless we just came from
+     * the app. In that case, we launch the next most recent.
+     */
+    public void handleOverviewCommand() {
+        int childCount = mTaskRecyclerView.getChildCount();
+        if (childCount == 0) {
+            // Do nothing
+            return;
+        }
+        TaskHolder taskToLaunch;
+        if (mTransitionedFromApp && childCount > 1) {
+            // Launch the next most recent app
+            TaskItemView itemView = (TaskItemView) mTaskRecyclerView.getChildAt(1);
+            taskToLaunch = (TaskHolder) mTaskRecyclerView.getChildViewHolder(itemView);
+        } else {
+            // Launch the most recent app
+            TaskItemView itemView = (TaskItemView) mTaskRecyclerView.getChildAt(0);
+            taskToLaunch = (TaskHolder) mTaskRecyclerView.getChildViewHolder(itemView);
+        }
+        mTaskActionController.launchTask(taskToLaunch);
+    }
+
+    /**
      * Get the thumbnail view associated with a task for the purposes of animation.
      *
      * @param taskId task id of thumbnail view to get
diff --git a/libs/plugin_core.jar b/libs/plugin_core.jar
new file mode 100644
index 0000000..dd27f86
--- /dev/null
+++ b/libs/plugin_core.jar
Binary files differ
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 19e9cb4..446fb39 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -24,7 +24,6 @@
 import android.content.Intent;
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.AppUsageLimit;
-import android.content.res.Resources;
 import android.icu.text.MeasureFormat;
 import android.icu.text.MeasureFormat.FormatWidth;
 import android.icu.util.Measure;
@@ -54,7 +53,7 @@
     private final LauncherApps mLauncherApps;
 
     public interface InitializeCallback {
-        void call(float saturation, String contentDescription);
+        void call(String contentDescription);
     }
 
     private static final String TAG = DigitalWellBeingToast.class.getSimpleName();
@@ -84,7 +83,7 @@
 
         if (task.key.userId != UserHandle.myUserId()) {
             setVisibility(GONE);
-            callback.call(1, task.titleDescription);
+            callback.call(task.titleDescription);
             return;
         }
 
@@ -99,7 +98,7 @@
                     usageLimit != null ? usageLimit.getUsageRemaining() : -1;
 
             post(() -> {
-                if (appUsageLimitTimeMs < 0) {
+                if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
                     setVisibility(GONE);
                 } else {
                     setVisibility(VISIBLE);
@@ -108,10 +107,8 @@
                             R.drawable.hourglass_top : R.drawable.hourglass_bottom);
                 }
 
-                callback.call(
-                        appUsageLimitTimeMs >= 0 && appRemainingTimeMs <= 0 ? 0 : 1,
-                        getContentDescriptionForTask(
-                                task, appUsageLimitTimeMs, appRemainingTimeMs));
+                callback.call(getContentDescriptionForTask(
+                        task, appUsageLimitTimeMs, appRemainingTimeMs));
             });
         });
     }
@@ -180,12 +177,9 @@
     }
 
     private String getText(long remainingTime) {
-        final Resources resources = getResources();
-        return (remainingTime <= 0) ?
-                resources.getString(R.string.app_in_grayscale) :
-                resources.getString(
-                        R.string.time_left_for_app,
-                        getRoundedUpToMinuteReadableDuration(remainingTime));
+        return getResources().getString(
+                R.string.time_left_for_app,
+                getRoundedUpToMinuteReadableDuration(remainingTime));
     }
 
     public void openAppUsageSettings() {
@@ -209,7 +203,7 @@
 
     private String getContentDescriptionForTask(
             Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) {
-        return appUsageLimitTimeMs >= 0 ?
+        return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ?
                 getResources().getString(
                         R.string.task_contents_description_with_remaining_time,
                         task.titleDescription,
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 38aaac5..eb17e3e 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -322,9 +322,8 @@
                         }
                         mDigitalWellBeingToast.initialize(
                                 mTask,
-                                (saturation, contentDescription) -> {
+                                contentDescription -> {
                                     setContentDescription(contentDescription);
-                                    mSnapshotView.setSaturation(saturation);
                                     if (mDigitalWellBeingToast.getVisibility() == VISIBLE) {
                                         getRecentsView().onDigitalWellbeingToastShown();
                                     }
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index d120a2c..484f445 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -30,6 +30,5 @@
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacions recents"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>; <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
     <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1 minut"</string>
-    <string name="app_in_grayscale" msgid="1108706002158384887">"App en escala de grisos"</string>
     <string name="time_left_for_app" msgid="3111996412933644358">"temps restant avui: <xliff:g id="TIME">%1$s</xliff:g>"</string>
 </resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 068fd08..248a5da 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -30,6 +30,5 @@
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> : <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
     <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1 min"</string>
-    <string name="app_in_grayscale" msgid="1108706002158384887">"Application en nuances de gris"</string>
     <string name="time_left_for_app" msgid="3111996412933644358">"Il reste <xliff:g id="TIME">%1$s</xliff:g> aujourd\'hui"</string>
 </resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index ea5b0dc..338d9ba 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -30,6 +30,5 @@
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
     <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1 min"</string>
-    <string name="app_in_grayscale" msgid="1108706002158384887">"Appli en nuances de gris"</string>
     <string name="time_left_for_app" msgid="3111996412933644358">"Encore <xliff:g id="TIME">%1$s</xliff:g> aujourd\'hui"</string>
 </resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 5daa508..9543e79 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -30,6 +30,5 @@
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"최근 앱"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
     <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1분"</string>
-    <string name="app_in_grayscale" msgid="1108706002158384887">"앱이 그레이 스케일로 전환됨"</string>
     <string name="time_left_for_app" msgid="3111996412933644358">"오늘 <xliff:g id="TIME">%1$s</xliff:g> 남음"</string>
 </resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index ecc8f6c..19bfaa9 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -30,6 +30,5 @@
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"சமீபத்திய ஆப்ஸ்"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
     <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1 நி"</string>
-    <string name="app_in_grayscale" msgid="1108706002158384887">"கிரேஸ்கேலில் உள்ள ஆப்ஸ்"</string>
     <string name="time_left_for_app" msgid="3111996412933644358">"இன்று <xliff:g id="TIME">%1$s</xliff:g> மீதமுள்ளது"</string>
 </resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index f5e8fa8..81565a5 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -55,10 +55,6 @@
      escaped form of '<'). [CHAR LIMIT=15] -->
     <string name="shorter_duration_less_than_one_minute">&lt; 1 minute</string>
 
-    <!-- Annotation shown on an app card in Recents, telling that the app was switched to a
-    grayscale because it ran over its time limit [CHAR LIMIT=25] -->
-    <string name="app_in_grayscale">App in grayscale</string>
-
     <!-- Annotation shown on an app card in Recents, telling that the app has a usage limit set by
     the user, and a given time is left for it today [CHAR LIMIT=22] -->
     <string name="time_left_for_app"><xliff:g id="time" example="7 minutes">%1$s</xliff:g> left today</string>
diff --git a/tests/Android.mk b/tests/Android.mk
index bf5cb29..b9b703d 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -28,12 +28,12 @@
 ifneq (,$(wildcard frameworks/base))
 else
     LOCAL_STATIC_JAVA_LIBRARIES += libSharedSystemUI
-endif
 
-LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \
-  ../quickstep/src/com/android/quickstep/SwipeUpSetting.java \
-  ../src/com/android/launcher3/util/SecureSettingsObserver.java \
-  ../src/com/android/launcher3/TestProtocol.java \
+    LOCAL_SRC_FILES := $(call all-java-files-under, tapl) \
+        ../quickstep/src/com/android/quickstep/SwipeUpSetting.java \
+        ../src/com/android/launcher3/util/SecureSettingsObserver.java \
+        ../src/com/android/launcher3/TestProtocol.java
+endif
 
 LOCAL_SDK_VERSION := current
 LOCAL_MODULE := ub-launcher-aosp-tapl
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 122151e..b785007 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -29,7 +29,7 @@
 public class AllApps extends LauncherInstrumentation.VisibleContainer {
     private static final int MAX_SCROLL_ATTEMPTS = 40;
     private static final int MIN_INTERACT_SIZE = 100;
-    private static final int FLING_SPEED = 3000;
+    private static final int FLING_SPEED = LauncherInstrumentation.needSlowGestures() ? 1000 : 3000;
 
     private final int mHeight;
 
@@ -60,47 +60,59 @@
      */
     @NonNull
     public AppIcon getAppIcon(String appName) {
-        final UiObject2 allAppsContainer = verifyActiveContainer();
-        final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
-        if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
-            scrollBackToBeginning();
-            int attempts = 0;
-            while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
-                    allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
-                LauncherInstrumentation.assertTrue(
-                        "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
-                        ++attempts <= MAX_SCROLL_ATTEMPTS);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to get app icon on all apps")) {
+            final UiObject2 allAppsContainer = verifyActiveContainer();
+            final BySelector appIconSelector = AppIcon.getAppIconSelector(appName, mLauncher);
+            if (!hasClickableIcon(allAppsContainer, appIconSelector)) {
+                scrollBackToBeginning();
+                int attempts = 0;
+                try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled")) {
+                    while (!hasClickableIcon(allAppsContainer, appIconSelector) &&
+                            allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
+                        mLauncher.assertTrue(
+                                "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+                                ++attempts <= MAX_SCROLL_ATTEMPTS);
+                        verifyActiveContainer();
+                    }
+                }
                 verifyActiveContainer();
             }
-        }
-        verifyActiveContainer();
 
-        final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector);
-        ensureIconVisible(appIcon, allAppsContainer);
-        return new AppIcon(mLauncher, appIcon);
+            final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer,
+                    appIconSelector);
+            ensureIconVisible(appIcon, allAppsContainer);
+            return new AppIcon(mLauncher, appIcon);
+        }
     }
 
     private void scrollBackToBeginning() {
-        final UiObject2 allAppsContainer = verifyActiveContainer();
-        final UiObject2 searchBox =
-                mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to scroll back in all apps")) {
+            final UiObject2 allAppsContainer = verifyActiveContainer();
+            final UiObject2 searchBox =
+                    mLauncher.waitForObjectInContainer(allAppsContainer,
+                            "search_container_all_apps");
 
-        int attempts = 0;
-        allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
+            int attempts = 0;
+            allAppsContainer.setGestureMargins(0, searchBox.getVisibleBounds().bottom + 1, 0, 5);
 
-        for (int scroll = getScroll(allAppsContainer);
-                scroll != 0;
-                scroll = getScroll(allAppsContainer)) {
-            LauncherInstrumentation.assertTrue("Negative scroll position", scroll > 0);
+            for (int scroll = getScroll(allAppsContainer);
+                    scroll != 0;
+                    scroll = getScroll(allAppsContainer)) {
+                mLauncher.assertTrue("Negative scroll position", scroll > 0);
 
-            LauncherInstrumentation.assertTrue(
-                    "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
-                    ++attempts <= MAX_SCROLL_ATTEMPTS);
+                mLauncher.assertTrue(
+                        "Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+                        ++attempts <= MAX_SCROLL_ATTEMPTS);
 
-            allAppsContainer.scroll(Direction.UP, 1);
+                allAppsContainer.scroll(Direction.UP, 1);
+            }
+
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("scrolled up")) {
+                verifyActiveContainer();
+            }
         }
-
-        verifyActiveContainer();
     }
 
     private int getScroll(UiObject2 allAppsContainer) {
@@ -115,8 +127,11 @@
             // to reveal the app icon to have the MIN_INTERACT_SIZE
             final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
             allAppsContainer.scroll(Direction.DOWN, pct);
-            mLauncher.waitForIdle();
-            verifyActiveContainer();
+            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                    "scrolled an icon in all apps to make it visible - and then")) {
+                mLauncher.waitForIdle();
+                verifyActiveContainer();
+            }
         }
     }
 
@@ -124,21 +139,29 @@
      * Flings forward (down) and waits the fling's end.
      */
     public void flingForward() {
-        final UiObject2 allAppsContainer = verifyActiveContainer();
-        // Start the gesture in the center to avoid starting at elements near the top.
-        allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
-        allAppsContainer.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        verifyActiveContainer();
+        try(LauncherInstrumentation.Closable c =
+                    mLauncher.addContextLayer("want to fling forward in all apps")) {
+            final UiObject2 allAppsContainer = verifyActiveContainer();
+            // Start the gesture in the center to avoid starting at elements near the top.
+            allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
+            allAppsContainer.fling(Direction.DOWN,
+                    (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            verifyActiveContainer();
+        }
     }
 
     /**
      * Flings backward (up) and waits the fling's end.
      */
     public void flingBackward() {
-        final UiObject2 allAppsContainer = verifyActiveContainer();
-        // Start the gesture in the center, for symmetry with forward.
-        allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
-        allAppsContainer.fling(Direction.UP, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        verifyActiveContainer();
+        try(LauncherInstrumentation.Closable c =
+                    mLauncher.addContextLayer("want to fling backward in all apps")) {
+            final UiObject2 allAppsContainer = verifyActiveContainer();
+            // Start the gesture in the center, for symmetry with forward.
+            allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
+            allAppsContainer.fling(Direction.UP,
+                    (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            verifyActiveContainer();
+        }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index dcc51b5..c3b671b 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -42,20 +42,24 @@
      */
     @NonNull
     public Overview switchBackToOverview() {
-        final UiObject2 allAppsContainer = verifyActiveContainer();
-        // Swipe from the search box to the bottom.
-        final UiObject2 qsb = mLauncher.waitForObjectInContainer(
-                allAppsContainer, "search_container_all_apps");
-        final Point start = qsb.getVisibleCenter();
-        final int swipeHeight = mLauncher.getTestInfo(
-                TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
-                getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to switch back from all apps to overview")) {
+            final UiObject2 allAppsContainer = verifyActiveContainer();
+            // Swipe from the search box to the bottom.
+            final UiObject2 qsb = mLauncher.waitForObjectInContainer(
+                    allAppsContainer, "search_container_all_apps");
+            final Point start = qsb.getVisibleCenter();
+            final int swipeHeight = mLauncher.getTestInfo(
+                    TestProtocol.REQUEST_ALL_APPS_TO_OVERVIEW_SWIPE_HEIGHT).
+                    getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
 
-        final int endY = start.y + swipeHeight + mLauncher.getTouchSlop();
-        LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
-        mLauncher.swipe(start.x, start.y, start.x, endY, OVERVIEW_STATE_ORDINAL);
+            final int endY = start.y + swipeHeight + mLauncher.getTouchSlop();
+            LauncherInstrumentation.log("AllAppsFromOverview.switchBackToOverview before swipe");
+            mLauncher.swipe(start.x, start.y, start.x, endY, OVERVIEW_STATE_ORDINAL);
 
-        return new Overview(mLauncher);
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("swiped down")) {
+                return new Overview(mLauncher);
+            }
+        }
     }
-
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index ef509ed..26c0ca4 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -57,11 +57,14 @@
      */
     @NonNull
     public BaseOverview switchToOverview() {
-        verifyActiveContainer();
-        goToOverviewUnchecked(BACKGROUND_APP_STATE_ORDINAL);
-        assertTrue("Overview not visible", mLauncher.getDevice().wait(
-                Until.hasObject(By.pkg(getOverviewPackageName())), WAIT_TIME_MS));
-        return new BaseOverview(mLauncher);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to switch from background to overview")) {
+            verifyActiveContainer();
+            goToOverviewUnchecked(BACKGROUND_APP_STATE_ORDINAL);
+            assertTrue("Overview not visible", mLauncher.getDevice().wait(
+                    Until.hasObject(By.pkg(getOverviewPackageName())), WAIT_TIME_MS));
+            return new BaseOverview(mLauncher);
+        }
     }
 
     protected void goToOverviewUnchecked(int expectedState) {
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 8cf1262..4205188 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -29,7 +29,7 @@
  */
 public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
     private static final int FLING_SPEED = 1500;
-    private static final int FLINGS_FOR_DISMISS_LIMIT = 5;
+    private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
 
     BaseOverview(LauncherInstrumentation launcher) {
         super(launcher);
@@ -44,42 +44,54 @@
      * Flings forward (left) and waits the fling's end.
      */
     public void flingForward() {
-        LauncherInstrumentation.log("Overview.flingForward before fling");
-        final UiObject2 overview = verifyActiveContainer();
-        final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
-        overview.setGestureMargins(margin, 0, 0, 0);
-        overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        mLauncher.waitForIdle();
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable c =
+                     mLauncher.addContextLayer("want to fling forward in overview")) {
+            LauncherInstrumentation.log("Overview.flingForward before fling");
+            final UiObject2 overview = verifyActiveContainer();
+            final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
+            overview.setGestureMargins(margin, 0, 0, 0);
+            overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            mLauncher.waitForIdle();
+            verifyActiveContainer();
+        }
     }
 
     /**
      * Dismissed all tasks by scrolling to Clear-all button and pressing it.
      */
     public Workspace dismissAllTasks() {
-        final BySelector clearAllSelector = mLauncher.getLauncherObjectSelector("clear_all");
-        for (int i = 0;
-                i < FLINGS_FOR_DISMISS_LIMIT
-                        && verifyActiveContainer().findObject(clearAllSelector) == null;
-                ++i) {
-            flingForward();
-        }
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "dismissing all tasks")) {
+            final BySelector clearAllSelector = mLauncher.getLauncherObjectSelector("clear_all");
+            for (int i = 0;
+                    i < FLINGS_FOR_DISMISS_LIMIT
+                            && !verifyActiveContainer().hasObject(clearAllSelector);
+                    ++i) {
+                flingForward();
+            }
 
-        mLauncher.getObjectInContainer(verifyActiveContainer(), clearAllSelector).click();
-        return new Workspace(mLauncher);
+            mLauncher.getObjectInContainer(verifyActiveContainer(), clearAllSelector).click();
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "dismissed all tasks")) {
+                return new Workspace(mLauncher);
+            }
+        }
     }
 
     /**
      * Flings backward (right) and waits the fling's end.
      */
     public void flingBackward() {
-        LauncherInstrumentation.log("Overview.flingBackward before fling");
-        final UiObject2 overview = verifyActiveContainer();
-        final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
-        overview.setGestureMargins(0, 0, margin, 0);
-        overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        mLauncher.waitForIdle();
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable c =
+                     mLauncher.addContextLayer("want to fling backward in overview")) {
+            LauncherInstrumentation.log("Overview.flingBackward before fling");
+            final UiObject2 overview = verifyActiveContainer();
+            final int margin = (int) (50 * mLauncher.getDisplayDensity()) + 1;
+            overview.setGestureMargins(0, 0, margin, 0);
+            overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            mLauncher.waitForIdle();
+            verifyActiveContainer();
+        }
     }
 
     /**
@@ -89,18 +101,21 @@
      */
     @NonNull
     public OverviewTask getCurrentTask() {
-        verifyActiveContainer();
-        final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
-                mLauncher.getLauncherObjectSelector("snapshot"));
-        LauncherInstrumentation.assertNotEquals("Unable to find a task", 0, taskViews.size());
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to get current task")) {
+            verifyActiveContainer();
+            final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
+                    mLauncher.getLauncherObjectSelector("snapshot"));
+            mLauncher.assertNotEquals("Unable to find a task", 0, taskViews.size());
 
-        // taskViews contains up to 3 task views: the 'main' (having the widest visible
-        // part) one in the center, and parts of its right and left siblings. Find the
-        // main task view by its width.
-        final UiObject2 widestTask = Collections.max(taskViews,
-                (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
-                        t2.getVisibleBounds().width()));
+            // taskViews contains up to 3 task views: the 'main' (having the widest visible
+            // part) one in the center, and parts of its right and left siblings. Find the
+            // main task view by its width.
+            final UiObject2 widestTask = Collections.max(taskViews,
+                    (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
+                            t2.getVisibleBounds().width()));
 
-        return new OverviewTask(mLauncher, widestTask, this);
+            return new OverviewTask(mLauncher, widestTask, this);
+        }
     }
 }
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index f8bd85a..20c116c 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -48,8 +48,14 @@
     @NonNull
     @Override
     public Overview switchToOverview() {
-        verifyActiveContainer();
-        goToOverviewUnchecked(OVERVIEW_STATE_ORDINAL);
-        return new Overview(mLauncher);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to switch from home to overview")) {
+            verifyActiveContainer();
+            goToOverviewUnchecked(OVERVIEW_STATE_ORDINAL);
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "performed the switch action")) {
+                return new Overview(mLauncher);
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 481281a..7a2b7af 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -59,10 +59,10 @@
     private Background launch(String errorMessage, BySelector selector) {
         LauncherInstrumentation.log("Launchable.launch before click " +
                 mObject.getVisibleCenter());
-        LauncherInstrumentation.assertTrue(
+        mLauncher.assertTrue(
                 "Launching an app didn't open a new window: " + mObject.getText(),
                 mObject.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
-        LauncherInstrumentation.assertTrue(
+        mLauncher.assertTrue(
                 "App didn't start: " + errorMessage,
                 mLauncher.getDevice().wait(Until.hasObject(selector),
                         LauncherInstrumentation.WAIT_TIME_MS));
@@ -79,6 +79,9 @@
                 this,
                 new Point(device.getDisplayWidth() / 2, device.getDisplayHeight() / 2),
                 DRAG_SPEED);
-        return new Workspace(mLauncher);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "dragged launchable to workspace")) {
+            return new Workspace(mLauncher);
+        }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index f44022b..19b368f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.graphics.Point;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -53,6 +54,8 @@
 
 import java.io.IOException;
 import java.lang.ref.WeakReference;
+import java.util.Deque;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
@@ -90,11 +93,16 @@
          * @return UI object for the container.
          */
         final UiObject2 verifyActiveContainer() {
-            assertTrue("Attempt to use a stale container", this == sActiveContainer.get());
+            mLauncher.assertTrue("Attempt to use a stale container",
+                    this == sActiveContainer.get());
             return mLauncher.verifyContainerType(getContainerType());
         }
     }
 
+    interface Closable extends AutoCloseable {
+        void close();
+    }
+
     private static final String WORKSPACE_RES_ID = "workspace";
     private static final String APPS_RES_ID = "apps_view";
     private static final String OVERVIEW_RES_ID = "overview_panel";
@@ -108,6 +116,7 @@
     private final Instrumentation mInstrumentation;
     private int mExpectedRotation = Surface.ROTATION_0;
     private final Uri mTestProviderUri;
+    private final Deque<String> mDiagnosticContext = new LinkedList<>();
 
     /**
      * Constructs the root of TAPL hierarchy. You get all other objects from it.
@@ -161,6 +170,10 @@
         return isSwipeUpEnabled() ? NavigationModel.TWO_BUTTON : NavigationModel.THREE_BUTTON;
     }
 
+    static boolean needSlowGestures() {
+        return Build.MODEL.contains("Cuttlefish");
+    }
+
     private boolean isSwipeUpEnabled() {
         final boolean swipeUpEnabledDefaultValue = SwipeUpSetting.isSwipeUpEnabledDefaultValue();
         return SwipeUpSetting.isSwipeUpSettingAvailable() ?
@@ -175,31 +188,38 @@
         Log.d(TAG, message);
     }
 
-    private static void fail(String message) {
-        Assert.fail("http://go/tapl : " + message);
+    Closable addContextLayer(String piece) {
+        mDiagnosticContext.addLast(piece);
+        return () -> mDiagnosticContext.removeLast();
     }
 
-    static void assertTrue(String message, boolean condition) {
+    private void fail(String message) {
+        final String ctxt = mDiagnosticContext.isEmpty() ? "" : String.join(", ",
+                mDiagnosticContext) + "; ";
+        Assert.fail("http://go/tapl : " + ctxt + message);
+    }
+
+    void assertTrue(String message, boolean condition) {
         if (!condition) {
             fail(message);
         }
     }
 
-    static void assertNotNull(String message, Object object) {
+    void assertNotNull(String message, Object object) {
         assertTrue(message, object != null);
     }
 
-    static private void failEquals(String message, Object actual) {
+    private void failEquals(String message, Object actual) {
         fail(message + ". " + "Actual: " + actual);
     }
 
-    static private void assertEquals(String message, int expected, int actual) {
+    private void assertEquals(String message, int expected, int actual) {
         if (expected != actual) {
             fail(message + " expected: " + expected + " but was: " + actual);
         }
     }
 
-    static void assertNotEquals(String message, int unexpected, int actual) {
+    void assertNotEquals(String message, int unexpected, int actual) {
         if (unexpected == actual) {
             failEquals(message, actual);
         }
@@ -217,49 +237,52 @@
                         (mDevice.findObject(By.res(SYSTEMUI_PACKAGE, "recent_apps")) == null));
         log("verifyContainerType: " + containerType);
 
-        switch (containerType) {
-            case WORKSPACE: {
-                waitForLauncherObject(APPS_RES_ID);
-                waitUntilGone(OVERVIEW_RES_ID);
-                waitUntilGone(WIDGETS_RES_ID);
-                return waitForLauncherObject(WORKSPACE_RES_ID);
-            }
-            case WIDGETS: {
-                waitUntilGone(WORKSPACE_RES_ID);
-                waitUntilGone(APPS_RES_ID);
-                waitUntilGone(OVERVIEW_RES_ID);
-                return waitForLauncherObject(WIDGETS_RES_ID);
-            }
-            case ALL_APPS: {
-                waitUntilGone(WORKSPACE_RES_ID);
-                waitUntilGone(OVERVIEW_RES_ID);
-                waitUntilGone(WIDGETS_RES_ID);
-                return waitForLauncherObject(APPS_RES_ID);
-            }
-            case OVERVIEW: {
-                if (mDevice.isNaturalOrientation()) {
+        try (Closable c = addContextLayer(
+                "but the current state is not " + containerType.name())) {
+            switch (containerType) {
+                case WORKSPACE: {
                     waitForLauncherObject(APPS_RES_ID);
-                } else {
-                    waitUntilGone(APPS_RES_ID);
+                    waitUntilGone(OVERVIEW_RES_ID);
+                    waitUntilGone(WIDGETS_RES_ID);
+                    return waitForLauncherObject(WORKSPACE_RES_ID);
                 }
-                // Fall through
-            }
-            case BASE_OVERVIEW: {
-                waitUntilGone(WORKSPACE_RES_ID);
-                waitUntilGone(WIDGETS_RES_ID);
+                case WIDGETS: {
+                    waitUntilGone(WORKSPACE_RES_ID);
+                    waitUntilGone(APPS_RES_ID);
+                    waitUntilGone(OVERVIEW_RES_ID);
+                    return waitForLauncherObject(WIDGETS_RES_ID);
+                }
+                case ALL_APPS: {
+                    waitUntilGone(WORKSPACE_RES_ID);
+                    waitUntilGone(OVERVIEW_RES_ID);
+                    waitUntilGone(WIDGETS_RES_ID);
+                    return waitForLauncherObject(APPS_RES_ID);
+                }
+                case OVERVIEW: {
+                    if (mDevice.isNaturalOrientation()) {
+                        waitForLauncherObject(APPS_RES_ID);
+                    } else {
+                        waitUntilGone(APPS_RES_ID);
+                    }
+                    // Fall through
+                }
+                case BASE_OVERVIEW: {
+                    waitUntilGone(WORKSPACE_RES_ID);
+                    waitUntilGone(WIDGETS_RES_ID);
 
-                return waitForLauncherObject(OVERVIEW_RES_ID);
+                    return waitForLauncherObject(OVERVIEW_RES_ID);
+                }
+                case BACKGROUND: {
+                    waitUntilGone(WORKSPACE_RES_ID);
+                    waitUntilGone(APPS_RES_ID);
+                    waitUntilGone(OVERVIEW_RES_ID);
+                    waitUntilGone(WIDGETS_RES_ID);
+                    return null;
+                }
+                default:
+                    fail("Invalid state: " + containerType);
+                    return null;
             }
-            case BACKGROUND: {
-                waitUntilGone(WORKSPACE_RES_ID);
-                waitUntilGone(APPS_RES_ID);
-                waitUntilGone(OVERVIEW_RES_ID);
-                waitUntilGone(WIDGETS_RES_ID);
-                return null;
-            }
-            default:
-                fail("Invalid state: " + containerType);
-                return null;
         }
     }
 
@@ -351,7 +374,9 @@
      */
     @NonNull
     public Workspace getWorkspace() {
-        return new Workspace(this);
+        try (LauncherInstrumentation.Closable c = addContextLayer("want to get workspace object")) {
+            return new Workspace(this);
+        }
     }
 
     /**
@@ -373,7 +398,9 @@
      */
     @NonNull
     public Widgets getAllWidgets() {
-        return new Widgets(this);
+        try (LauncherInstrumentation.Closable c = addContextLayer("want to get widgets")) {
+            return new Widgets(this);
+        }
     }
 
     /**
@@ -384,7 +411,9 @@
      */
     @NonNull
     public Overview getOverview() {
-        return new Overview(this);
+        try (LauncherInstrumentation.Closable c = addContextLayer("want to get overview")) {
+            return new Overview(this);
+        }
     }
 
     /**
@@ -408,7 +437,9 @@
      */
     @NonNull
     public AllApps getAllApps() {
-        return new AllApps(this);
+        try (LauncherInstrumentation.Closable c = addContextLayer("want to get all apps object")) {
+            return new AllApps(this);
+        }
     }
 
     /**
@@ -421,7 +452,9 @@
      */
     @NonNull
     public AllAppsFromOverview getAllAppsFromOverview() {
-        return new AllAppsFromOverview(this);
+        try (LauncherInstrumentation.Closable c = addContextLayer("want to get all apps object")) {
+            return new AllAppsFromOverview(this);
+        }
     }
 
     void waitUntilGone(String resId) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 5c8d5eb..41932c8 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -20,11 +20,11 @@
 
 import android.graphics.Point;
 
-import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
-
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.UiObject2;
 
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
+
 /**
  * Overview pane.
  */
@@ -47,14 +47,20 @@
      */
     @NonNull
     public AllAppsFromOverview switchToAllApps() {
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to switch from overview to all apps")) {
+            verifyActiveContainer();
 
-        // Swipe from navbar to the top.
-        final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
-        final Point start = navBar.getVisibleCenter();
-        LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
-        mLauncher.swipe(start.x, start.y, start.x, 0, ALL_APPS_STATE_ORDINAL);
+            // Swipe from navbar to the top.
+            final UiObject2 navBar = mLauncher.waitForSystemUiObject("navigation_bar_frame");
+            final Point start = navBar.getVisibleCenter();
+            LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
+            mLauncher.swipe(start.x, start.y, start.x, 0, ALL_APPS_STATE_ORDINAL);
 
-        return new AllAppsFromOverview(mLauncher);
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "swiped all way up from overview")) {
+                return new AllAppsFromOverview(mLauncher);
+            }
+        }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 7ccd49b..b966851 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -44,10 +44,13 @@
      * Swipes the task up.
      */
     public void dismiss() {
-        verifyActiveContainer();
-        // Dismiss the task via flinging it up.
-        mTask.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        mLauncher.waitForIdle();
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to dismiss a task")) {
+            verifyActiveContainer();
+            // Dismiss the task via flinging it up.
+            mTask.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            mLauncher.waitForIdle();
+        }
     }
 
     /**
@@ -55,7 +58,7 @@
      */
     public Background open() {
         verifyActiveContainer();
-        LauncherInstrumentation.assertTrue("Launching task didn't open a new window: " +
+        mLauncher.assertTrue("Launching task didn't open a new window: " +
                         mTask.getParent().getContentDescription(),
                 mTask.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
         return new Background(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 89affd1..b6938d6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -34,21 +34,33 @@
      * Flings forward (down) and waits the fling's end.
      */
     public void flingForward() {
-        final UiObject2 widgetsContainer = verifyActiveContainer();
-        widgetsContainer.setGestureMargin(100);
-        widgetsContainer.fling(Direction.DOWN, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to fling forward in widgets")) {
+            final UiObject2 widgetsContainer = verifyActiveContainer();
+            widgetsContainer.setGestureMargin(100);
+            widgetsContainer.fling(Direction.DOWN,
+                    (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) {
+                verifyActiveContainer();
+            }
+        }
     }
 
     /**
      * Flings backward (up) and waits the fling's end.
      */
     public void flingBackward() {
-        final UiObject2 widgetsContainer = verifyActiveContainer();
-        widgetsContainer.setGestureMargin(100);
-        widgetsContainer.fling(Direction.UP, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
-        mLauncher.waitForIdle();
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to fling backwards in widgets")) {
+            final UiObject2 widgetsContainer = verifyActiveContainer();
+            widgetsContainer.setGestureMargin(100);
+            widgetsContainer.fling(Direction.UP,
+                    (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
+            mLauncher.waitForIdle();
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) {
+                verifyActiveContainer();
+            }
+        }
     }
 
     @Override
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 7d97acd..9979f50 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -36,7 +36,7 @@
 public final class Workspace extends Home {
     private static final float FLING_SPEED = 3500.0F;
     private final UiObject2 mHotseat;
-    private final int ICON_DRAG_SPEED = 2000;
+    private final int ICON_DRAG_SPEED = LauncherInstrumentation.needSlowGestures() ? 100 : 570;
 
     Workspace(LauncherInstrumentation launcher) {
         super(launcher);
@@ -50,21 +50,27 @@
      */
     @NonNull
     public AllApps switchToAllApps() {
-        verifyActiveContainer();
-        final UiObject2 hotseat = mHotseat;
-        final Point start = hotseat.getVisibleCenter();
-        final int swipeHeight = mLauncher.getTestInfo(
-                TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
-                getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
-        mLauncher.swipe(
-                start.x,
-                start.y,
-                start.x,
-                start.y - swipeHeight - mLauncher.getTouchSlop(),
-                ALL_APPS_STATE_ORDINAL
-        );
+        try(LauncherInstrumentation.Closable c =
+                    mLauncher.addContextLayer("want to switch from workspace to all apps")) {
+            verifyActiveContainer();
+            final UiObject2 hotseat = mHotseat;
+            final Point start = hotseat.getVisibleCenter();
+            final int swipeHeight = mLauncher.getTestInfo(
+                    TestProtocol.REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT).
+                    getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+            mLauncher.swipe(
+                    start.x,
+                    start.y,
+                    start.x,
+                    start.y - swipeHeight - mLauncher.getTouchSlop(),
+                    ALL_APPS_STATE_ORDINAL
+            );
 
-        return new AllApps(mLauncher);
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "swiped to all apps")) {
+                return new AllApps(mLauncher);
+            }
+        }
     }
 
     /**
@@ -75,9 +81,13 @@
      */
     @Nullable
     public AppIcon tryGetWorkspaceAppIcon(String appName) {
-        final UiObject2 workspace = verifyActiveContainer();
-        final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName, mLauncher));
-        return icon != null ? new AppIcon(mLauncher, icon) : null;
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to get a workspace icon")) {
+            final UiObject2 workspace = verifyActiveContainer();
+            final UiObject2 icon = workspace.findObject(
+                    AppIcon.getAppIconSelector(appName, mLauncher));
+            return icon != null ? new AppIcon(mLauncher, icon) : null;
+        }
     }
 
 
@@ -107,7 +117,7 @@
                     getHotseatAppIcon("Messages"),
                     new Point(mLauncher.getDevice().getDisplayWidth(),
                             workspace.getVisibleBounds().centerY()),
-                    ICON_DRAG_SPEED);
+                    (int) (ICON_DRAG_SPEED * mLauncher.getDisplayDensity()));
             verifyActiveContainer();
         }
         assertTrue("Home screen workspace didn't become scrollable",
@@ -165,7 +175,9 @@
     public Widgets openAllWidgets() {
         verifyActiveContainer();
         mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
-        return new Widgets(mLauncher);
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
+            return new Widgets(mLauncher);
+        }
     }
 
     @Override