Merge "TAPL: Optimization: avoid getting actual events twice" into ub-launcher3-master
diff --git a/SharedLibWrapper/build.gradle b/SharedLibWrapper/build.gradle
new file mode 100644
index 0000000..674e38a
--- /dev/null
+++ b/SharedLibWrapper/build.gradle
@@ -0,0 +1,17 @@
+apply plugin: 'java'
+
+final String ANDROID_TOP = "${rootDir}/../../.."
+final String FRAMEWORK_PREBUILTS_DIR = "${ANDROID_TOP}/prebuilts/framework_intermediates/"
+
+sourceSets {
+    main {
+        java.srcDirs = ["${ANDROID_TOP}/frameworks/lib/systemui/SharedLibWrapper/src"]
+    }
+}
+
+sourceCompatibility = 1.8
+
+dependencies {
+    implementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
+    compileOnly fileTree(dir: "$ANDROID_TOP/prebuilts/fullsdk-${org.gradle.internal.os.OperatingSystem.current().isMacOsX() ? "darwin" : "linux"}/platforms/${COMPILE_SDK}", include: 'android.jar')
+}
diff --git a/build.gradle b/build.gradle
index e296455..534ca65 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,6 +2,7 @@
     repositories {
         mavenCentral()
         google()
+        jcenter()
     }
     dependencies {
         classpath GRADLE_CLASS_PATH
@@ -62,12 +63,6 @@
             minSdkVersion 28
         }
 
-        withQuickstepIconRecents {
-            dimension "recents"
-
-            minSdkVersion 28
-        }
-
         withoutQuickstep {
             dimension "recents"
         }
@@ -78,11 +73,6 @@
         if (variant.buildType.name.endsWith('release')) {
             variant.setIgnore(true)
         }
-
-        // Icon recents is Go only
-        if (name.contains("WithQuickstepIconRecents") && !name.contains("l3go")) {
-            variant.setIgnore(true)
-        }
     }
 
     sourceSets {
@@ -96,10 +86,6 @@
             }
         }
 
-        debug {
-            manifest.srcFile "AndroidManifest.xml"
-        }
-
         androidTest {
             res.srcDirs = ['tests/res']
             java.srcDirs = ['tests/src', 'tests/tapl']
@@ -112,15 +98,30 @@
 
         aosp {
             java.srcDirs = ['src_flags', 'src_shortcuts_overrides']
+        }
+
+        aospWithoutQuickstep {
             manifest.srcFile "AndroidManifest.xml"
         }
 
+        aospWithQuickstep {
+            manifest.srcFile "quickstep/AndroidManifest-launcher.xml"
+        }
+
         l3go {
             res.srcDirs = ['go/res']
             java.srcDirs = ['go/src']
             manifest.srcFile "go/AndroidManifest.xml"
         }
 
+        l3goWithoutQuickstepDebug {
+            manifest.srcFile "AndroidManifest.xml"
+        }
+
+        l3goWithQuickstepDebug {
+            manifest.srcFile "quickstep/AndroidManifest-launcher.xml"
+        }
+
         withoutQuickstep {
             java.srcDirs = ['src_ui_overrides']
         }
@@ -130,20 +131,17 @@
             java.srcDirs = ['quickstep/src', 'quickstep/recents_ui_overrides/src']
             manifest.srcFile "quickstep/AndroidManifest.xml"
         }
-
-        withQuickstepIconRecents {
-            res.srcDirs = ['quickstep/res', 'go/quickstep/res']
-            java.srcDirs = ['quickstep/src', 'go/quickstep/src']
-            manifest.srcFile "quickstep/AndroidManifest.xml"
-        }
     }
 }
 
-repositories {
-    maven { url "../../../prebuilts/fullsdk-darwin/extras/android/m2repository" }
-    maven { url "../../../prebuilts/fullsdk-linux/extras/android/m2repository" }
-    mavenCentral()
-    google()
+allprojects {
+    repositories {
+        maven { url "../../../prebuilts/sdk/current/androidx/m2repository" }
+        maven { url "../../../prebuilts/fullsdk-darwin/extras/android/m2repository" }
+        maven { url "../../../prebuilts/fullsdk-linux/extras/android/m2repository" }
+        mavenCentral()
+        google()
+    }
 }
 
 dependencies {
@@ -151,14 +149,12 @@
     implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
     implementation "androidx.preference:preference:${ANDROID_X_VERSION}"
     implementation project(':IconLoader')
+    withQuickstepImplementation project(':SharedLibWrapper')
     implementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/libs", include: 'launcher_protos.jar')
 
     // Recents lib dependency
     withQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
 
-    // Recents lib dependency for Go
-    withQuickstepIconRecentsImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
-
     // Required for AOSP to compile. This is already included in the sysui_shared.jar
     withoutQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/libs", include: 'plugin_core.jar')
 
@@ -175,7 +171,7 @@
 protobuf {
     // Configure the protoc executable
     protoc {
-        artifact = 'com.google.protobuf:protoc:3.0.0-alpha-3'
+        artifact = 'com.google.protobuf:protoc:3.0.0'
 
         generateProtoTasks {
             all().each { task ->
diff --git a/gradle.properties b/gradle.properties
index a77f52a..7a51375 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,11 +2,11 @@
 android.useAndroidX = true
 android.enableJetifier = true
 
-ANDROID_X_VERSION=1.0.0-beta01
+ANDROID_X_VERSION=1+
 
-GRADLE_CLASS_PATH=com.android.tools.build:gradle:3.3.0
+GRADLE_CLASS_PATH=com.android.tools.build:gradle:3.5.1
 
-PROTOBUF_CLASS_PATH=com.google.protobuf:protobuf-gradle-plugin:0.8.6
+PROTOBUF_CLASS_PATH=com.google.protobuf:protobuf-gradle-plugin:0.8.8
 PROTOBUF_DEPENDENCY=com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7
 
 BUILD_TOOLS_VERSION=28.0.3
diff --git a/iconloaderlib/build.gradle b/iconloaderlib/build.gradle
index 8a4d2b7..d7a62e1 100644
--- a/iconloaderlib/build.gradle
+++ b/iconloaderlib/build.gradle
@@ -3,7 +3,6 @@
 android {
     compileSdkVersion COMPILE_SDK
     buildToolsVersion BUILD_TOOLS_VERSION
-    publishNonDefault true
 
     defaultConfig {
         minSdkVersion 25
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index d4db05a..1e01709 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -69,9 +69,9 @@
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.views.FloatingIconView;
+import com.android.quickstep.RemoteAnimationTargets;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.RemoteAnimationProvider;
-import com.android.quickstep.RemoteAnimationTargets;
 import com.android.systemui.shared.system.ActivityCompat;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -83,6 +83,8 @@
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
+import java.lang.ref.WeakReference;
+
 /**
  * {@link LauncherAppTransitionManager} with Quickstep-specific app transitions for launching from
  * home and/or all-apps.
@@ -149,6 +151,7 @@
     private DeviceProfile mDeviceProfile;
 
     private RemoteAnimationProvider mRemoteAnimationProvider;
+    private WrappedAnimationRunnerImpl mWallpaperOpenRunner;
 
     private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
         @Override
@@ -176,7 +179,6 @@
         mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
 
         mLauncher.addOnDeviceProfileChangeListener(this);
-        registerRemoteAnimations();
     }
 
     @Override
@@ -598,18 +600,36 @@
     /**
      * Registers remote animations used when closing apps to home screen.
      */
-    private void registerRemoteAnimations() {
-        // Unregister this
+    @Override
+    public void registerRemoteAnimations() {
         if (hasControlRemoteAppTransitionPermission()) {
+            mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */);
+
             RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
             definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
                     WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
-                    new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(false /* fromUnlock */),
+                    new RemoteAnimationAdapterCompat(
+                            new WrappedLauncherAnimationRunner<>(mWallpaperOpenRunner,
+                                    false /* startAtFrontOfQueue */),
                             CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
             new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
         }
     }
 
+    /**
+     * Unregisters all remote animations.
+     */
+    @Override
+    public void unregisterRemoteAnimations() {
+        if (hasControlRemoteAppTransitionPermission()) {
+            new ActivityCompat(mLauncher).unregisterRemoteAnimations();
+
+            // Also clear strong references to the runners registered with the remote animation
+            // definition so we don't have to wait for the system gc
+            mWallpaperOpenRunner = null;
+        }
+    }
+
     private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
         return taskIsATargetWithMode(targets, mLauncher.getTaskId(), mode);
     }
@@ -618,9 +638,8 @@
      * @return Runner that plays when user goes to Launcher
      *         ie. pressing home, swiping up from nav bar.
      */
-    RemoteAnimationRunnerCompat getWallpaperOpenRunner(boolean fromUnlock) {
-        return new WallpaperOpenLauncherAnimationRunner(mHandler, false /* startAtFrontOfQueue */,
-                fromUnlock);
+    WrappedAnimationRunnerImpl createWallpaperOpenRunner(boolean fromUnlock) {
+        return new WallpaperOpenLauncherAnimationRunner(mHandler, fromUnlock);
     }
 
     /**
@@ -701,7 +720,8 @@
     }
 
     /**
-     * Creates an animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}.
+     * Creates an animator that modifies Launcher as a result from 
+     * {@link #createWallpaperOpenRunner}.
      */
     private void createLauncherResumeAnimation(AnimatorSet anim) {
         if (mLauncher.isInState(LauncherState.ALL_APPS)) {
@@ -761,18 +781,70 @@
     }
 
     /**
+     * Used with WrappedLauncherAnimationRunner as an interface for the runner to call back to the
+     * implementation.
+     */
+    protected interface WrappedAnimationRunnerImpl {
+        Handler getHandler();
+        void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
+                RemoteAnimationTargetCompat[] wallpaperTargets,
+                LauncherAnimationRunner.AnimationResult result);
+    }
+
+    /**
+     * This class is needed to wrap any animation runner that is a part of the
+     * RemoteAnimationDefinition:
+     * - Launcher creates a new instance of the LauncherAppTransitionManagerImpl whenever it is
+     *   created, which in turn registers a new definition
+     * - When the definition is registered, window manager retains a strong binder reference to the
+     *   runner passed in
+     * - If the Launcher activity is recreated, the new definition registered will replace the old
+     *   reference in the system's activity record, but until the system server is GC'd, the binder
+     *   reference will still exist, which references the runner in the Launcher process, which
+     *   references the (old) Launcher activity through this class
+     *
+     * Instead we make the runner provided to the definition static only holding a weak reference to
+     * the runner implementation.  When this animation manager is destroyed, we remove the Launcher
+     * reference to the runner, leaving only the weak ref from the runner.
+     */
+    protected static class WrappedLauncherAnimationRunner<R extends WrappedAnimationRunnerImpl>
+            extends LauncherAnimationRunner {
+        private WeakReference<R> mImpl;
+
+        public WrappedLauncherAnimationRunner(R animationRunnerImpl, boolean startAtFrontOfQueue) {
+            super(animationRunnerImpl.getHandler(), startAtFrontOfQueue);
+            mImpl = new WeakReference<>(animationRunnerImpl);
+        }
+
+        @Override
+        public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
+                RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
+            R animationRunnerImpl = mImpl.get();
+            if (animationRunnerImpl != null) {
+                animationRunnerImpl.onCreateAnimation(appTargets, wallpaperTargets, result);
+            }
+        }
+    }
+
+    /**
      * Remote animation runner for animation from the app to Launcher, including recents.
      */
-    class WallpaperOpenLauncherAnimationRunner extends LauncherAnimationRunner {
+    protected class WallpaperOpenLauncherAnimationRunner implements WrappedAnimationRunnerImpl {
+
+        private final Handler mHandler;
         private final boolean mFromUnlock;
 
-        public WallpaperOpenLauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue,
-                boolean fromUnlock) {
-            super(handler, startAtFrontOfQueue);
+        public WallpaperOpenLauncherAnimationRunner(Handler handler, boolean fromUnlock) {
+            mHandler = handler;
             mFromUnlock = fromUnlock;
         }
 
         @Override
+        public Handler getHandler() {
+            return mHandler;
+        }
+
+        @Override
         public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
                 RemoteAnimationTargetCompat[] wallpaperTargets,
                 LauncherAnimationRunner.AnimationResult result) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index ab6393a..71d77fc 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -43,6 +43,7 @@
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.views.RecentsView;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -51,10 +52,18 @@
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class TaplTestsQuickstep extends AbstractQuickStepTest {
+    private int mLauncherPid;
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
         TaplTestsLauncher3.initialize(this);
+        mLauncherPid = mLauncher.getPid();
+    }
+
+    @After
+    public void teardown() {
+        assertEquals("Launcher crashed, pid mismatch:", mLauncherPid, mLauncher.getPid());
     }
 
     private void startTestApps() throws Exception {
diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
index 83b8599..6223760 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
@@ -23,12 +23,14 @@
 
 import android.database.sqlite.SQLiteDatabase;
 
+import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.util.LauncherModelHelper;
 import com.android.launcher3.util.LauncherRoboTestRunner;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.LooperMode;
 
 /**
@@ -44,7 +46,8 @@
     @Before
     public void setUp() {
         mModelHelper = new LauncherModelHelper();
-        mDb = mModelHelper.provider.getDbWithRestoreDbTask();
+        RestoreDbTask.setPending(RuntimeEnvironment.application, true);
+        mDb = mModelHelper.provider.getDb();
     }
 
     @Test
diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 655055c..e8b7157 100644
--- a/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/robolectric_tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
 import android.provider.Settings;
 
@@ -276,6 +277,8 @@
         Context context = RuntimeEnvironment.application;
         LauncherSettings.Settings.call(context.getContentResolver(),
                 LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+        LauncherSettings.Settings.call(context.getContentResolver(),
+                LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
         int[][][] ids = new int[typeArray.length][][];
 
         for (int i = 0; i < typeArray.length; i++) {
@@ -312,7 +315,6 @@
         idp.numRows = idp.numColumns = idp.numHotseatIcons = DEFAULT_GRID_SIZE;
         idp.iconBitmapSize = DEFAULT_BITMAP_SIZE;
 
-        provider.setAllowLoadDefaultFavorites(true);
         Settings.Secure.putString(context.getContentResolver(),
                 "launcher3.layout.provider", TEST_PROVIDER_AUTHORITY);
 
@@ -340,4 +342,20 @@
         filter.addCategory(Intent.CATEGORY_DEFAULT);
         spm.addIntentFilterForActivity(cn, filter);
     }
+
+    /**
+     * An extension of LauncherProvider backed up by in-memory database.
+     */
+    public static class TestLauncherProvider extends LauncherProvider {
+
+        @Override
+        public boolean onCreate() {
+            return true;
+        }
+
+        public SQLiteDatabase getDb() {
+            createDbIfNotExists();
+            return mOpenHelper.getWritableDatabase();
+        }
+    }
 }
diff --git a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
deleted file mode 100644
index 8ae6528..0000000
--- a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.android.launcher3.util;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-
-import com.android.launcher3.LauncherProvider;
-import com.android.launcher3.provider.RestoreDbTask;
-
-/**
- * An extension of LauncherProvider backed up by in-memory database.
- */
-public class TestLauncherProvider extends LauncherProvider {
-
-    private boolean mAllowLoadDefaultFavorites;
-
-    @Override
-    public boolean onCreate() {
-        return true;
-    }
-
-    @Override
-    protected synchronized void createDbIfNotExists() {
-        if (mOpenHelper == null) {
-            mOpenHelper = new MyDatabaseHelper(getContext(), mAllowLoadDefaultFavorites);
-        }
-    }
-
-    public void setAllowLoadDefaultFavorites(boolean allowLoadDefaultFavorites) {
-        mAllowLoadDefaultFavorites = allowLoadDefaultFavorites;
-    }
-
-    public SQLiteDatabase getDb() {
-        createDbIfNotExists();
-        return mOpenHelper.getWritableDatabase();
-    }
-
-    public SQLiteDatabase getDbWithRestoreDbTask() {
-        RestoreDbTask.setPending(getContext(), true);
-        super.createDbIfNotExists();
-        return mOpenHelper.getWritableDatabase();
-    }
-
-    private static class MyDatabaseHelper extends DatabaseHelper {
-
-        private final boolean mAllowLoadDefaultFavorites;
-
-        MyDatabaseHelper(Context context, boolean allowLoadDefaultFavorites) {
-            super(context, null);
-            mAllowLoadDefaultFavorites = allowLoadDefaultFavorites;
-            initIds();
-        }
-
-        @Override
-        public long getDefaultUserSerial() {
-            return 0;
-        }
-
-        @Override
-        protected void onEmptyDbCreated() {
-            if (mAllowLoadDefaultFavorites) {
-                super.onEmptyDbCreated();
-            }
-        }
-
-        @Override
-        protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { }
-    }
-}
diff --git a/settings.gradle b/settings.gradle
index b52bd4f..ce13bfb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,5 @@
 include ':IconLoader'
 project(':IconLoader').projectDir = new File(rootDir, 'iconloaderlib')
+
+include ':SharedLibWrapper'
+project(':SharedLibWrapper').projectDir = new File(rootDir, 'SharedLibWrapper')
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index ea63fa7..3ca4f59 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -286,7 +286,7 @@
     /**
      * Used to set the override visibility state, used only to handle the transition home with the
      * recents animation.
-     * @see QuickstepAppTransitionManagerImpl#getWallpaperOpenRunner
+     * @see QuickstepAppTransitionManagerImpl#createWallpaperOpenRunner
      */
     public void addForceInvisibleFlag(@InvisibilityFlags int flag) {
         mForceInvisible |= flag;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index f5fafbf..8066d38 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -373,6 +373,7 @@
         mPopupDataProvider = new PopupDataProvider(this);
 
         mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
+        mAppTransitionManager.registerRemoteAnimations();
 
         boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this);
         if (internalStateHandled) {
@@ -1545,6 +1546,7 @@
         LauncherAppState.getIDP(this).removeOnChangeListener(this);
 
         mOverlayManager.onActivityDestroyed(this);
+        mAppTransitionManager.unregisterRemoteAnimations();
     }
 
     public LauncherAccessibilityDelegate getAccessibilityDelegate() {
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index c55c120..9148c2f 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -67,4 +67,18 @@
     public Animator createStateElementAnimation(int index, float... values) {
         throw new RuntimeException("Unknown gesture animation " + index);
     }
+
+    /**
+     * Registers remote animations for certain system transitions.
+     */
+    public void registerRemoteAnimations() {
+        // Do nothing
+    }
+
+    /**
+     * Unregisters all remote animations.
+     */
+    public void unregisterRemoteAnimations() {
+        // Do nothing
+    }
 }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index b589560..b0ab35c 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
 import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.annotation.TargetApi;
 import android.app.backup.BackupManager;
@@ -45,6 +46,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -87,6 +89,8 @@
     private static final boolean LOGD = false;
 
     private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json";
+    private static final String TOKEN_RESTORE_BACKUP_TABLE = "restore_backup_table";
+    private static final long RESTORE_BACKUP_TABLE_DELAY = 60000;
 
     /**
      * Represents the schema of the database. Changes in scheme need not be backwards compatible.
@@ -388,8 +392,11 @@
                 return null;
             }
             case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
-                RestoreDbTask.restoreIfPossible(
-                        getContext(), mOpenHelper, new BackupManager(getContext()));
+                final Handler handler = MODEL_EXECUTOR.getHandler();
+                handler.removeCallbacksAndMessages(TOKEN_RESTORE_BACKUP_TABLE);
+                handler.postDelayed(() -> RestoreDbTask.restoreIfPossible(
+                        getContext(), mOpenHelper, new BackupManager(getContext())),
+                        TOKEN_RESTORE_BACKUP_TABLE, RESTORE_BACKUP_TABLE_DELAY);
                 return null;
             }
         }
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index f0bae02..89f0a3d 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -78,6 +78,7 @@
         }
 
         InstallSessionHelper packageInstallerCompat = InstallSessionHelper.INSTANCE.get(context);
+        packageInstallerCompat.restoreDbIfApplicable(info);
         if (TextUtils.isEmpty(info.getAppPackageName())
                 || info.getInstallReason() != PackageManager.INSTALL_REASON_USER
                 || packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 81dcba3..75609fe 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -136,6 +136,10 @@
     public static final TogglableFlag ENABLE_OVERVIEW_ACTIONS = new TogglableFlag(
             "ENABLE_OVERVIEW_ACTIONS", false, "Show app actions in Overview");
 
+    public static final TogglableFlag ENABLE_DATABASE_RESTORE = new TogglableFlag(
+            "ENABLE_DATABASE_RESTORE", true,
+            "Enable database restore when new restore session is created");
+
     public static void initialize(Context context) {
         // Avoid the disk read for user builds
         if (Utilities.IS_DEBUG_DEVICE) {
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 186293f..976d7ba 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -29,6 +29,10 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.SessionCommitReceiver;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
@@ -52,6 +56,8 @@
     // Set<String> of session ids of promise icons that have been added to the home screen
     // as FLAG_PROMISE_NEW_INSTALLS.
     protected static final String PROMISE_ICON_IDS = "promise_icon_ids";
+    public static final String KEY_INSTALL_SESSION_CREATED_TIMESTAMP =
+            "key_install_session_created_timestamp";
 
     private static final boolean DEBUG = false;
 
@@ -159,6 +165,34 @@
         return list;
     }
 
+    /**
+     * Attempt to restore workspace layout if the session is triggered due to device restore and it
+     * has a newer timestamp.
+     */
+    public boolean restoreDbIfApplicable(@NonNull final SessionInfo info) {
+        if (!Utilities.ATLEAST_OREO || !FeatureFlags.ENABLE_DATABASE_RESTORE.get()) {
+            return false;
+        }
+        if (isRestore(info) && hasNewerTimestamp(mAppContext, info)) {
+            LauncherSettings.Settings.call(mAppContext.getContentResolver(),
+                    LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE);
+            return true;
+        }
+        return false;
+    }
+
+    @RequiresApi(26)
+    private static boolean isRestore(@NonNull final SessionInfo info) {
+        return info.getInstallReason() == PackageManager.INSTALL_REASON_DEVICE_RESTORE;
+    }
+
+    private static boolean hasNewerTimestamp(
+            @NonNull final Context context, @NonNull final SessionInfo info) {
+        return PackageManagerHelper.getSessionCreatedTimeInMillis(info)
+                > Utilities.getDevicePrefs(context).getLong(
+                        KEY_INSTALL_SESSION_CREATED_TIMESTAMP, 0);
+    }
+
     public boolean promiseIconAddedForId(int sessionId) {
         return mPromiseIconIds.contains(sessionId);
     }
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 7ee30cc..407ff31 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.provider;
 
+import static com.android.launcher3.pm.InstallSessionHelper.KEY_INSTALL_SESSION_CREATED_TIMESTAMP;
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
 
 import android.app.backup.BackupManager;
@@ -86,6 +87,8 @@
      */
     public static boolean restoreIfPossible(@NonNull Context context,
             @NonNull DatabaseHelper helper, @NonNull BackupManager backupManager) {
+        Utilities.getDevicePrefs(context).edit().putLong(
+                KEY_INSTALL_SESSION_CREATED_TIMESTAMP, System.currentTimeMillis()).apply();
         final SQLiteDatabase db = helper.getWritableDatabase();
         try (SQLiteTransaction t = new SQLiteTransaction(db)) {
             RestoreDbTask task = new RestoreDbTask();
diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
index e6203b4..5291ce4 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutRequest.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
@@ -58,10 +58,20 @@
         mUserHandle = userHandle;
     }
 
+    /** @see #forPackage(String, List) */
+    public ShortcutRequest forPackage(String packageName) {
+        return forPackage(packageName, (List<String>) null);
+    }
+
+    /** @see #forPackage(String, List) */
     public ShortcutRequest forPackage(String packageName, String... shortcutIds) {
         return forPackage(packageName, Arrays.asList(shortcutIds));
     }
 
+    /**
+     * @param shortcutIds If null, match all shortcuts, otherwise only match the given id's.
+     * @return A list of ShortcutInfo's associated with the given package.
+     */
     public ShortcutRequest forPackage(String packageName, @Nullable List<String> shortcutIds) {
         if (!GO_DISABLE_WIDGETS && packageName != null) {
             mQuery.setPackage(packageName);
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index ecfc77c..506830d 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -126,11 +126,11 @@
 
             case TestProtocol.REQUEST_APPS_LIST_SCROLL_Y: {
                 try {
-                    final int deferUpdatesFlags = MAIN_EXECUTOR.submit(() ->
+                    final int scroll = MAIN_EXECUTOR.submit(() ->
                             mLauncher.getAppsView().getActiveRecyclerView().getCurrentScrollY())
                             .get();
                     response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                            deferUpdatesFlags);
+                            scroll);
                 } catch (ExecutionException | InterruptedException e) {
                     throw new RuntimeException(e);
                 }
diff --git a/src/com/android/launcher3/testing/TestLogging.java b/src/com/android/launcher3/testing/TestLogging.java
index 024110d..fd066c1 100644
--- a/src/com/android/launcher3/testing/TestLogging.java
+++ b/src/com/android/launcher3/testing/TestLogging.java
@@ -21,7 +21,7 @@
 import com.android.launcher3.Utilities;
 
 public final class TestLogging {
-    public static synchronized void recordEvent(String event) {
+    public static void recordEvent(String event) {
         if (Utilities.IS_RUNNING_IN_TEST_HARNESS) {
             Log.d(TestProtocol.TAPL_EVENTS_TAG, event);
         }
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index bee7853..ba1bfa5 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -33,7 +33,6 @@
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
-import com.android.launcher3.testing.TestLogging;
 
 /**
  * Class to handle long-clicks on workspace items and start drag as a result.
@@ -47,7 +46,6 @@
             ItemLongClickListener::onAllAppsItemLongClick;
 
     private static boolean onWorkspaceItemLongClick(View v) {
-        TestLogging.recordEvent("onWorkspaceItemLongClick");
         Launcher launcher = Launcher.getLauncher(v.getContext());
         if (!canStartDrag(launcher)) return false;
         if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
@@ -77,7 +75,6 @@
     }
 
     private static boolean onAllAppsItemLongClick(View v) {
-        TestLogging.recordEvent("onAllAppsItemLongClick");
         Launcher launcher = Launcher.getLauncher(v.getContext());
         if (!canStartDrag(launcher)) return false;
         // When we have exited all apps or are in transition, disregard long clicks
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 61ce046..310d598 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -38,7 +38,6 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.views.OptionsPopupView;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -166,7 +165,6 @@
 
     @Override
     public void onLongPress(MotionEvent event) {
-        TestLogging.recordEvent("Workspace.longPress");
         if (mLongPressState == STATE_REQUESTED) {
             if (canHandleLongPress()) {
                 mLongPressState = STATE_PENDING_PARENT_INFORM;
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 8b2ee36..6c18747 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.util;
 
+import static android.content.pm.PackageInstaller.SessionInfo;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
 import android.app.AppOpsManager;
@@ -44,6 +45,8 @@
 import android.util.Pair;
 import android.widget.Toast;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.AppInfo;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppWidgetInfo;
@@ -345,4 +348,15 @@
         }
         return false;
     }
+
+    /**
+     * Returns the created time in millis of given session info. Returns 0 if not available.
+     */
+    public static long getSessionCreatedTimeInMillis(@NonNull final SessionInfo info) {
+        try {
+            return (long) SessionInfo.class.getDeclaredMethod("getCreatedMillis").invoke(info);
+        } catch (Exception e) {
+            return 0;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 3758cb8..6cae43d 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -35,7 +35,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.popup.PopupDataProvider;
-import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.uioverrides.WallpaperColorInfo;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -91,7 +90,6 @@
 
     @Override
     public boolean onLongClick(View v) {
-        TestLogging.recordEvent("Widgets.onLongClick");
         if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
 
         if (v instanceof WidgetCell) {
diff --git a/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java b/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java
new file mode 100644
index 0000000..56c885d
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 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.launcher3.util.rule;
+
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import androidx.test.uiautomator.UiDevice;
+
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+class FailureInvestigator {
+    private static boolean matches(String regex, CharSequence string) {
+        return Pattern.compile(regex).matcher(string).find();
+    }
+
+    static int getBugForFailure(CharSequence exception, String testsStartTime) {
+        final String logSinceTestsStart;
+        try {
+            logSinceTestsStart =
+                    UiDevice.getInstance(getInstrumentation())
+                            .executeShellCommand("logcat -d -t " + testsStartTime.replace(" ", ""));
+        } catch (IOException e) {
+            return 0;
+        }
+
+        if (matches(
+                "java.lang.AssertionError: http://go/tapl : Tests are broken by a non-Launcher "
+                        + "system error: Phone is locked",
+                exception)) {
+            if (matches(
+                    "BroadcastQueue: Can't deliver broadcast to com.android.systemui.*Crashing it",
+                    logSinceTestsStart)) {
+                return 147845913;
+            }
+        }
+
+        return 0;
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index cdda0f0..feb89b9 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -8,10 +8,13 @@
 
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 public class FailureWatcher extends TestWatcher {
     private static final String TAG = "FailureWatcher";
@@ -35,6 +38,30 @@
         }
     }
 
+    private static final String testsStartTime =
+            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date());
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    base.evaluate();
+                } catch (Throwable e) {
+                    final int bug =
+                            FailureInvestigator.getBugForFailure(e.toString(), testsStartTime);
+                    if (bug == 0) throw e;
+
+                    Log.e(TAG, "Known bug found for the original failure "
+                            + android.util.Log.getStackTraceString(e));
+                    throw new AssertionError(
+                            "Detected a failure that matches a known bug b/" + bug);
+                }
+            }
+        };
+    }
+
     @Override
     protected void failed(Throwable e, Description description) {
         onError(mDevice, description, e);
diff --git a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
index 03d1600..afb50e0 100644
--- a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
+++ b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
@@ -37,8 +37,10 @@
     }
 
     public void addAutomatically() {
-        mLauncher.waitForObjectInContainer(
-                mWidgetCell.getParent().getParent().getParent().getParent(),
-                By.text(ADD_AUTOMATICALLY)).click();
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            mLauncher.waitForObjectInContainer(
+                    mWidgetCell.getParent().getParent().getParent().getParent(),
+                    By.text(ADD_AUTOMATICALLY)).click();
+        }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 3bdeb14..4a2d699 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -99,8 +99,9 @@
      */
     @NonNull
     public AppIcon getAppIcon(String appName) {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "getting app icon " + appName + " on all apps")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "getting app icon " + appName + " on all apps")) {
             final UiObject2 allAppsContainer = verifyActiveContainer();
             final UiObject2 appListRecycler = mLauncher.waitForObjectInContainer(allAppsContainer,
                     "apps_list_view");
@@ -130,6 +131,9 @@
                                 searchBox.getVisibleBounds().bottom
                                         - allAppsContainer.getVisibleBounds().top);
                         final int newScroll = getAllAppsScroll();
+                        mLauncher.assertTrue(
+                                "Scrolled in a wrong direction in AllApps: from " + scroll + " to "
+                                        + newScroll, newScroll >= scroll);
                         if (newScroll == scroll) break;
 
                         mLauncher.assertTrue(
@@ -197,7 +201,8 @@
      * Flings forward (down) and waits the fling's end.
      */
     public void flingForward() {
-        try (LauncherInstrumentation.Closable c =
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             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.
@@ -211,7 +216,8 @@
      * Flings backward (up) and waits the fling's end.
      */
     public void flingBackward() {
-        try (LauncherInstrumentation.Closable c =
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             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.
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
index f48d4dd..8f9fec9 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -42,8 +42,9 @@
      */
     @NonNull
     public Overview switchBackToOverview() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to switch back from all apps to overview")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             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(
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index bf68f71..0a6ed7f 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -22,15 +22,11 @@
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiObject2;
 
-import java.util.regex.Pattern;
-
 /**
  * App icon, whether in all apps or in workspace/
  */
 public final class AppIcon extends Launchable {
 
-    private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onAllAppsItemLongClick");
-
     AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
         super(launcher, icon);
     }
@@ -43,13 +39,10 @@
      * Long-clicks the icon to open its menu.
      */
     public AppIconMenu openMenu() {
-        return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
-                mObject, "deep_shortcuts_container"));
-    }
-
-    @Override
-    protected void addExpectedEventsForLongClick() {
-        mLauncher.expectEvent(LONG_CLICK_EVENT);
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            return new AppIconMenu(mLauncher, mLauncher.clickAndGet(
+                    mObject, "deep_shortcuts_container"));
+        }
     }
 
     @Override
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
index 597be90..ba9c10e 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIconMenuItem.java
@@ -34,10 +34,6 @@
     }
 
     @Override
-    protected void addExpectedEventsForLongClick() {
-    }
-
-    @Override
     protected String getLongPressIndicator() {
         return "drop_target_bar";
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index d9ae778..50bdf5c 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -52,8 +52,9 @@
      */
     @NonNull
     public BaseOverview switchToOverview() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to switch from background to overview")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to switch from background to overview")) {
             verifyActiveContainer();
             goToOverviewUnchecked();
             return mLauncher.isFallbackOverview() ?
@@ -124,8 +125,9 @@
      * Swipes right or double presses the square button to switch to the previous app.
      */
     public Background quickSwitchToPreviousApp() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to quick switch to the previous app")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to quick switch to the previous app")) {
             verifyActiveContainer();
             quickSwitchToPreviousApp(getExpectedStateForQuickSwitch());
             return new Background(mLauncher);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 339e14f..e13ea52 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -48,6 +48,12 @@
      * Flings forward (left) and waits the fling's end.
      */
     public void flingForward() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            flingForwardImpl();
+        }
+    }
+
+    private void flingForwardImpl() {
         try (LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to fling forward in overview")) {
             LauncherInstrumentation.log("Overview.flingForward before fling");
@@ -65,14 +71,15 @@
      * Dismissed all tasks by scrolling to Clear-all button and pressing it.
      */
     public void dismissAllTasks() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "dismissing all tasks")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "dismissing all tasks")) {
             final BySelector clearAllSelector = mLauncher.getOverviewObjectSelector("clear_all");
             for (int i = 0;
                     i < FLINGS_FOR_DISMISS_LIMIT
                             && !verifyActiveContainer().hasObject(clearAllSelector);
                     ++i) {
-                flingForward();
+                flingForwardImpl();
             }
 
             mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector).click();
@@ -83,7 +90,8 @@
      * Flings backward (right) and waits the fling's end.
      */
     public void flingBackward() {
-        try (LauncherInstrumentation.Closable c =
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to fling backward in overview")) {
             LauncherInstrumentation.log("Overview.flingBackward before fling");
             final UiObject2 overview = verifyActiveContainer();
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
index 1e4d937..1a0fe3d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Home.java
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -48,8 +48,9 @@
     @NonNull
     @Override
     public Overview switchToOverview() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to switch from home to overview")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to switch from home to overview")) {
             verifyActiveContainer();
             goToOverviewUnchecked();
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 9327cb3..f88a616 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -46,7 +46,9 @@
      * Clicks the object to launch its app.
      */
     public Background launch(String expectedPackageName) {
-        return launch(By.pkg(expectedPackageName));
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            return launch(By.pkg(expectedPackageName));
+        }
     }
 
     private Background launch(BySelector selector) {
@@ -73,7 +75,6 @@
             final Point launchableCenter = getObject().getVisibleCenter();
             final Point displaySize = mLauncher.getRealDisplaySize();
             final int width = displaySize.x / 2;
-            addExpectedEventsForLongClick();
             Workspace.dragIconToWorkspace(
                     mLauncher,
                     this,
@@ -86,7 +87,5 @@
         }
     }
 
-    protected abstract void addExpectedEventsForLongClick();
-
     protected abstract String getLongPressIndicator();
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index bd3671b..3670392 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -560,61 +560,63 @@
      * @return the Workspace object.
      */
     public Workspace pressHome() {
-        // Click home, then wait for any accessibility event, then wait until accessibility events
-        // stop.
-        // We need waiting for any accessibility event generated after pressing Home because
-        // otherwise waitForIdle may return immediately in case when there was a big enough pause in
-        // accessibility events prior to pressing Home.
-        final String action;
-        if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
-            checkForAnomaly();
+        try (LauncherInstrumentation.Closable e = eventsCheck()) {
+            // Click home, then wait for any accessibility event, then wait until accessibility
+            // events stop.
+            // We need waiting for any accessibility event generated after pressing Home because
+            // otherwise waitForIdle may return immediately in case when there was a big enough
+            // pause in accessibility events prior to pressing Home.
+            final String action;
+            if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
+                checkForAnomaly();
 
-            final Point displaySize = getRealDisplaySize();
+                final Point displaySize = getRealDisplaySize();
 
-            if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
-                linearGesture(
-                        displaySize.x / 2, displaySize.y - 1,
-                        displaySize.x / 2, 0,
-                        ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                        false);
-                try (LauncherInstrumentation.Closable c = addContextLayer(
-                        "Swiped up from context menu to home")) {
-                    waitUntilGone(CONTEXT_MENU_RES_ID);
-                }
-            }
-            if (hasLauncherObject(WORKSPACE_RES_ID)) {
-                log(action = "already at home");
-            } else {
-                log("Hierarchy before swiping up to home:");
-                dumpViewHierarchy();
-                log(action = "swiping up to home from " + getVisibleStateMessage());
-
-                try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
-                    swipeToState(
+                if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
+                    linearGesture(
                             displaySize.x / 2, displaySize.y - 1,
                             displaySize.x / 2, 0,
-                            ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL);
+                            ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+                            false);
+                    try (LauncherInstrumentation.Closable c = addContextLayer(
+                            "Swiped up from context menu to home")) {
+                        waitUntilGone(CONTEXT_MENU_RES_ID);
+                    }
+                }
+                if (hasLauncherObject(WORKSPACE_RES_ID)) {
+                    log(action = "already at home");
+                } else {
+                    log("Hierarchy before swiping up to home:");
+                    dumpViewHierarchy();
+                    log(action = "swiping up to home from " + getVisibleStateMessage());
+
+                    try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
+                        swipeToState(
+                                displaySize.x / 2, displaySize.y - 1,
+                                displaySize.x / 2, 0,
+                                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL);
+                    }
+                }
+            } else {
+                log("Hierarchy before clicking home:");
+                dumpViewHierarchy();
+                log(action = "clicking home button from " + getVisibleStateMessage());
+                try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
+                    mDevice.waitForIdle();
+                    runToState(
+                            waitForSystemUiObject("home")::click,
+                            NORMAL_STATE_ORDINAL,
+                            !hasLauncherObject(WORKSPACE_RES_ID)
+                                    && (hasLauncherObject(APPS_RES_ID)
+                                    || hasLauncherObject(OVERVIEW_RES_ID)));
+                    mDevice.waitForIdle();
                 }
             }
-        } else {
-            log("Hierarchy before clicking home:");
-            dumpViewHierarchy();
-            log(action = "clicking home button from " + getVisibleStateMessage());
-            try (LauncherInstrumentation.Closable c = addContextLayer(action)) {
-                mDevice.waitForIdle();
-                runToState(
-                        waitForSystemUiObject("home")::click,
-                        NORMAL_STATE_ORDINAL,
-                        !hasLauncherObject(WORKSPACE_RES_ID)
-                                && (hasLauncherObject(APPS_RES_ID)
-                                || hasLauncherObject(OVERVIEW_RES_ID)));
-                mDevice.waitForIdle();
+            try (LauncherInstrumentation.Closable c = addContextLayer(
+                    "performed action to switch to Home - " + action)) {
+                return getWorkspace();
             }
         }
-        try (LauncherInstrumentation.Closable c = addContextLayer(
-                "performed action to switch to Home - " + action)) {
-            return getWorkspace();
-        }
     }
 
     /**
@@ -1221,6 +1223,6 @@
     private String formatEventMismatchMessage(String message, List<String> actual, int position) {
         return message + ", pos=" + position
                 + ", expected=" + mExpectedEvents
-                + ", actual" + actual;
+                + ", actual=" + actual;
     }
 }
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
index 8527d05..461610d 100644
--- a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
+++ b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenuItem.java
@@ -35,12 +35,14 @@
      */
     @NonNull
     public void launch(@NonNull String expectedPackageName) {
-        LauncherInstrumentation.log("OptionsPopupMenuItem before click "
-                + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
-        mObject.click();
-        mLauncher.assertTrue(
-                "App didn't start: " + By.pkg(expectedPackageName),
-                mLauncher.getDevice().wait(Until.hasObject(By.pkg(expectedPackageName)),
-                        LauncherInstrumentation.WAIT_TIME_MS));
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            LauncherInstrumentation.log("OptionsPopupMenuItem before click "
+                    + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
+            mObject.click();
+            mLauncher.assertTrue(
+                    "App didn't start: " + By.pkg(expectedPackageName),
+                    mLauncher.getDevice().wait(Until.hasObject(By.pkg(expectedPackageName)),
+                            LauncherInstrumentation.WAIT_TIME_MS));
+        }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
index 16a64a7..6622c6e 100644
--- a/tests/tapl/com/android/launcher3/tapl/Overview.java
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -45,8 +45,9 @@
      */
     @NonNull
     public AllAppsFromOverview switchToAllApps() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to switch from overview to all apps")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to switch from overview to all apps")) {
             verifyActiveContainer();
 
             // Swipe from an app icon to the top.
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 46f8ba5..0d93cbc 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -45,8 +45,9 @@
      * Swipes the task up.
      */
     public void dismiss() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to dismiss a task")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to dismiss a task")) {
             verifyActiveContainer();
             // Dismiss the task via flinging it up.
             final Rect taskBounds = mTask.getVisibleBounds();
@@ -61,15 +62,17 @@
      * Clicks at the task.
      */
     public Background open() {
-        verifyActiveContainer();
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "clicking an overview task")) {
-            mLauncher.executeAndWaitForEvent(
-                    () -> mTask.click(),
-                    event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
-                    () -> "Launching task didn't open a new window: "
-                            + mTask.getParent().getContentDescription());
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            verifyActiveContainer();
+            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                    "clicking an overview task")) {
+                mLauncher.executeAndWaitForEvent(
+                        () -> mTask.click(),
+                        event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
+                        () -> "Launching task didn't open a new window: "
+                                + mTask.getParent().getContentDescription());
+            }
+            return new Background(mLauncher);
         }
-        return new Background(mLauncher);
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Widget.java b/tests/tapl/com/android/launcher3/tapl/Widget.java
index e0db16d..dfd74ed 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widget.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widget.java
@@ -18,15 +18,11 @@
 
 import androidx.test.uiautomator.UiObject2;
 
-import java.util.regex.Pattern;
-
 /**
  * Widget in workspace or a widget list.
  */
 public final class Widget extends Launchable {
 
-    private static final Pattern LONG_CLICK_EVENT = Pattern.compile("Widgets.onLongClick");
-
     Widget(LauncherInstrumentation launcher, UiObject2 icon) {
         super(launcher, icon);
     }
@@ -35,9 +31,4 @@
     protected String getLongPressIndicator() {
         return "drop_target_bar";
     }
-
-    @Override
-    protected void addExpectedEventsForLongClick() {
-        mLauncher.expectEvent(LONG_CLICK_EVENT);
-    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index d208c66..ede5bd9 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -41,8 +41,9 @@
      * Flings forward (down) and waits the fling's end.
      */
     public void flingForward() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to fling forward in widgets")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to fling forward in widgets")) {
             LauncherInstrumentation.log("Widgets.flingForward enter");
             final UiObject2 widgetsContainer = verifyActiveContainer();
             mLauncher.scroll(
@@ -62,8 +63,9 @@
      * Flings backward (up) and waits the fling's end.
      */
     public void flingBackward() {
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                "want to fling backwards in widgets")) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to fling backwards in widgets")) {
             LauncherInstrumentation.log("Widgets.flingBackward enter");
             final UiObject2 widgetsContainer = verifyActiveContainer();
             mLauncher.scroll(
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index af7e552..1d2c821 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -85,7 +85,8 @@
      */
     @NonNull
     public AllApps switchToAllApps() {
-        try (LauncherInstrumentation.Closable c =
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to switch from workspace to all apps")) {
             verifyActiveContainer();
             final int deviceHeight = mLauncher.getDevice().getDisplayHeight();
@@ -156,21 +157,23 @@
      * second screen.
      */
     public void ensureWorkspaceIsScrollable() {
-        final UiObject2 workspace = verifyActiveContainer();
-        if (!isWorkspaceScrollable(workspace)) {
-            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                    "dragging icon to a second page of workspace to make it scrollable")) {
-                dragIconToWorkspace(
-                        mLauncher,
-                        getHotseatAppIcon("Chrome"),
-                        new Point(mLauncher.getDevice().getDisplayWidth(),
-                                workspace.getVisibleBounds().centerY()),
-                        "deep_shortcuts_container");
-                verifyActiveContainer();
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            final UiObject2 workspace = verifyActiveContainer();
+            if (!isWorkspaceScrollable(workspace)) {
+                try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                        "dragging icon to a second page of workspace to make it scrollable")) {
+                    dragIconToWorkspace(
+                            mLauncher,
+                            getHotseatAppIcon("Chrome"),
+                            new Point(mLauncher.getDevice().getDisplayWidth(),
+                                    workspace.getVisibleBounds().centerY()),
+                            "deep_shortcuts_container");
+                    verifyActiveContainer();
+                }
             }
+            assertTrue("Home screen workspace didn't become scrollable",
+                    isWorkspaceScrollable(workspace));
         }
-        assertTrue("Home screen workspace didn't become scrollable",
-                isWorkspaceScrollable(workspace));
     }
 
     private boolean isWorkspaceScrollable(UiObject2 workspace) {
@@ -213,11 +216,13 @@
      * recoil to complete.
      */
     public void flingForward() {
-        final UiObject2 workspace = verifyActiveContainer();
-        mLauncher.scroll(workspace, Direction.RIGHT,
-                new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0),
-                FLING_STEPS, false);
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            final UiObject2 workspace = verifyActiveContainer();
+            mLauncher.scroll(workspace, Direction.RIGHT,
+                    new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0),
+                    FLING_STEPS, false);
+            verifyActiveContainer();
+        }
     }
 
     /**
@@ -225,11 +230,13 @@
      * recoil to complete.
      */
     public void flingBackward() {
-        final UiObject2 workspace = verifyActiveContainer();
-        mLauncher.scroll(workspace, Direction.LEFT,
-                new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0),
-                FLING_STEPS, false);
-        verifyActiveContainer();
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            final UiObject2 workspace = verifyActiveContainer();
+            mLauncher.scroll(workspace, Direction.LEFT,
+                    new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0),
+                    FLING_STEPS, false);
+            verifyActiveContainer();
+        }
     }
 
     /**
@@ -239,10 +246,12 @@
      */
     @NonNull
     public Widgets openAllWidgets() {
-        verifyActiveContainer();
-        mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
-        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
-            return new Widgets(mLauncher);
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            verifyActiveContainer();
+            mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
+            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
+                return new Widgets(mLauncher);
+            }
         }
     }