Merge "Fix launch animation issue for Desktop tile" into main
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 9178062..189deda 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -44,11 +44,13 @@
     /** Launch desktop tasks from recents view */
     fun launchDesktopFromRecents(
         desktopTaskView: DesktopTaskView,
+        animated: Boolean,
         callback: Consumer<Boolean>? = null
     ) {
         val animRunner =
             RemoteDesktopLaunchTransitionRunner(
                 desktopTaskView,
+                animated,
                 stateManager,
                 depthController,
                 callback
@@ -64,6 +66,7 @@
 
     private class RemoteDesktopLaunchTransitionRunner(
         private val desktopTaskView: DesktopTaskView,
+        private val animated: Boolean,
         private val stateManager: StateManager<*, *>,
         private val depthController: DepthController?,
         private val successCallback: Consumer<Boolean>?
@@ -84,16 +87,21 @@
             }
 
             MAIN_EXECUTOR.execute {
-                TaskViewUtils.composeRecentsDesktopLaunchAnimator(
-                    desktopTaskView,
-                    stateManager,
-                    depthController,
-                    info,
-                    t
-                ) {
-                    errorHandlingFinishCallback.run()
-                    successCallback?.accept(true)
+                val animator =
+                    TaskViewUtils.composeRecentsDesktopLaunchAnimator(
+                        desktopTaskView,
+                        stateManager,
+                        depthController,
+                        info,
+                        t
+                    ) {
+                        errorHandlingFinishCallback.run()
+                        successCallback?.accept(true)
+                    }
+                if (!animated) {
+                    animator.setDuration(0)
                 }
+                animator.start()
             }
         }
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 3c7f335..eafc5b6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -22,9 +22,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.VibrationEffect;
 import android.view.MotionEvent;
-import android.view.View;
 import android.view.animation.Interpolator;
 
 import com.android.app.animation.Interpolators;
@@ -67,7 +67,7 @@
     protected final CONTAINER mContainer;
     private final SingleAxisSwipeDetector mDetector;
     private final RecentsView mRecentsView;
-    private final int[] mTempCords = new int[2];
+    private final Rect mTempRect = new Rect();
     private final boolean mIsRtl;
 
     private AnimatorPlaybackController mCurrentAnimation;
@@ -252,10 +252,8 @@
                     mTaskBeingDragged, maxDuration, currentInterpolator);
 
             // Since the thumbnail is what is filling the screen, based the end displacement on it.
-            View thumbnailView = mTaskBeingDragged.getFirstSnapshotView();
-            mTempCords[1] = orientationHandler.getSecondaryDimension(thumbnailView);
-            dl.getDescendantCoordRelativeToSelf(thumbnailView, mTempCords);
-            mEndDisplacement = secondaryLayerDimension - mTempCords[1];
+            mTaskBeingDragged.getThumbnailBounds(mTempRect, /*relativeToDragLayer=*/true);
+            mEndDisplacement = secondaryLayerDimension - mTempRect.bottom;
         }
         mEndDisplacement *= verticalFactor;
         mCurrentAnimation = pa.createPlaybackController();
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index bd44283..1a09691 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -232,9 +232,13 @@
                         TaskViewSimulator::setTaskRectTranslation, taskRectTranslationPrimary,
                         taskRectTranslationSecondary);
 
-                // Fade in the task during the initial 20% of the animation
-                out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1,
-                        clampToProgress(LINEAR, 0, 0.2f));
+                if (v instanceof DesktopTaskView) {
+                    targetHandle.getTransformParams().setTargetAlpha(1f);
+                } else {
+                    // Fade in the task during the initial 20% of the animation
+                    out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0,
+                            1, clampToProgress(LINEAR, 0, 0.2f));
+                }
             }
         }
 
@@ -558,7 +562,7 @@
     /**
      * Start recents to desktop animation
      */
-    public static void composeRecentsDesktopLaunchAnimator(
+    public static AnimatorSet composeRecentsDesktopLaunchAnimator(
             @NonNull DesktopTaskView launchingTaskView,
             @NonNull StateManager stateManager, @Nullable DepthController depthController,
             @NonNull TransitionInfo transitionInfo,
@@ -588,7 +592,7 @@
                 true /* launcherClosing */, stateManager, launchingTaskView.getRecentsView(),
                 depthController);
 
-        animatorSet.start();
+        return animatorSet;
     }
 
     public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index d9b7d20..e5c54bb 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -171,7 +171,6 @@
             mTaskRect.set(mFullTaskSize);
             mOrientationState.getOrientationHandler()
                     .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
-            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
         } else if (mIsDesktopTask) {
             // For desktop, tasks can take up only part of the screen size.
             // Full task size represents the whole screen size, but scaled down to fit in recents.
@@ -185,10 +184,19 @@
             mTaskRect.scale(scale);
             // Ensure the task rect is inside the full task rect
             mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top);
+
+            Rect taskDimension = new Rect(0, 0, (int) fullscreenTaskDimension.x,
+                    (int) fullscreenTaskDimension.y);
+            mTmpCropRect.set(mThumbnailPosition);
+            if (mTmpCropRect.setIntersect(taskDimension, mThumbnailPosition)) {
+                mTmpCropRect.offset(-mThumbnailPosition.left, -mThumbnailPosition.top);
+            } else {
+                mTmpCropRect.setEmpty();
+            }
         } else {
             mTaskRect.set(mFullTaskSize);
-            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
         }
+        mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
     }
 
     /**
@@ -486,10 +494,12 @@
                 recentsViewPrimaryTranslation.value);
         applyWindowToHomeRotation(mMatrix);
 
-        // Crop rect is the inverse of thumbnail matrix
-        mTempRectF.set(0, 0, taskWidth, taskHeight);
-        mInversePositionMatrix.mapRect(mTempRectF);
-        mTempRectF.roundOut(mTmpCropRect);
+        if (!mIsDesktopTask) {
+            // Crop rect is the inverse of thumbnail matrix
+            mTempRectF.set(0, 0, taskWidth, taskHeight);
+            mInversePositionMatrix.mapRect(mTempRectF);
+            mTempRectF.roundOut(mTmpCropRect);
+        }
 
         params.setProgress(1f - fullScreenProgress);
         params.applySurfaceParams(surfaceTransaction == null
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index e242dfd..8e48f22 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -242,7 +242,7 @@
         }
     }
 
-    override fun launchTaskAnimated(): RunnableList? {
+    private fun launchTaskWithDesktopController(animated: Boolean): RunnableList? {
         val recentsView = recentsView ?: return null
         TestLogging.recordEvent(
             TestProtocol.SEQUENCE_MAIN,
@@ -252,17 +252,23 @@
         val endCallback = RunnableList()
         val desktopController = recentsView.desktopRecentsController
         checkNotNull(desktopController) { "recentsController is null" }
-        desktopController.launchDesktopFromRecents(this) { endCallback.executeAllAndDestroy() }
-        Log.d(TAG, "launchTaskAnimated - launchDesktopFromRecents: ${taskIds.contentToString()}")
+        desktopController.launchDesktopFromRecents(this, animated) {
+            endCallback.executeAllAndDestroy()
+        }
+        Log.d(
+            TAG,
+            "launchTaskAnimated - launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated"
+        )
 
         // Callbacks get run from recentsView for case when recents animation already running
         recentsView.addSideTaskLaunchCallback(endCallback)
         return endCallback
     }
 
+    override fun launchTaskAnimated() = launchTaskWithDesktopController(animated = true)
+
     override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) {
-        launchTasks()
-        callback(true)
+        launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false)
     }
 
     // Desktop tile can't be in split screen
@@ -272,8 +278,7 @@
     override fun setOverlayEnabled(overlayEnabled: Boolean) {}
 
     override fun onFullscreenProgressChanged(fullscreenProgress: Float) {
-        // Don't show background while we are transitioning to/from fullscreen
-        backgroundView.visibility = if (fullscreenProgress > 0) INVISIBLE else VISIBLE
+        backgroundView.alpha = 1 - fullscreenProgress
     }
 
     override fun updateCurrentFullscreenParams() {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5a6c278..53e6e72 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -40,6 +40,7 @@
 import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
@@ -57,6 +58,7 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
+import static com.android.quickstep.BaseContainerInterface.getTaskDimension;
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
 import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_DOWN;
@@ -90,6 +92,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -5232,23 +5235,37 @@
      * to the right.
      */
     @SuppressLint("Recycle")
-    public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
+    public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView taskView) {
         AnimatorSet anim = new AnimatorSet();
 
-        int taskIndex = indexOfChild(tv);
+        int taskIndex = indexOfChild(taskView);
         int centerTaskIndex = getCurrentPage();
 
         float toScale = getMaxScaleForFullScreen();
         boolean showAsGrid = showAsGrid();
-        boolean launchingCenterTask = showAsGrid
-                ? tv.isFocusedTask() && isTaskViewFullyVisible(tv)
+        boolean zoomInTaskView = showAsGrid
+                ? ((taskView.isFocusedTask() && isTaskViewFullyVisible(taskView))
+                || taskView instanceof DesktopTaskView)
                 : taskIndex == centerTaskIndex;
-        if (launchingCenterTask) {
+        if (zoomInTaskView) {
             anim.play(ObjectAnimator.ofFloat(this, RECENTS_SCALE_PROPERTY, toScale));
             anim.play(ObjectAnimator.ofFloat(this, FULLSCREEN_PROGRESS, 1));
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(@NonNull Animator animation, boolean isReverse) {
+                    taskView.getThumbnailBounds(mTempRect, /*relativeToDragLayer=*/true);
+                    getTaskDimension(mContext, mContainer.getDeviceProfile(), mTempPointF);
+                    Rect fullscreenBounds = new Rect(0, 0, (int) mTempPointF.x,
+                            (int) mTempPointF.y);
+                    Utilities.getPivotsForScalingRectToRect(mTempRect, fullscreenBounds,
+                            mTempPointF);
+                    setPivotX(mTempPointF.x);
+                    setPivotY(mTempPointF.y);
+                }
+            });
         } else if (!showAsGrid) {
             // We are launching an adjacent task, so parallax the center and other adjacent task.
-            float displacementX = tv.getWidth() * (toScale - 1f);
+            float displacementX = taskView.getWidth() * (toScale - 1f);
             float primaryTranslation = mIsRtl ? -displacementX : displacementX;
             anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
                     getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation));
@@ -5276,6 +5293,17 @@
             }
         }
         anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0, 1));
+        if (taskView instanceof DesktopTaskView) {
+            anim.play(ObjectAnimator.ofArgb(mContainer.getScrimView(), VIEW_BACKGROUND_COLOR,
+                    Color.TRANSPARENT));
+        }
+        DepthController depthController = getDepthController();
+        if (depthController != null) {
+            float targetDepth = taskView instanceof DesktopTaskView ? 0 : BACKGROUND_APP.getDepth(
+                    mContainer);
+            anim.play(ObjectAnimator.ofFloat(depthController.stateDepth, MULTI_PROPERTY_VALUE,
+                    targetDepth));
+        }
         return anim;
     }
 
@@ -5301,7 +5329,7 @@
     }
 
     public PendingAnimation createTaskLaunchAnimation(
-            TaskView tv, long duration, Interpolator interpolator) {
+            TaskView taskView, long duration, Interpolator interpolator) {
         if (FeatureFlags.IS_STUDIO_BUILD && mPendingAnimation != null) {
             throw new IllegalStateException("Another pending animation is still running");
         }
@@ -5316,13 +5344,13 @@
         updateGridProperties();
         updateScrollSynchronously();
 
-        int targetSysUiFlags = tv.getTaskContainers().getFirst().getSysUiStatusNavFlags();
+        int targetSysUiFlags = taskView.getTaskContainers().getFirst().getSysUiStatusNavFlags();
         final boolean[] passedOverviewThreshold = new boolean[]{false};
-        ValueAnimator progressAnim = ValueAnimator.ofFloat(0, 1);
-        progressAnim.addUpdateListener(animator -> {
+        AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(taskView);
+        anim.play(new AnimatedFloat(v -> {
             // Once we pass a certain threshold, update the sysui flags to match the target
             // tasks' flags
-            if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
+            if (v > UPDATE_SYSUI_FLAGS_THRESHOLD) {
                 mContainer.getSystemUiController().updateUiState(
                         UI_STATE_FULLSCREEN_TASK, targetSysUiFlags);
             } else {
@@ -5330,8 +5358,7 @@
             }
 
             // Passing the threshold from taskview to fullscreen app will vibrate
-            final boolean passed = animator.getAnimatedFraction() >=
-                    SUCCESS_TRANSITION_PROGRESS;
+            final boolean passed = v >= SUCCESS_TRANSITION_PROGRESS;
             if (passed != passedOverviewThreshold[0]) {
                 passedOverviewThreshold[0] = passed;
                 performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
@@ -5341,19 +5368,7 @@
                     mRecentsAnimationController.setWillFinishToHome(!passed);
                 }
             }
-        });
-
-        AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv);
-
-        DepthController depthController = getDepthController();
-        if (depthController != null) {
-            ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController.stateDepth,
-                    MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mContainer));
-            anim.play(depthAnimator);
-        }
-        anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0f, 1f));
-
-        anim.play(progressAnim);
+        }).animateToValue(0f, 1f));
         anim.setInterpolator(interpolator);
 
         mPendingAnimation = new PendingAnimation(duration);
@@ -5362,9 +5377,18 @@
                 remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
                         .addOverviewToAppAnim(mPendingAnimation, interpolator));
         mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
+        if (taskView instanceof DesktopTaskView && mRemoteTargetHandles != null) {
+            mPendingAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    runActionOnRemoteHandles(remoteTargetHandle ->
+                            remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
+                }
+            });
+        }
         mPendingAnimation.addEndListener(isSuccess -> {
             if (isSuccess) {
-                if (tv instanceof GroupedTaskView && hasAllValidTaskIds(tv.getTaskIds())
+                if (taskView instanceof GroupedTaskView && hasAllValidTaskIds(taskView.getTaskIds())
                         && mRemoteTargetHandles != null) {
                     // TODO(b/194414938): make this part of the animations instead.
                     TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
@@ -5374,13 +5398,13 @@
                                 dividerAnimator.end();
                             });
                 }
-                if (tv.isRunningTask()) {
+                if (taskView.isRunningTask()) {
                     finishRecentsAnimation(false /* toRecents */, null);
                     onTaskLaunchAnimationEnd(true /* success */);
                 } else {
-                    tv.launchTask(this::onTaskLaunchAnimationEnd);
+                    taskView.launchTask(this::onTaskLaunchAnimationEnd);
                 }
-                mContainer.getStatsLogManager().logger().withItemInfo(tv.getFirstItemInfo())
+                mContainer.getStatsLogManager().logger().withItemInfo(taskView.getFirstItemInfo())
                         .log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
             } else {
                 onTaskLaunchAnimationEnd(false);