diff options
| -rw-r--r-- | core/java/android/animation/Animator.java | 5 | ||||
| -rw-r--r-- | core/java/android/animation/AnimatorSet.java | 136 | ||||
| -rw-r--r-- | core/java/android/animation/ValueAnimator.java | 75 |
3 files changed, 144 insertions, 72 deletions
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index 8142ee5806ca..a81ef18c8022 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -547,7 +547,6 @@ public abstract class Animator implements Cloneable { */ void skipToEndValue(boolean inReverse) {} - /** * Internal use only. * @@ -565,13 +564,13 @@ public abstract class Animator implements Cloneable { * repetition. lastPlayTime is similar and is used to calculate how many repeats have been * done between the two times. */ - void animateValuesInRange(long currentPlayTime, long lastPlayTime) {} + void animateValuesInRange(long currentPlayTime, long lastPlayTime, boolean notify) {} /** * Internal use only. This animates any animation that has ended since lastPlayTime. * If an animation hasn't been finished, no change will be made. */ - void animateSkipToEnds(long currentPlayTime, long lastPlayTime) {} + void animateSkipToEnds(long currentPlayTime, long lastPlayTime, boolean notify) {} /** * Internal use only. Adds all start times (after delay) to and end times to times. diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 54aaafc6c30a..257adfe390d6 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -188,6 +188,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim */ private long[] mChildStartAndStopTimes; + /** + * Tracks whether we've notified listeners of the onAnimationStart() event. + */ + private boolean mStartListenersCalled; + // This is to work around a bug in b/34736819. This needs to be removed once app team // fixes their side. private AnimatorListenerAdapter mAnimationEndListener = new AnimatorListenerAdapter() { @@ -736,19 +741,38 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim startAnimation(); } - if (mListeners != null) { + notifyStartListeners(inReverse); + if (isEmptySet) { + // In the case of empty AnimatorSet, or 0 duration scale, we will trigger the + // onAnimationEnd() right away. + end(); + } + } + + private void notifyStartListeners(boolean inReverse) { + if (mListeners != null && !mStartListenersCalled) { ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); int numListeners = tmpListeners.size(); for (int i = 0; i < numListeners; ++i) { - tmpListeners.get(i).onAnimationStart(this, inReverse); + AnimatorListener listener = tmpListeners.get(i); + listener.onAnimationStart(this, inReverse); } } - if (isEmptySet) { - // In the case of empty AnimatorSet, or 0 duration scale, we will trigger the - // onAnimationEnd() right away. - end(); + mStartListenersCalled = true; + } + + private void notifyEndListeners(boolean inReverse) { + if (mListeners != null && mStartListenersCalled) { + ArrayList<AnimatorListener> tmpListeners = + (ArrayList<AnimatorListener>) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + AnimatorListener listener = tmpListeners.get(i); + listener.onAnimationEnd(this, inReverse); + } } + mStartListenersCalled = false; } // Returns true if set is empty or contains nothing but animator sets with no start delay. @@ -823,7 +847,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim private void animateBasedOnPlayTime( long currentPlayTime, long lastPlayTime, - boolean inReverse + boolean inReverse, + boolean notify ) { if (currentPlayTime < 0 || lastPlayTime < -1) { throw new UnsupportedOperationException("Error: Play time should never be negative."); @@ -854,8 +879,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim while (index < endIndex) { long playTime = startEndTimes[index]; if (lastPlayTime != playTime) { - animateSkipToEnds(playTime, lastPlayTime); - animateValuesInRange(playTime, lastPlayTime); + animateSkipToEnds(playTime, lastPlayTime, notify); + animateValuesInRange(playTime, lastPlayTime, notify); lastPlayTime = playTime; } index++; @@ -865,15 +890,15 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim index--; long playTime = startEndTimes[index]; if (lastPlayTime != playTime) { - animateSkipToEnds(playTime, lastPlayTime); - animateValuesInRange(playTime, lastPlayTime); + animateSkipToEnds(playTime, lastPlayTime, notify); + animateValuesInRange(playTime, lastPlayTime, notify); lastPlayTime = playTime; } } } if (currentPlayTime != lastPlayTime) { - animateSkipToEnds(currentPlayTime, lastPlayTime); - animateValuesInRange(currentPlayTime, lastPlayTime); + animateSkipToEnds(currentPlayTime, lastPlayTime, notify); + animateValuesInRange(currentPlayTime, lastPlayTime, notify); } } @@ -893,10 +918,13 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } @Override - void animateSkipToEnds(long currentPlayTime, long lastPlayTime) { + void animateSkipToEnds(long currentPlayTime, long lastPlayTime, boolean notify) { initAnimation(); if (lastPlayTime > currentPlayTime) { + if (notify) { + notifyStartListeners(true); + } for (int i = mEvents.size() - 1; i >= 0; i--) { AnimationEvent event = mEvents.get(i); Node node = event.mNode; @@ -904,23 +932,31 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim && node.mStartTime != DURATION_INFINITE ) { Animator animator = node.mAnimation; - long start = node.mStartTime + animator.getStartDelay(); + long start = node.mStartTime; long end = node.mTotalDuration == DURATION_INFINITE ? Long.MAX_VALUE : node.mEndTime; if (currentPlayTime <= start && start < lastPlayTime) { animator.animateSkipToEnds( - start - node.mStartTime, - lastPlayTime - node.mStartTime + 0, + lastPlayTime - node.mStartTime, + notify ); } else if (start <= currentPlayTime && currentPlayTime <= end) { animator.animateSkipToEnds( currentPlayTime - node.mStartTime, - lastPlayTime - node.mStartTime + lastPlayTime - node.mStartTime, + notify ); } } } + if (currentPlayTime <= 0 && notify) { + notifyEndListeners(true); + } } else { + if (notify) { + notifyStartListeners(false); + } int eventsSize = mEvents.size(); for (int i = 0; i < eventsSize; i++) { AnimationEvent event = mEvents.get(i); @@ -929,29 +965,48 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim && node.mStartTime != DURATION_INFINITE ) { Animator animator = node.mAnimation; - long start = node.mStartTime + animator.getStartDelay(); + long start = node.mStartTime; long end = node.mTotalDuration == DURATION_INFINITE ? Long.MAX_VALUE : node.mEndTime; if (lastPlayTime < end && end <= currentPlayTime) { animator.animateSkipToEnds( end - node.mStartTime, - lastPlayTime - node.mStartTime + lastPlayTime - node.mStartTime, + notify ); } else if (start <= currentPlayTime && currentPlayTime <= end) { animator.animateSkipToEnds( currentPlayTime - node.mStartTime, - lastPlayTime - node.mStartTime + lastPlayTime - node.mStartTime, + notify ); } } } + if (currentPlayTime >= getTotalDuration() && notify) { + notifyEndListeners(false); + } } } @Override - void animateValuesInRange(long currentPlayTime, long lastPlayTime) { + void animateValuesInRange(long currentPlayTime, long lastPlayTime, boolean notify) { initAnimation(); + if (notify) { + if (lastPlayTime < 0 || (lastPlayTime == 0 && currentPlayTime > 0)) { + notifyStartListeners(false); + } else { + long duration = getTotalDuration(); + if (duration >= 0 + && (lastPlayTime > duration || (lastPlayTime == duration + && currentPlayTime < duration)) + ) { + notifyStartListeners(true); + } + } + } + int eventsSize = mEvents.size(); for (int i = 0; i < eventsSize; i++) { AnimationEvent event = mEvents.get(i); @@ -960,13 +1015,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim && node.mStartTime != DURATION_INFINITE ) { Animator animator = node.mAnimation; - long start = node.mStartTime + animator.getStartDelay(); + long start = node.mStartTime; long end = node.mTotalDuration == DURATION_INFINITE ? Long.MAX_VALUE : node.mEndTime; - if (start < currentPlayTime && currentPlayTime < end) { + if ((start < currentPlayTime && currentPlayTime < end) + || (start == currentPlayTime && lastPlayTime < start) + || (end == currentPlayTime && lastPlayTime > end) + ) { animator.animateValuesInRange( currentPlayTime - node.mStartTime, - Math.max(-1, lastPlayTime - node.mStartTime) + Math.max(-1, lastPlayTime - node.mStartTime), + notify ); } } @@ -1021,6 +1080,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim * set to this time; it will simply set the time to this value and perform any appropriate * actions based on that time. If the animation is already running, then setCurrentPlayTime() * will set the current playing time to this value and continue playing from that point. + * On {@link Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, an AnimatorSet + * that hasn't been {@link #start()}ed, will issue + * {@link android.animation.Animator.AnimatorListener#onAnimationStart(Animator, boolean)} + * and {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator, boolean)} + * events. * * @param playTime The time, in milliseconds, to which the animation is advanced or rewound. * Unless the animation is reversing, the playtime is considered the time since @@ -1042,12 +1106,12 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim initAnimation(); + long lastPlayTime = mSeekState.getPlayTime(); if (!isStarted() || isPaused()) { if (mReversing && !isStarted()) { throw new UnsupportedOperationException("Error: Something went wrong. mReversing" + " should not be set when AnimatorSet is not started."); } - long lastPlayTime = mSeekState.getPlayTime(); if (!mSeekState.isActive()) { findLatestEventIdForTime(0); initChildren(); @@ -1055,13 +1119,9 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim skipToEndValue(!mReversing); mSeekState.setPlayTime(0, mReversing); } - animateBasedOnPlayTime(playTime, lastPlayTime, mReversing); - mSeekState.setPlayTime(playTime, mReversing); - } else { - // If the animation is running, just set the seek time and wait until the next frame - // (i.e. doAnimationFrame(...)) to advance the animation. - mSeekState.setPlayTime(playTime, mReversing); } + animateBasedOnPlayTime(playTime, lastPlayTime, mReversing, true); + mSeekState.setPlayTime(playTime, mReversing); } /** @@ -1101,7 +1161,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim long previousTime = -1; for (long time : times) { - animateBasedOnPlayTime(time, previousTime, false); + animateBasedOnPlayTime(time, previousTime, false, false); previousTime = time; } } @@ -1397,15 +1457,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // No longer receive callbacks removeAnimationCallback(); - // Call end listener - if (mListeners != null) { - ArrayList<AnimatorListener> tmpListeners = - (ArrayList<AnimatorListener>) mListeners.clone(); - int numListeners = tmpListeners.size(); - for (int i = 0; i < numListeners; ++i) { - tmpListeners.get(i).onAnimationEnd(this, mReversing); - } - } + notifyEndListeners(mReversing); removeAnimationEndListener(); mSelfPulse = true; mReversing = false; diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index d41c03d9ab82..7009725aa32b 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1108,18 +1108,30 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio } } - private void notifyStartListeners() { + private void notifyStartListeners(boolean isReversing) { if (mListeners != null && !mStartListenersCalled) { ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); int numListeners = tmpListeners.size(); for (int i = 0; i < numListeners; ++i) { - tmpListeners.get(i).onAnimationStart(this, mReversing); + tmpListeners.get(i).onAnimationStart(this, isReversing); } } mStartListenersCalled = true; } + private void notifyEndListeners(boolean isReversing) { + if (mListeners != null && mStartListenersCalled) { + ArrayList<AnimatorListener> tmpListeners = + (ArrayList<AnimatorListener>) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationEnd(this, isReversing); + } + } + mStartListenersCalled = false; + } + /** * Start the animation playing. This version of start() takes a boolean flag that indicates * whether the animation should play in reverse. The flag is usually false, but may be set @@ -1210,7 +1222,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio if ((mStarted || mRunning) && mListeners != null) { if (!mRunning) { // If it's not yet running, then start listeners weren't called. Call them now. - notifyStartListeners(); + notifyStartListeners(mReversing); } int listenersSize = mListeners.size(); if (listenersSize > 0) { @@ -1324,22 +1336,14 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio boolean notify = (mStarted || mRunning) && mListeners != null; if (notify && !mRunning) { // If it's not yet running, then start listeners weren't called. Call them now. - notifyStartListeners(); + notifyStartListeners(mReversing); } mRunning = false; mStarted = false; - mStartListenersCalled = false; mLastFrameTime = -1; mFirstFrameTime = -1; mStartTime = -1; - if (notify && mListeners != null) { - ArrayList<AnimatorListener> tmpListeners = - (ArrayList<AnimatorListener>) mListeners.clone(); - int numListeners = tmpListeners.size(); - for (int i = 0; i < numListeners; ++i) { - tmpListeners.get(i).onAnimationEnd(this, mReversing); - } - } + notifyEndListeners(mReversing); // mReversing needs to be reset *after* notifying the listeners for the end callbacks. mReversing = false; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { @@ -1366,9 +1370,8 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio } else { mOverallFraction = 0f; } - if (mListeners != null) { - notifyStartListeners(); - } + + notifyStartListeners(mReversing); } /** @@ -1459,13 +1462,22 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * will be called. */ @Override - void animateValuesInRange(long currentPlayTime, long lastPlayTime) { - if (currentPlayTime < mStartDelay || lastPlayTime < -1) { + void animateValuesInRange(long currentPlayTime, long lastPlayTime, boolean notify) { + if (currentPlayTime < 0 || lastPlayTime < -1) { throw new UnsupportedOperationException("Error: Play time should never be negative."); } initAnimation(); long duration = getTotalDuration(); + if (notify) { + if (lastPlayTime < 0 || (lastPlayTime == 0 && currentPlayTime > 0)) { + notifyStartListeners(false); + } else if (lastPlayTime > duration + || (lastPlayTime == duration && currentPlayTime < duration) + ) { + notifyStartListeners(true); + } + } if (duration >= 0) { lastPlayTime = Math.min(duration, lastPlayTime); } @@ -1474,8 +1486,8 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio // Check whether repeat callback is needed only when repeat count is non-zero if (mRepeatCount > 0) { - int iteration = (int) (currentPlayTime / mDuration); - int lastIteration = (int) (lastPlayTime / mDuration); + int iteration = Math.max(0, (int) (currentPlayTime / mDuration)); + int lastIteration = Math.max(0, (int) (lastPlayTime / mDuration)); // Clamp iteration to [0, mRepeatCount] iteration = Math.min(iteration, mRepeatCount); @@ -1491,24 +1503,33 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio } } - if (mRepeatCount != INFINITE && currentPlayTime >= (mRepeatCount + 1) * mDuration) { + if (mRepeatCount != INFINITE && currentPlayTime > (mRepeatCount + 1) * mDuration) { throw new IllegalStateException("Can't animate a value outside of the duration"); } else { // Find the current fraction: - float fraction = currentPlayTime / (float) mDuration; + float fraction = Math.max(0, currentPlayTime) / (float) mDuration; fraction = getCurrentIterationFraction(fraction, false); animateValue(fraction); } } @Override - void animateSkipToEnds(long currentPlayTime, long lastPlayTime) { - if (currentPlayTime <= mStartDelay && lastPlayTime > mStartDelay) { - skipToEndValue(true); + void animateSkipToEnds(long currentPlayTime, long lastPlayTime, boolean notify) { + boolean inReverse = currentPlayTime < lastPlayTime; + boolean doSkip; + if (currentPlayTime <= 0 && lastPlayTime > 0) { + doSkip = true; } else { long duration = getTotalDuration(); - if (duration >= 0 && currentPlayTime >= duration && lastPlayTime < duration) { - skipToEndValue(false); + doSkip = duration >= 0 && currentPlayTime >= duration && lastPlayTime < duration; + } + if (doSkip) { + if (notify) { + notifyStartListeners(inReverse); + } + skipToEndValue(inReverse); + if (notify) { + notifyEndListeners(inReverse); } } } |