Use RectFSpringAnim for auto-enter-pip

Make SwipePipToHomeAnimator a subclass of RectFSpringAnim and use the
bounds calculated from latter for auto-enter-pip transition.

Note that the landscape to portrait case may not fully comply to
RectFSpringAnim as we calculate the position separately in
SwipePipToHomeAnimator.

Video: http://recall/-/aaaaaabFQoRHlzixHdtY/CWBPU2A6vB8CeTFRanQLx
Bug: 184789411
Test: manual, see video
Change-Id: I67dae09e682b7d8f1a1f08995eb3bcf76bdf7417
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 8f42993..57dcad6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -45,8 +45,6 @@
 import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
-import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_END;
-import static com.android.quickstep.util.SwipePipToHomeAnimator.FRACTION_START;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -248,7 +246,6 @@
 
     private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
 
-    private static final long SWIPE_PIP_TO_HOME_DURATION = 425;
     private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
     protected boolean mIsSwipingPipToHome;
 
@@ -1127,17 +1124,14 @@
                     createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
                             runningTaskTarget);
             mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome() && appCanEnterPip;
+            final RectFSpringAnim windowAnim;
             if (mIsSwipingPipToHome) {
-                mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
+                mSwipePipToHomeAnimator = createWindowAnimationToPip(
                         homeAnimFactory, runningTaskTarget, start);
-                mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION);
-                mSwipePipToHomeAnimator.setInterpolator(interpolator);
-                mSwipePipToHomeAnimator.setFloatValues(FRACTION_START, FRACTION_END);
-                mSwipePipToHomeAnimator.start();
-                mRunningWindowAnim = RunningWindowAnim.wrap(mSwipePipToHomeAnimator);
+                windowAnim = mSwipePipToHomeAnimator;
             } else {
                 mSwipePipToHomeAnimator = null;
-                RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
+                windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
                 windowAnim.addAnimatorListener(new AnimationSuccessListener() {
                     @Override
                     public void onAnimationSuccess(Animator animator) {
@@ -1151,9 +1145,9 @@
                         mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
                     }
                 });
-                windowAnim.start(mContext, velocityPxPerMs);
-                mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
             }
+            windowAnim.start(mContext, velocityPxPerMs);
+            mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
             homeAnimFactory.setSwipeVelocity(velocityPxPerMs.y);
             homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
             mLauncherTransitionController = null;
@@ -1209,7 +1203,7 @@
         }
     }
 
-    private SwipePipToHomeAnimator getSwipePipToHomeAnimator(HomeAnimationFactory homeAnimFactory,
+    private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
             RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
         // Directly animate the app to PiP (picture-in-picture) mode
         final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask();
@@ -1222,16 +1216,15 @@
                         runningTaskTarget.taskInfo.pictureInPictureParams,
                         homeRotation,
                         mDp.hotseatBarSizePx);
-        final Rect startBounds = new Rect();
-        updateProgressForStartRect(new Matrix(), startProgress).round(startBounds);
         final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator(
+                mContext,
                 runningTaskTarget.taskId,
                 taskInfo.topActivity,
                 runningTaskTarget.leash.getSurfaceControl(),
                 TaskInfoCompat.getPipSourceRectHint(
                         runningTaskTarget.taskInfo.pictureInPictureParams),
                 TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
-                startBounds,
+                updateProgressForStartRect(new Matrix(), startProgress),
                 destinationBounds,
                 mRecentsView.getPipCornerRadius(),
                 mRecentsView);
@@ -1243,7 +1236,7 @@
         }
         AnimatorPlaybackController activityAnimationToHome =
                 homeAnimFactory.createActivityAnimationToHome();
-        swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() {
+        swipePipToHomeAnimator.addAnimatorListener(new AnimatorListenerAdapter() {
             private boolean mHasAnimationEnded;
             @Override
             public void onAnimationStart(Animator animation) {
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 61a2eaf..67a635b 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -20,8 +20,8 @@
 
 import android.animation.Animator;
 import android.animation.RectEvaluator;
-import android.animation.ValueAnimator;
 import android.content.ComponentName;
+import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -44,30 +44,24 @@
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 /**
- * An {@link Animator} that animates an Activity to PiP (picture-in-picture) window when
- * swiping up (in gesture navigation mode). Note that this class is derived from
- * {@link com.android.wm.shell.pip.PipAnimationController.PipTransitionAnimator}.
- *
- * TODO: consider sharing this class including the animator and leash operations between
- * Launcher and SysUI. Also, there should be one source of truth for the corner radius of the
- * PiP window, which would ideally be on SysUI side as well.
+ * Subclass of {@link RectFSpringAnim} that animates an Activity to PiP (picture-in-picture) window
+ * when swiping up (in gesture navigation mode).
  */
-public class SwipePipToHomeAnimator extends ValueAnimator {
+public class SwipePipToHomeAnimator extends RectFSpringAnim {
     private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
 
-    public static final float FRACTION_START = 0f;
-    public static final float FRACTION_END = 1f;
+    private static final float END_PROGRESS = 1.0f;
 
     private final int mTaskId;
     private final ComponentName mComponentName;
     private final SurfaceControl mLeash;
     private final Rect mAppBounds = new Rect();
     private final Rect mStartBounds = new Rect();
+    private final Rect mCurrentBounds = new Rect();
     private final Rect mDestinationBounds = new Rect();
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
 
-    /** for calculating the transform in {@link #onAnimationUpdate(ValueAnimator)} */
-    private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
+    /** for calculating transform in {@link #onAnimationUpdate(AppCloseConfig, RectF, float)} */
     private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
     private final Rect mSourceHintRectInsets;
     private final Rect mSourceInsets = new Rect();
@@ -90,6 +84,7 @@
     private SurfaceControl mContentOverlay;
 
     /**
+     * @param context {@link Context} provides Launcher resources
      * @param taskId Task id associated with this animator, see also {@link #getTaskId()}
      * @param componentName Component associated with this animator,
      *                      see also {@link #getComponentName()}
@@ -102,20 +97,22 @@
      * @param destinationBounds Bounds of the destination this animator ends to
      * @param cornerRadius Corner radius in pixel value for PiP window
      */
-    public SwipePipToHomeAnimator(int taskId,
+    public SwipePipToHomeAnimator(@NonNull Context context,
+            int taskId,
             @NonNull ComponentName componentName,
             @NonNull SurfaceControl leash,
             @Nullable Rect sourceRectHint,
             @NonNull Rect appBounds,
-            @NonNull Rect startBounds,
+            @NonNull RectF startBounds,
             @NonNull Rect destinationBounds,
             int cornerRadius,
             @NonNull View view) {
+        super(startBounds, new RectF(destinationBounds), context);
         mTaskId = taskId;
         mComponentName = componentName;
         mLeash = leash;
         mAppBounds.set(appBounds);
-        mStartBounds.set(startBounds);
+        startBounds.round(mStartBounds);
         mDestinationBounds.set(destinationBounds);
         mDestinationBoundsTransformed.set(mDestinationBounds);
         mDestinationBoundsAnimation.set(mDestinationBounds);
@@ -151,10 +148,10 @@
             t.reparent(mContentOverlay, mLeash);
             t.apply();
 
-            addUpdateListener(valueAnimator -> {
-                float alpha = valueAnimator.getAnimatedFraction() < 0.5f
+            addOnUpdateListener((values, currentRect, progress) -> {
+                float alpha = progress < 0.5f
                         ? 0
-                        : Utilities.mapToRange(valueAnimator.getAnimatedFraction(), 0.5f, 1f,
+                        : Utilities.mapToRange(Math.min(progress, 1f), 0.5f, 1f,
                                 0f, 1f, Interpolators.FAST_OUT_SLOW_IN);
                 t.setAlpha(mContentOverlay, alpha);
                 t.apply();
@@ -166,7 +163,7 @@
                     appBounds.bottom - sourceRectHint.bottom);
         }
 
-        addListener(new AnimationSuccessListener() {
+        addAnimatorListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
                 InteractionJankMonitorWrapper.begin(view, CUJ_APP_CLOSE_TO_PIP);
@@ -191,7 +188,7 @@
                 mHasAnimationEnded = true;
             }
         });
-        addUpdateListener(this::onAnimationUpdate);
+        addOnUpdateListener(this::onAnimationUpdate);
     }
 
     /** sets the from rotation if it's different from the target rotation. */
@@ -219,34 +216,34 @@
                 mAppBounds.top + mDestinationBounds.height());
     }
 
-    private void onAnimationUpdate(ValueAnimator animator) {
+    private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
+            float progress) {
         if (mHasAnimationEnded) return;
         final SurfaceControl.Transaction tx =
                 PipSurfaceTransactionHelper.newSurfaceControlTransaction();
-        onAnimationUpdate(tx, animator.getAnimatedFraction());
+        onAnimationUpdate(tx, currentRect, progress);
         tx.apply();
     }
 
     private PictureInPictureSurfaceTransaction onAnimationUpdate(SurfaceControl.Transaction tx,
-            float fraction) {
-        final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
-                mDestinationBoundsAnimation);
+            RectF currentRect, float progress) {
+        currentRect.round(mCurrentBounds);
         final PictureInPictureSurfaceTransaction op;
         if (mSourceHintRectInsets == null) {
             // no source rect hint been set, directly scale the window down
-            op = onAnimationScale(fraction, tx, bounds);
+            op = onAnimationScale(progress, tx, mCurrentBounds);
         } else {
             // scale and crop according to the source rect hint
-            op = onAnimationScaleAndCrop(fraction, tx, bounds);
+            op = onAnimationScaleAndCrop(progress, tx, mCurrentBounds);
         }
         return op;
     }
 
     /** scale the window directly with no source rect hint being set */
     private PictureInPictureSurfaceTransaction onAnimationScale(
-            float fraction, SurfaceControl.Transaction tx, Rect bounds) {
+            float progress, SurfaceControl.Transaction tx, Rect bounds) {
         if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
-            final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+            final RotatedPosition rotatedPosition = getRotatedPosition(progress);
             return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
                     rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
         } else {
@@ -256,12 +253,12 @@
 
     /** scale and crop the window with source rect hint */
     private PictureInPictureSurfaceTransaction onAnimationScaleAndCrop(
-            float fraction, SurfaceControl.Transaction tx,
+            float progress, SurfaceControl.Transaction tx,
             Rect bounds) {
-        final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
+        final Rect insets = mInsetsEvaluator.evaluate(progress, mSourceInsets,
                 mSourceHintRectInsets);
         if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
-            final RotatedPosition rotatedPosition = getRotatedPosition(fraction);
+            final RotatedPosition rotatedPosition = getRotatedPosition(progress);
             return mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
                     rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
         } else {
@@ -291,22 +288,22 @@
         // get the final leash operations but do not apply to the leash.
         final SurfaceControl.Transaction tx =
                 PipSurfaceTransactionHelper.newSurfaceControlTransaction();
-        return onAnimationUpdate(tx, FRACTION_END);
+        return onAnimationUpdate(tx, new RectF(mDestinationBounds), END_PROGRESS);
     }
 
-    private RotatedPosition getRotatedPosition(float fraction) {
+    private RotatedPosition getRotatedPosition(float progress) {
         final float degree, positionX, positionY;
         if (mFromRotation == Surface.ROTATION_90) {
-            degree = -90 * fraction;
-            positionX = fraction * (mDestinationBoundsTransformed.left - mStartBounds.left)
+            degree = -90 * progress;
+            positionX = progress * (mDestinationBoundsTransformed.left - mStartBounds.left)
                     + mStartBounds.left;
-            positionY = fraction * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
+            positionY = progress * (mDestinationBoundsTransformed.bottom - mStartBounds.top)
                     + mStartBounds.top;
         } else {
-            degree = 90 * fraction;
-            positionX = fraction * (mDestinationBoundsTransformed.right - mStartBounds.left)
+            degree = 90 * progress;
+            positionX = progress * (mDestinationBoundsTransformed.right - mStartBounds.left)
                     + mStartBounds.left;
-            positionY = fraction * (mDestinationBoundsTransformed.top - mStartBounds.top)
+            positionY = progress * (mDestinationBoundsTransformed.top - mStartBounds.top)
                     + mStartBounds.top;
         }
         return new RotatedPosition(degree, positionX, positionY);