Trigger onTaskAppeared when a task started from recents becomes ready.

Launcher can now receive onTaskAppeared callback from
RecentsAnimationController to get remote animation target when in quick
switch mode.

Note: This CL just demonstrates how to receive callback and then
calling removeTask & finish recents animation,
in order to really improve quick switch flicking, launcher side needs
to implement the rest of logic to animate task's remote animation target
to make task switching more smoothly.

Bug: 152480470
Test: WIP
Change-Id: Id0371db7339cfe84942cc905a89b0a2c1fab62ec
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 5abeae4..f81c56f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -212,36 +212,23 @@
                 Log.d(TestProtocol.NO_START_FROM_RECENTS, "startNewTask2");
             }
             int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
-            mFinishingRecentsAnimationForNewTaskId = taskId;
-            mRecentsAnimationController.finish(true /* toRecents */, () -> {
-                if (TestProtocol.sDebugTracing) {
-                    Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete1");
+            if (!mCanceled) {
+                TaskView nextTask = mRecentsView.getTaskView(taskId);
+                if (nextTask != null) {
+                    nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
+                            success -> {
+                                resultCallback.accept(success);
+                                if (!success) {
+                                    mActivityInterface.onLaunchTaskFailed();
+                                    nextTask.notifyTaskLaunchFailed(TAG);
+                                } else {
+                                    mActivityInterface.onLaunchTaskSuccess();
+                                }
+                            }, MAIN_EXECUTOR.getHandler());
                 }
-                if (!mCanceled) {
-                    if (TestProtocol.sDebugTracing) {
-                        Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete2");
-                    }
-                    TaskView nextTask = mRecentsView.getTaskView(taskId);
-                    if (nextTask != null) {
-                        if (TestProtocol.sDebugTracing) {
-                            Log.d(TestProtocol.NO_START_FROM_RECENTS, "onFinishComplete3");
-                        }
-                        nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
-                                success -> {
-                                    resultCallback.accept(success);
-                                    if (!success) {
-                                        mActivityInterface.onLaunchTaskFailed();
-                                        nextTask.notifyTaskLaunchFailed(TAG);
-                                    } else {
-                                        mActivityInterface.onLaunchTaskSuccess();
-                                    }
-                                }, MAIN_EXECUTOR.getHandler());
-                    }
-                    mStateCallback.setStateOnUiThread(successStateFlag);
-                }
-                mCanceled = false;
-                mFinishingRecentsAnimationForNewTaskId = -1;
-            });
+                mStateCallback.setStateOnUiThread(successStateFlag);
+            }
+            mCanceled = false;
         }
         ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
index 1bd0333..4cfa6f1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherSwipeHandler.java
@@ -30,6 +30,7 @@
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
 import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
+import static com.android.quickstep.GestureState.STATE_TASK_APPEARED_DURING_SWITCH;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
 import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
@@ -253,6 +254,8 @@
                         | STATE_RECENTS_SCROLLING_FINISHED,
                 this::onSettledOnEndTarget);
 
+        mGestureState.runOnceAtState(STATE_TASK_APPEARED_DURING_SWITCH, this::onTaskAppeared);
+
         mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
         mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                 this::invalidateHandlerWithLauncher);
@@ -727,6 +730,22 @@
         }
     }
 
+    private void onTaskAppeared() {
+        RemoteAnimationTargetCompat app = mGestureState.getAnimationTarget();
+        if (mRecentsAnimationController != null && app != null) {
+
+            // TODO(b/152480470): Update Task target animation after onTaskAppeared holistically.
+            /* android.util.Log.d("LauncherSwipeHandler", "onTaskAppeared");
+
+            final boolean result = mRecentsAnimationController.removeTaskTarget(app);
+            mGestureState.setAnimationTarget(null);
+            android.util.Log.d("LauncherSwipeHandler", "removeTask, result=" + result); */
+
+            mRecentsAnimationController.finish(false /* toRecents */,
+                    null /* onFinishComplete */);
+        }
+    }
+
     private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
             boolean isCancel) {
         final GestureEndTarget endTarget;
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 5118906..544f420 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -109,6 +110,9 @@
     public static final int STATE_RECENTS_SCROLLING_FINISHED =
             getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
 
+    // Called when the new task appeared from quick switching.
+    public static final int STATE_TASK_APPEARED_DURING_SWITCH =
+            getFlagForIndex("STATE_TASK_APPEARED_DURING_SWITCH");
 
     // Needed to interact with the current activity
     private final Intent mHomeIntent;
@@ -119,6 +123,7 @@
 
     private ActivityManager.RunningTaskInfo mRunningTask;
     private GestureEndTarget mEndTarget;
+    private RemoteAnimationTargetCompat mAnimationTarget;
     // TODO: This can be removed once we stop finishing the animation when starting a new task
     private int mFinishingRecentsAnimationTaskId = -1;
 
@@ -227,6 +232,14 @@
         return mEndTarget;
     }
 
+    public void setAnimationTarget(RemoteAnimationTargetCompat target) {
+        mAnimationTarget = target;
+    }
+
+    public RemoteAnimationTargetCompat getAnimationTarget() {
+        return mAnimationTarget;
+    }
+
     /**
      * Sets the end target of this gesture and immediately notifies the state changes.
      */
@@ -301,6 +314,12 @@
         mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
     }
 
+    @Override
+    public void onTaskAppeared(RemoteAnimationTargetCompat app) {
+        mAnimationTarget = app;
+        mStateCallback.setState(STATE_TASK_APPEARED_DURING_SWITCH);
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("GestureState:");
         pw.println("  gestureID=" + mGestureId);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 783978d..566a701 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -121,6 +121,16 @@
         });
     }
 
+    @BinderThread
+    @Override
+    public void onTaskAppeared(RemoteAnimationTargetCompat app) {
+        Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
+            for (RecentsAnimationListener listener : getListeners()) {
+                listener.onTaskAppeared(app);
+            }
+        });
+    }
+
     private final void onAnimationFinished(RecentsAnimationController controller) {
         Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
             for (RecentsAnimationListener listener : getListeners()) {
@@ -150,5 +160,10 @@
          * Callback made whenever the recents animation is finished.
          */
         default void onRecentsAnimationFinished(RecentsAnimationController controller) {}
+
+        /**
+         * Callback made when a task started from the recents is ready for an app transition.
+         */
+        default void onTaskAppeared(RemoteAnimationTargetCompat app) {}
     }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 8dd4aa4..268e564 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
+import android.annotation.NonNull;
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.InputEvent;
@@ -34,6 +35,7 @@
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.util.function.Consumer;
 import java.util.function.Supplier;
@@ -107,6 +109,15 @@
         UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot());
     }
 
+    /**
+     * Remove task remote animation target from
+     * {@link RecentsAnimationCallbacks#onTaskAppeared(RemoteAnimationTargetCompat)}}.
+     */
+    @UiThread
+    public boolean removeTaskTarget(@NonNull RemoteAnimationTargetCompat target) {
+        return mController.removeTask(target.taskId);
+    }
+
     @UiThread
     public void finishAnimationToHome() {
         finishAndClear(true /* toRecents */, null, false /* sendUserLeaveHint */);