Prevent multiple calls to finish on the recents controller

Bug: 186246362
Test: Verify from logs that we don't finish the controller
      multiple times
Change-Id: I8d40a756216133b8a278a28b822cf75c6e2a3046
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;