Merge "[AA+] Add SearchResult type to ItemInfo attributes." into sc-dev
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9c79c32..61803aa 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -150,6 +150,9 @@
     protected Runnable mGestureEndCallback;
     protected MultiStateCallback mStateCallback;
     protected boolean mCanceled;
+    // One time flag set when onConsumerAboutToBeSwitched() is called, indicating that certain
+    // shared animations should not be canceled when this handler is invalidated
+    private boolean mConsumerIsSwitching;
     private boolean mRecentsViewScrollLinked = false;
 
     private static int getFlagForIndex(int index, String name) {
@@ -1002,7 +1005,14 @@
         animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocity);
     }
 
-    private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) {
+    private int getLogGestureTaskIndex(@Nullable TaskView targetTask) {
+        return mRecentsView == null || targetTask == null
+                ? LOG_NO_OP_PAGE_INDEX
+                : mRecentsView.indexOfChild(targetTask);
+    }
+
+    private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask,
+            int pageIndex) {
         StatsLogManager.EventEnum event;
         switch (endTarget) {
             case HOME:
@@ -1031,9 +1041,6 @@
             // We probably never received an animation controller, skip logging.
             return;
         }
-        int pageIndex = endTarget == LAST_TASK
-                ? LOG_NO_OP_PAGE_INDEX
-                : mRecentsView.getNextPage();
         // TODO: set correct container using the pageIndex
         logger.log(event);
     }
@@ -1278,18 +1285,18 @@
     }
 
     public void onConsumerAboutToBeSwitched() {
+        mConsumerIsSwitching = true;
         if (mActivity != null) {
             // In the off chance that the gesture ends before Launcher is started, we should clear
             // the callback here so that it doesn't update with the wrong state
             mActivity.clearRunOnceOnStartCallback();
-            resetLauncherListeners();
         }
         if (mGestureState.getEndTarget() != null && !mGestureState.isRunningAnimationToLauncher()) {
             cancelCurrentAnimation();
         } else {
             mStateCallback.setStateOnUiThread(STATE_FINISH_WITH_NO_END);
-            reset();
         }
+        reset();
     }
 
     public boolean isCanceled() {
@@ -1300,13 +1307,14 @@
     private void resumeLastTask() {
         mRecentsAnimationController.finish(false /* toRecents */, null);
         ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
-        doLogGesture(LAST_TASK, null);
+        doLogGesture(LAST_TASK, null, getLogGestureTaskIndex(null));
         reset();
     }
 
     @UiThread
     private void startNewTask() {
         TaskView taskToLaunch = mRecentsView == null ? null : mRecentsView.getNextPageTaskView();
+        int taskPageIndex = getLogGestureTaskIndex(taskToLaunch);
         startNewTask(success -> {
             if (!success) {
                 reset();
@@ -1315,7 +1323,7 @@
                 endLauncherTransitionController();
                 updateSysUiFlags(1 /* windowProgress == overview */);
             }
-            doLogGesture(NEW_TASK, taskToLaunch);
+            doLogGesture(NEW_TASK, taskToLaunch, taskPageIndex);
         });
     }
 
@@ -1349,32 +1357,38 @@
     }
 
     private void invalidateHandler() {
-        if (!LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode()
-                || mGestureState.getEndTarget() != RECENTS) {
-            mInputConsumerProxy.destroy();
-            mTaskAnimationManager.setLiveTileCleanUpHandler(null);
+        if (!mConsumerIsSwitching) {
+            if (!LIVE_TILE.get() || !mActivityInterface.isInLiveTileMode()
+                    || mGestureState.getEndTarget() != RECENTS) {
+                mInputConsumerProxy.destroy();
+                mTaskAnimationManager.setLiveTileCleanUpHandler(null);
+            }
+            endRunningWindowAnim(false /* cancel */);
+
+            if (mGestureEndCallback != null) {
+                mGestureEndCallback.run();
+            }
         }
+
         mInputConsumerProxy.unregisterCallback();
-        endRunningWindowAnim(false /* cancel */);
-
-        if (mGestureEndCallback != null) {
-            mGestureEndCallback.run();
-        }
-
         mActivityInitListener.unregister();
         ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mActivityRestartListener);
         mTaskSnapshot = null;
         mHandler.post(() -> {
             // Defer clearing the activity since invalidation can happen over multiple callbacks
+            // ie. invalidateHandlerWithLauncher()
             mActivity = null;
+            mRecentsView = null;
         });
     }
 
     private void invalidateHandlerWithLauncher() {
-        endLauncherTransitionController();
+        if (!mConsumerIsSwitching) {
+            endLauncherTransitionController();
+            mRecentsView.onGestureAnimationEnd();
+        }
 
         mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener);
-        mRecentsView.onGestureAnimationEnd();
         resetLauncherListeners();
     }
 
@@ -1499,7 +1513,8 @@
                     () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
         }
         ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
-        doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView());
+        TaskView taskToLaunch = mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView();
+        doLogGesture(HOME, taskToLaunch, getLogGestureTaskIndex(taskToLaunch));
     }
 
     /**
@@ -1530,7 +1545,8 @@
         }
 
         SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
-        doLogGesture(RECENTS, mRecentsView.getCurrentPageTaskView());
+        TaskView taskToLaunch = mRecentsView.getCurrentPageTaskView();
+        doLogGesture(RECENTS, taskToLaunch, getLogGestureTaskIndex(taskToLaunch));
         reset();
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 4560735..78da311 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -25,6 +25,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.RunnableList;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -43,6 +44,8 @@
 
     private boolean mUseLauncherSysBarFlags = false;
     private boolean mSplitScreenMinimized = false;
+    private boolean mFinishRequested = false;
+    private RunnableList mPendingFinishCallbacks = new RunnableList();
 
     public RecentsAnimationController(RecentsAnimationControllerCompat controller,
             boolean allowMinimizeSplitScreen,
@@ -132,14 +135,22 @@
 
     @UiThread
     public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
+        if (mFinishRequested) {
+            // If finishing, add to pending finish callbacks, otherwise, if finished, adding to the
+            // destroyed RunnableList will just trigger the callback to be called immediately
+            mPendingFinishCallbacks.add(callback);
+            return;
+        }
+
+        // Finish not yet requested
+        mFinishRequested = true;
         mOnFinishedListener.accept(this);
+        mPendingFinishCallbacks.add(callback);
         UI_HELPER_EXECUTOR.execute(() -> {
             mController.finish(toRecents, sendUserLeaveHint);
             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
-            if (callback != null) {
-                MAIN_EXECUTOR.execute(callback);
-            }
+            MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy);
         });
     }
 
diff --git a/src/com/android/launcher3/util/RunnableList.java b/src/com/android/launcher3/util/RunnableList.java
index 55add14..644537b 100644
--- a/src/com/android/launcher3/util/RunnableList.java
+++ b/src/com/android/launcher3/util/RunnableList.java
@@ -29,6 +29,9 @@
      * Ads a runnable to this list
      */
     public void add(Runnable runnable) {
+        if (runnable == null) {
+            return;
+        }
         if (mDestroyed) {
             runnable.run();
             return;