Fixing animation jittering during swipe-up

AnimatorPlaybackController was using setCurrentPlayTime to control animation,
which converts progress (float) to duration (long) causing the progress to
loose accuracy.
Instead calling setCurrentFraction(float) on the target animation.

Bug: 155164803
Change-Id: I3e4c93c5a75a9ba16e80adee97229c974ffc86b1
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index e11917b..ea0ff8b 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.anim;
 
+import static com.android.launcher3.Utilities.boundToRange;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
@@ -30,8 +31,6 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.Utilities;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -54,11 +53,8 @@
      * to float (animation-fraction * total duration) to int conversion.
      */
     public static AnimatorPlaybackController wrap(AnimatorSet anim, long duration) {
-        /**
-         * TODO: use {@link AnimatorSet#setCurrentPlayTime(long)} once b/68382377 is fixed.
-         */
         ArrayList<Holder> childAnims = new ArrayList<>();
-        addAnimationHoldersRecur(anim, SpringProperty.DEFAULT, childAnims);
+        addAnimationHoldersRecur(anim, duration, SpringProperty.DEFAULT, childAnims);
 
         return new AnimatorPlaybackController(anim, duration, childAnims);
     }
@@ -152,7 +148,7 @@
         float scaleInverse = 1 / Math.abs(scale);
         float scaledVelocity = velocity * scaleInverse;
 
-        float nextFrameProgress = Utilities.boundToRange(getProgressFraction()
+        float nextFrameProgress = boundToRange(getProgressFraction()
                 + scaledVelocity * getSingleFrameMs(context), 0f, 1f);
 
         // Update setters for spring
@@ -176,8 +172,8 @@
                 springDuration = Math.max(expectedDurationL, springDuration);
 
                 float expectedDuration = expectedDurationL;
-                h.setter = (a, l) -> a.setCurrentFraction(
-                        mAnimationPlayer.getCurrentPlayTime() / expectedDuration);
+                h.mapper = (progress, globalEndProgress) ->
+                        mAnimationPlayer.getCurrentPlayTime() / expectedDuration;
                 h.anim.setInterpolator(s::getInterpolatedValue);
             }
         }
@@ -237,9 +233,9 @@
         if (mTargetCancelled) {
             return;
         }
-        long playPos = clampDuration(fraction);
+        float progress = boundToRange(fraction, 0, 1);
         for (Holder holder : mChildAnimations) {
-            holder.setter.set(holder.anim, playPos);
+            holder.setProgress(progress);
         }
     }
 
@@ -361,14 +357,14 @@
     }
 
     /**
-     * Interface for setting position of value animator
+     * Interface for mapping progress to animation progress
      */
-    private interface PositionSetter {
+    private interface ProgressMapper {
 
-        PositionSetter DEFAULT = (anim, playPos) ->
-                anim.setCurrentPlayTime(Math.min(playPos, anim.getDuration()));
+        ProgressMapper DEFAULT = (progress, globalEndProgress) ->
+                progress > globalEndProgress ? 1 : (progress / globalEndProgress);
 
-        void set(ValueAnimator anim, long position);
+        float getProgress(float progress, float globalProgress);
     }
 
     /**
@@ -382,27 +378,34 @@
 
         public final TimeInterpolator interpolator;
 
-        public PositionSetter setter;
+        public final float globalEndProgress;
 
-        Holder(Animator anim, SpringProperty springProperty) {
+        public ProgressMapper mapper;
+
+        Holder(Animator anim, float globalDuration, SpringProperty springProperty) {
             this.anim = (ValueAnimator) anim;
             this.springProperty = springProperty;
             this.interpolator = this.anim.getInterpolator();
-            this.setter = PositionSetter.DEFAULT;
+            this.globalEndProgress = anim.getDuration() / globalDuration;
+            this.mapper = ProgressMapper.DEFAULT;
+        }
+
+        public void setProgress(float progress) {
+            anim.setCurrentFraction(mapper.getProgress(progress, globalEndProgress));
         }
 
         public void reset() {
             anim.setInterpolator(interpolator);
-            setter = PositionSetter.DEFAULT;
+            mapper = ProgressMapper.DEFAULT;
         }
     }
 
-    static void addAnimationHoldersRecur(
-            Animator anim, SpringProperty springProperty, ArrayList<Holder> out) {
+    static void addAnimationHoldersRecur(Animator anim, long globalDuration,
+            SpringProperty springProperty, ArrayList<Holder> out) {
         long forceDuration = anim.getDuration();
         TimeInterpolator forceInterpolator = anim.getInterpolator();
         if (anim instanceof ValueAnimator) {
-            out.add(new Holder(anim, springProperty));
+            out.add(new Holder(anim, globalDuration, springProperty));
         } else if (anim instanceof AnimatorSet) {
             for (Animator child : ((AnimatorSet) anim).getChildAnimations()) {
                 if (forceDuration > 0) {
@@ -411,7 +414,7 @@
                 if (forceInterpolator != null) {
                     child.setInterpolator(forceInterpolator);
                 }
-                addAnimationHoldersRecur(child, springProperty, out);
+                addAnimationHoldersRecur(child, globalDuration, springProperty, out);
             }
         } else {
             throw new RuntimeException("Unknown animation type " + anim);
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 0f04104..afeb341 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -70,7 +70,7 @@
 
     public void add(Animator a, SpringProperty springProperty) {
         mAnim.play(a);
-        addAnimationHoldersRecur(a, springProperty, mAnimHolders);
+        addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders);
     }
 
     public void finish(boolean isSuccess, int logAction) {
@@ -150,7 +150,7 @@
         }
         if (mAnimHolders.isEmpty()) {
             // Add a dummy animation to that the duration is respected
-            add(ValueAnimator.ofFloat(0, 1));
+            add(ValueAnimator.ofFloat(0, 1).setDuration(mDuration));
         }
         return mAnim;
     }