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;
}