Merge "Fix bug where view stays invisible due to view recycling before it gets reset." into ub-launcher3-rvc-dev
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 70b139d..fadde37 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -204,27 +204,23 @@
                     true /* freezeTaskList */);
         } else {
             int taskId = mRecentsView.getNextPageTaskView().getTask().key.id;
-            mFinishingRecentsAnimationForNewTaskId = taskId;
-            mRecentsAnimationController.finish(true /* toRecents */, () -> {
-                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());
-                    }
-                    mStateCallback.setStateOnUiThread(successStateFlag);
+            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());
                 }
-                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 8574cf1..31a2814 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/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 123c988..0f45196 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -62,10 +62,13 @@
 
     @Override
     public void setState(@NonNull LauncherState state) {
-        ScaleAndTranslation scaleAndTranslation = state
-                .getOverviewScaleAndTranslation(mLauncher);
+        ScaleAndTranslation scaleAndTranslation = state.getOverviewScaleAndTranslation(mLauncher);
+        float translationX = scaleAndTranslation.translationX;
+        if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+            translationX = -translationX;
+        }
         SCALE_PROPERTY.set(mRecentsView, scaleAndTranslation.scale);
-        mRecentsView.setTranslationX(scaleAndTranslation.translationX);
+        mRecentsView.setTranslationX(translationX);
         mRecentsView.setTranslationY(scaleAndTranslation.translationY);
 
         getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
@@ -96,9 +99,13 @@
     void setStateWithAnimationInternal(@NonNull final LauncherState toState,
             @NonNull StateAnimationConfig config, @NonNull PendingAnimation setter) {
         ScaleAndTranslation scaleAndTranslation = toState.getOverviewScaleAndTranslation(mLauncher);
+        float translationX = scaleAndTranslation.translationX;
+        if (mRecentsView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+            translationX = -translationX;
+        }
         setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndTranslation.scale,
                 config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
-        setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, scaleAndTranslation.translationX,
+        setter.setFloat(mRecentsView, VIEW_TRANSLATE_X, translationX,
                 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
         setter.setFloat(mRecentsView, VIEW_TRANSLATE_Y, scaleAndTranslation.translationY,
                 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
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/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 10f9feb..b0ce8e6 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -124,6 +124,17 @@
     }
 
     @Override
+    public void onRecentTaskListUpdated() {
+        // In some cases immediately after booting, the tasks in the system recent task list may be
+        // loaded, but not in the active task hierarchy in the system.  These tasks are displayed in 
+        // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
+        // callback (those are for changes to the active tasks), but the task list is still updated,
+        // so we should also invalidate the change id to ensure we load a new list instead of 
+        // reusing a stale list.
+        mChangeId++;
+    }
+
+    @Override
     public void onTaskRemoved(int taskId) {
         mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index d1dbcfb..7d568a4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -118,6 +118,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()) {
@@ -147,5 +157,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..5ece2d7 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -28,12 +28,14 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.util.Preconditions;
 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 */);
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index a7089fe..86faddb 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -162,7 +162,6 @@
         mLauncher.enableDebugTracing();
         // Avoid double-reporting of Launcher crashes.
         mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
-        mLauncher.disableSensorRotation();
     }
 
     protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -278,7 +277,6 @@
             clearPackageData(mDevice.getLauncherPackageName());
             mLauncher.enableDebugTracing();
             mLauncherPid = mLauncher.getPid();
-            mLauncher.disableSensorRotation();
         }
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 84eae2d..af22704 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1265,7 +1265,7 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
-    public void disableSensorRotation() {
+    private void disableSensorRotation() {
         getTestInfo(TestProtocol.REQUEST_MOCK_SENSOR_ROTATION);
     }