diff --git a/api/current.txt b/api/current.txt
index 072d4bbf2cf7a..d57663434e988 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3067,8 +3067,10 @@ package android.animation {
public static abstract interface Animator.AnimatorListener {
method public abstract void onAnimationCancel(android.animation.Animator);
+ method public default void onAnimationEnd(android.animation.Animator, boolean);
method public abstract void onAnimationEnd(android.animation.Animator);
method public abstract void onAnimationRepeat(android.animation.Animator);
+ method public default void onAnimationStart(android.animation.Animator, boolean);
method public abstract void onAnimationStart(android.animation.Animator);
}
@@ -3104,6 +3106,8 @@ package android.animation {
method public void playSequentially(java.util.List An animation listener receives notifications from an animation.
* Notifications indicate animation related events, such as the end or the
* repetition of the animation. Notifies the start of the animation as well as the animation's overall play direction.
+ * This method's default behavior is to call {@link #onAnimationStart(Animator)}. This
+ * method can be overridden, though not required, to get the additional play direction info
+ * when an animation starts. Skipping calling super when overriding this method results in
+ * {@link #onAnimationStart(Animator)} not getting called.
+ *
+ * @param animation The started animation.
+ * @param isReverse Whether the animation is playing in reverse.
+ */
+ default void onAnimationStart(Animator animation, boolean isReverse) {
+ onAnimationStart(animation);
+ }
+
+ /**
+ * Notifies the end of the animation. This callback is not invoked
+ * for animations with repeat count set to INFINITE. This method's default behavior is to call {@link #onAnimationEnd(Animator)}. This
+ * method can be overridden, though not required, to get the additional play direction info
+ * when an animation ends. Skipping calling super when overriding this method results in
+ * {@link #onAnimationEnd(Animator)} not getting called.
+ *
+ * @param animation The animation which reached its end.
+ * @param isReverse Whether the animation is playing in reverse.
+ */
+ default void onAnimationEnd(Animator animation, boolean isReverse) {
+ onAnimationEnd(animation);
+ }
+
/**
* Notifies the start of the animation.AnimatorListeners added to them.
*/
-public abstract class Animator implements Cloneable {
+public abstract class Animator implements Cloneable, AnimationHandler.AnimationFrameCallback {
/**
* The value used to indicate infinite duration (e.g. when Animators repeat infinitely).
@@ -464,12 +464,103 @@ public abstract class Animator implements Cloneable {
throw new IllegalStateException("Reverse is not supported");
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean doAnimationFrame(long frameTime) {
+ // TODO: Need to find a better signal than this
+ return getDuration() + getStartDelay() >= frameTime;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void commitAnimationFrame(long frameTime) {}
+
+
+ /**
+ * Internal use only.
+ * This call starts the animation in regular or reverse direction without requiring them to
+ * register frame callbacks. The caller will be responsible for all the subsequent animation
+ * pulses. Specifically, the caller needs to call doAnimationFrame(...) for the animation on
+ * every frame.
+ *
+ * @param inReverse whether the animation should play in reverse direction
+ */
+ void startWithoutPulsing(boolean inReverse) {
+ if (inReverse) {
+ reverse();
+ } else {
+ start();
+ }
+ }
+
+ /**
+ * Internal use only.
+ * Skips the animation value to end/start, depending on whether the play direction is forward
+ * or backward.
+ *
+ * @param inReverse whether the end value is based on a reverse direction. If yes, this is
+ * equivalent to skip to start value in a forward playing direction.
+ */
+ void skipToEndValue(boolean inReverse) {}
+
+
+ /**
+ * Internal use only.
+ *
+ * Returns whether the animation has start/end values setup. For most of the animations, this
+ * should always be true. For ObjectAnimators, the start values are setup in the initialization
+ * of the animation.
+ */
+ boolean isInitialized() {
+ return true;
+ }
+
+ /**
+ * Internal use only.
+ */
+ void animateBasedOnPlayTime(long currentPlayTime, long lastPlayTime, boolean inReverse) {}
+
/**
*
+ * Note: reverse is not supported for infinite AnimatorSet.
*/
@Override
public void reverse() {
- if (canReverse()) {
- int size = mNodes.size();
- for (int i = 0; i < size; i++) {
- Node node = mNodes.get(i);
- node.mAnimation.reverse();
- }
- }
+ start(true, true);
}
@Override
@@ -993,18 +1325,61 @@ public final class AnimatorSet extends Animator {
mRootNode.mEndTime = mDelayAnim.getDuration();
updatePlayTime(mRootNode, visited);
- long maxEndTime = 0;
- for (int i = 0; i < size; i++) {
+ sortAnimationEvents();
+ mTotalDuration = mEvents.get(mEvents.size() - 1).getTime();
+ }
+
+ private void sortAnimationEvents() {
+ // Sort the list of events in ascending order of their time
+ // Create the list including the delay animation.
+ mEvents.clear();
+ for (int i = 0; i < mNodes.size(); i++) {
Node node = mNodes.get(i);
- node.mTotalDuration = node.mAnimation.getTotalDuration();
- if (node.mEndTime == DURATION_INFINITE) {
- maxEndTime = DURATION_INFINITE;
- break;
- } else {
- maxEndTime = node.mEndTime > maxEndTime ? node.mEndTime : maxEndTime;
- }
+ mEvents.add(new AnimationEvent(node, AnimationEvent.ANIMATION_START));
+ mEvents.add(new AnimationEvent(node, AnimationEvent.ANIMATION_DELAY_ENDED));
+ mEvents.add(new AnimationEvent(node, AnimationEvent.ANIMATION_END));
+ }
+ mEvents.sort(new ComparatorBuilder object is a utility class to facilitate adding animations to a
* AnimatorSet along with the relationships between the various animations. The
@@ -1328,7 +1792,6 @@ public final class AnimatorSet extends Animator {
* {@link AnimatorSet#play(Animator)} method ends.
*/
public Builder before(Animator anim) {
- mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addChild(node);
return this;
@@ -1343,7 +1806,6 @@ public final class AnimatorSet extends Animator {
* {@link AnimatorSet#play(Animator)} method to play.
*/
public Builder after(Animator anim) {
- mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addParent(node);
return this;
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 4707bed3ee143..1e1f1554d3a28 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -991,6 +991,11 @@ public final class ObjectAnimator extends ValueAnimator {
}
}
+ @Override
+ boolean isInitialized() {
+ return mInitialized;
+ }
+
@Override
public ObjectAnimator clone() {
final ObjectAnimator anim = (ObjectAnimator) super.clone();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f0fc8af9d504e..470523fc42522 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -24,6 +24,7 @@ import android.os.Trace;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
@@ -67,7 +68,7 @@ import java.util.HashMap;
*
*/
@SuppressWarnings("unchecked")
-public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {
+public class ValueAnimator extends Animator {
private static final String TAG = "ValueAnimator";
private static final boolean DEBUG = false;
@@ -90,7 +91,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
*
* Whenever mStartTime is set, you must also update mStartTimeCommitted.
*/
- long mStartTime;
+ long mStartTime = -1;
/**
* When true, the start time has been firmly committed as a chosen reference point in
@@ -152,7 +153,13 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
/**
* Tracks the time (in milliseconds) when the last frame arrived.
*/
- private long mLastFrameTime = 0;
+ private long mLastFrameTime = -1;
+
+ /**
+ * Tracks the time (in milliseconds) when the first frame arrived. Note the frame may arrive
+ * during the start delay.
+ */
+ private long mFirstFrameTime = -1;
/**
* Additional playing state to indicate whether an animator has been start()'d. There is
@@ -211,6 +218,12 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
*/
private int mRepeatMode = RESTART;
+ /**
+ * Whether or not the animator should register for its own animation callback to receive
+ * animation pulse.
+ */
+ private boolean mSelfPulse = true;
+
/**
* The time interpolator to be used. The elapsed fraction of the animation will be passed
* through this interpolator to calculate the interpolated fraction, which is then used to
@@ -628,7 +641,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
mSeekFraction = fraction;
}
mOverallFraction = fraction;
- final float currentIterationFraction = getCurrentIterationFraction(fraction);
+ final float currentIterationFraction = getCurrentIterationFraction(fraction, mReversing);
animateValue(currentIterationFraction);
}
@@ -654,11 +667,11 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* should be played backwards. E.g. When the animation is played backwards in an iteration,
* the fraction for that iteration will go from 1f to 0f.
*/
- private float getCurrentIterationFraction(float fraction) {
+ private float getCurrentIterationFraction(float fraction, boolean inReverse) {
fraction = clampFraction(fraction);
int iteration = getCurrentIteration(fraction);
float currentFraction = fraction - iteration;
- return shouldPlayBackward(iteration) ? 1f - currentFraction : currentFraction;
+ return shouldPlayBackward(iteration, inReverse) ? 1f - currentFraction : currentFraction;
}
/**
@@ -682,18 +695,18 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
* whether the entire animation is being reversed, 2) repeat mode applied to the current
* iteration.
*/
- private boolean shouldPlayBackward(int iteration) {
+ private boolean shouldPlayBackward(int iteration, boolean inReverse) {
if (iteration > 0 && mRepeatMode == REVERSE &&
(iteration < (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 (mReversing) {
+ if (inReverse) {
return (iteration % 2) == 0;
} else {
return (iteration % 2) != 0;
}
} else {
- return mReversing;
+ return inReverse;
}
}
@@ -965,7 +978,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
(ArrayList