diff options
author | Chet Haase <chet@google.com> | 2014-12-02 17:51:34 -0800 |
---|---|---|
committer | Chet Haase <chet@google.com> | 2014-12-04 15:09:01 -0800 |
commit | f4e3bab9253bba2c0086c35f4e5a1f7e41324876 (patch) | |
tree | 3ed907fbd1956ae7aae6052139bdcb01e1aedb0e /core/java/android/animation | |
parent | 8d72046b9ba06feadbcf71815a1c6e1017c8da37 (diff) | |
download | frameworks_base-f4e3bab9253bba2c0086c35f4e5a1f7e41324876.zip frameworks_base-f4e3bab9253bba2c0086c35f4e5a1f7e41324876.tar.gz frameworks_base-f4e3bab9253bba2c0086c35f4e5a1f7e41324876.tar.bz2 |
Fix seeking behavior
A recent fix to seeking behavior injected a couple of issues that need
to be addressed:
- the start time should be updated when seeking so that future calculations
that depend on it (such as the next animation frame) will use the updated
start time based on this seek request. This allows, for example, seeking
into a running animator so that that animator will update its current fraction
to the new seeked value.
- calling reverse() on an unstarted animation would incorrectly set the initial
frame of the animation to the end value for one frame before the reverse animation
actually began.
Issue #18567716 No icons in folders in battery saving mode
Issue #18511989 Search bar flashes when icon is picked up and dropped
Change-Id: Ie30b7e797468c6ccb3d17d4fb3aba6b9849436b0
Diffstat (limited to 'core/java/android/animation')
-rw-r--r-- | core/java/android/animation/ValueAnimator.java | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index e18aa5c..5a44a74 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -114,6 +114,15 @@ public class ValueAnimator extends Animator { private boolean mPlayingBackwards = false; /** + * Flag to indicate whether this animator is playing in reverse mode, specifically + * by being started or interrupted by a call to reverse(). This flag is different than + * mPlayingBackwards, which indicates merely whether the current iteration of the + * animator is playing in reverse. It is used in corner cases to determine proper end + * behavior. + */ + private boolean mReversing; + + /** * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the * repeatCount (if repeatCount!=INFINITE), the animation ends */ @@ -545,21 +554,51 @@ public class ValueAnimator extends Animator { * Sets the position of the animation to the specified fraction. This fraction should * be between 0 and the total fraction of the animation, including any repetition. That is, * a fraction of 0 will position the animation at the beginning, a value of 1 at the end, - * and a value of 2 at the beginning of a reversing animator that repeats once. If + * and a value of 2 at the end of a reversing animator that repeats once. If * the animation has not yet been started, then it will not advance forward after it is * set to this fraction; it will simply set the fraction to this value and perform any * appropriate actions based on that fraction. If the animation is already running, then * setCurrentFraction() will set the current fraction to this value and continue - * playing from that point. + * playing from that point. {@link AnimatorListener} events are not called + * due to changing the fraction; those events are only processed while the animation + * is running. * - * @param fraction The fraction to which the animation is advanced or rewound. + * @param fraction The fraction to which the animation is advanced or rewound. Values + * outside the range of 0 to the maximum fraction for the animator will be clamped to + * the correct range. */ public void setCurrentFraction(float fraction) { initAnimation(); + if (fraction < 0) { + fraction = 0; + } + int iteration = (int) fraction; + if (fraction == 1) { + iteration -= 1; + } else if (fraction > 1) { + if (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE) { + if (mRepeatMode == REVERSE) { + mPlayingBackwards = (iteration % 2) != 0; + } + fraction = fraction % 1f; + } else { + fraction = 1; + iteration -= 1; + } + } else { + mPlayingBackwards = mReversing; + } + mCurrentIteration = iteration; + long seekTime = (long) (mDuration * fraction); + long currentTime = AnimationUtils.currentAnimationTimeMillis(); + mStartTime = currentTime - seekTime; if (mPlayingState != RUNNING) { mSeekFraction = fraction; mPlayingState = SEEKED; } + if (mPlayingBackwards) { + fraction = 1f - fraction; + } animateValue(fraction); } @@ -962,8 +1001,30 @@ public class ValueAnimator extends Animator { if (Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } + mReversing = playBackwards; mPlayingBackwards = playBackwards; - mCurrentIteration = 0; + if (playBackwards && mSeekFraction != -1) { + if (mSeekFraction == 0 && mCurrentIteration == 0) { + // special case: reversing from seek-to-0 should act as if not seeked at all + mSeekFraction = 0; + } else if (mRepeatCount == INFINITE) { + mSeekFraction = 1 - (mSeekFraction % 1); + } else { + mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction); + } + mCurrentIteration = (int) mSeekFraction; + mSeekFraction = mSeekFraction % 1; + } + if (mCurrentIteration > 0 && mRepeatMode == REVERSE && + (mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) { + // if we were seeked to some other iteration in a reversing animator, + // figure out the correct direction to start playing based on the iteration + if (playBackwards) { + mPlayingBackwards = (mCurrentIteration % 2) == 0; + } else { + mPlayingBackwards = (mCurrentIteration % 2) != 0; + } + } int prevPlayingState = mPlayingState; mPlayingState = STOPPED; mStarted = true; @@ -1071,6 +1132,7 @@ public class ValueAnimator extends Animator { long currentPlayTime = currentTime - mStartTime; long timeLeft = mDuration - currentPlayTime; mStartTime = currentTime - timeLeft; + mReversing = !mReversing; } else if (mStarted) { end(); } else { @@ -1113,6 +1175,8 @@ public class ValueAnimator extends Animator { mStarted = false; mStartListenersCalled = false; mPlayingBackwards = false; + mReversing = false; + mCurrentIteration = 0; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), System.identityHashCode(this)); @@ -1201,8 +1265,16 @@ public class ValueAnimator extends Animator { case RUNNING: case SEEKED: float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; + if (mDuration == 0 && mRepeatCount != INFINITE) { + // Skip to the end + mCurrentIteration = mRepeatCount; + if (!mReversing) { + mPlayingBackwards = false; + } + } if (fraction >= 1f) { - if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { + if (mCurrentIteration < mRepeatCount || + (mRepeatCount == INFINITE && mDuration != 0)) { // Time to repeat if (mListeners != null) { int numListeners = mListeners.size(); @@ -1213,7 +1285,7 @@ public class ValueAnimator extends Animator { if (mRepeatMode == REVERSE) { mPlayingBackwards = !mPlayingBackwards; } - mCurrentIteration += (int)fraction; + mCurrentIteration += (int) fraction; fraction = fraction % 1f; mStartTime += mDuration; } else { @@ -1313,6 +1385,7 @@ public class ValueAnimator extends Animator { } anim.mSeekFraction = -1; anim.mPlayingBackwards = false; + anim.mReversing = false; anim.mCurrentIteration = 0; anim.mInitialized = false; anim.mPlayingState = STOPPED; |