Merge "Automatically diagnosing known flakes" into ub-launcher3-master
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/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/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/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index cab7f54..4a2d699 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -131,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(