Fix bugs with quickstep springs.

* Listeners weren't getting called properly. We add one listener to the
SpringbjectAnimator and then use that to dispatch to the other listeners.

* We fast finish on both double swipe cases to prevent the shelf from
  ending in an invalid state. This causes a visual jump but this can be
  addressed in follow up CL.

Bug: 111698021
Change-Id: Ifeb55da9dd253d062122a8e1577f94044f688641
This commit is contained in:
Jon Miranda
2019-01-28 15:00:46 -08:00
parent e0c5f5d0ab
commit f82fd49244
3 changed files with 50 additions and 7 deletions
@@ -25,6 +25,7 @@ import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRE
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
@@ -82,7 +83,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
if (mCurrentAnimation != null) {
if (mFinishFastOnSecondTouch) {
// TODO: Animate to finish instead.
mCurrentAnimation.getAnimationPlayer().end();
mCurrentAnimation.skipToEnd();
}
AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
@@ -241,7 +242,10 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
private void handleFirstSwipeToOverview(final ValueAnimator animator,
final long expectedDuration, final LauncherState targetState, final float velocity,
final boolean isFling) {
if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
if (QUICKSTEP_SPRINGS.get() && mFromState == OVERVIEW && mToState == ALL_APPS
&& targetState == OVERVIEW) {
mFinishFastOnSecondTouch = true;
} else if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
mFinishFastOnSecondTouch = true;
if (isFling && expectedDuration != 0) {
// Update all apps interpolator to add a bit of overshoot starting from currFraction
@@ -80,6 +80,9 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
private OnAnimationEndDispatcher mEndListener;
private DynamicAnimation.OnAnimationEndListener mSpringEndListener;
// We need this variable to ensure the end listener is called immediately, otherwise we run into
// issues where the callback interferes with the states of the swipe detector.
private boolean mSkipToEnd = false;
protected AnimatorPlaybackController(AnimatorSet anim, long duration,
Runnable onCancelRunnable) {
@@ -232,7 +235,11 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
}
private void dispatchOnStartRecursively(Animator animator) {
for (AnimatorListener l : nonNullList(animator.getListeners())) {
List<AnimatorListener> listeners = animator instanceof SpringObjectAnimator
? nonNullList(((SpringObjectAnimator) animator).getSuperListeners())
: nonNullList(animator.getListeners());
for (AnimatorListener l : listeners) {
l.onAnimationStart(animator);
}
@@ -280,6 +287,17 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
return mOnCancelRunnable;
}
public void skipToEnd() {
mSkipToEnd = true;
for (SpringAnimation spring : mSprings) {
if (spring.canSkipToEnd()) {
spring.skipToEnd();
}
}
mAnimationPlayer.end();
mSkipToEnd = false;
}
public static class AnimatorPlaybackControllerVL extends AnimatorPlaybackController {
private final ValueAnimator[] mChildAnimations;
@@ -343,19 +361,34 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
*/
private class OnAnimationEndDispatcher extends AnimationSuccessListener {
boolean mAnimatorDone = false;
boolean mSpringsDone = false;
boolean mDispatched = false;
@Override
public void onAnimationStart(Animator animation) {
mCancelled = false;
mDispatched = false;
}
@Override
public void onAnimationSuccess(Animator animator) {
if (mSprings.isEmpty()) {
mSpringsDone = mAnimatorDone = true;
}
if (isAnySpringRunning()) {
mAnimatorDone = true;
} else {
mSpringsDone = true;
}
// We wait for the spring (if any) to finish running before completing the end callback.
if (mSprings.isEmpty() || !isAnySpringRunning()) {
if (!mDispatched && (mSkipToEnd || (mAnimatorDone && mSpringsDone))) {
dispatchOnEndRecursively(mAnim);
if (mEndAction != null) {
mEndAction.run();
}
mDispatched = true;
}
}
@@ -73,7 +73,9 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
mListeners = new ArrayList<>();
setFloatValues(values);
mObjectAnimator.addListener(new AnimatorListenerAdapter() {
// We use this listener and track mListeners so that we can sync the animator and spring
// listeners.
super.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mAnimatorEnded = false;
@@ -94,7 +96,7 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
for (AnimatorListener l : mListeners) {
l.onAnimationCancel(animation);
}
mSpring.animateToFinalPosition(mObject.getProgress());
mSpring.cancel();
}
});
@@ -145,6 +147,10 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
mListeners.add(listener);
}
public ArrayList<AnimatorListener> getSuperListeners() {
return super.getListeners();
}
@Override
public ArrayList<AnimatorListener> getListeners() {
return mListeners;
@@ -167,8 +173,8 @@ public class SpringObjectAnimator<T extends ProgressInterface> extends ValueAnim
@Override
public void cancel() {
mSpring.animateToFinalPosition(mObject.getProgress());
mObjectAnimator.cancel();
mSpring.cancel();
}
@Override