summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/animation/Animator.java5
-rw-r--r--core/java/android/animation/AnimatorSet.java136
-rw-r--r--core/java/android/animation/ValueAnimator.java75
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);
}
}
}