Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3140,6 +3140,7 @@ package android.animation { public final class AnimatorSet extends android.animation.Animator { ctor public AnimatorSet(); method public java.util.ArrayList<android.animation.Animator> getChildAnimations(); method public long getCurrentPlayTime(); method public long getDuration(); method public long getStartDelay(); method public boolean isRunning(); api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3260,6 +3260,7 @@ package android.animation { public final class AnimatorSet extends android.animation.Animator { ctor public AnimatorSet(); method public java.util.ArrayList<android.animation.Animator> getChildAnimations(); method public long getCurrentPlayTime(); method public long getDuration(); method public long getStartDelay(); method public boolean isRunning(); api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3140,6 +3140,7 @@ package android.animation { public final class AnimatorSet extends android.animation.Animator { ctor public AnimatorSet(); method public java.util.ArrayList<android.animation.Animator> getChildAnimations(); method public long getCurrentPlayTime(); method public long getDuration(); method public long getStartDelay(); method public boolean isRunning(); core/java/android/animation/AnimatorSet.java +158 −48 Original line number Diff line number Diff line Loading @@ -142,11 +142,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // the animation was previously seeked and therefore doesn't start from the beginning). private final boolean mShouldResetValuesAtStart; // In pre-O releases, end() may never explicitly called on a child animator. As a result, end() // may not even be properly implemented in a lot of cases. After a few apps crashing on this, // it became necessary to use an sdk target guard for calling end(). private final boolean mEndCanBeCalled; // The time, in milliseconds, when last frame of the animation came in. -1 when the animation is // not running. private long mLastFrameTime = -1; // The time, in milliseconds, when the first frame of the animation came in. // The time, in milliseconds, when the first frame of the animation came in. This is the // frame before we start counting down the start delay, if any. // -1 when the animation is not running. private long mFirstFrame = -1; Loading Loading @@ -191,11 +197,12 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim super(); mNodeMap.put(mDelayAnim, mRootNode); mNodes.add(mRootNode); boolean isPreO; // Set the flag to ignore calling end() without start() for pre-N releases Application app = ActivityThread.currentApplication(); if (app == null || app.getApplicationInfo() == null) { mShouldIgnoreEndWithoutStart = true; mShouldResetValuesAtStart = false; isPreO = true; } else { if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { mShouldIgnoreEndWithoutStart = true; Loading @@ -203,12 +210,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim mShouldIgnoreEndWithoutStart = false; } if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) { mShouldResetValuesAtStart = false; } else { mShouldResetValuesAtStart = true; } isPreO = app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O; } mShouldResetValuesAtStart = !isPreO; mEndCanBeCalled = !isPreO; } /** Loading Loading @@ -424,6 +429,35 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } // Force all the animations to end when the duration scale is 0. private void forceToEnd() { if (mEndCanBeCalled) { end(); } else { // Note: we don't want to combine this case with the end() method below because in // the case of developer calling end(), we still need to make sure end() is explicitly // called on the child animators to maintain the old behavior. if (mReversing) { mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId; for (int j = mLastEventId - 1; j >= 0; j--) { AnimationEvent event = mEvents.get(j); if (event.mEvent == AnimationEvent.ANIMATION_END) { event.mNode.mAnimation.reverse(); } } } else { for (int j = mLastEventId + 1; j < mEvents.size(); j++) { AnimationEvent event = mEvents.get(j); if (event.mEvent == AnimationEvent.ANIMATION_START) { event.mNode.mAnimation.start(); } } } mPlayingSet.clear(); endAnimation(); } } /** * {@inheritDoc} * Loading @@ -445,19 +479,28 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId; for (int j = mLastEventId - 1; j >= 0; j--) { AnimationEvent event = mEvents.get(j); Animator anim = event.mNode.mAnimation; if (event.mEvent == AnimationEvent.ANIMATION_END) { event.mNode.mAnimation.reverse(); } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) { event.mNode.mAnimation.end(); anim.reverse(); } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED && anim.isStarted()) { // Make sure anim hasn't finished before calling end() so that we don't end // already ended animations, which will cause start and end callbacks to be // triggered again. anim.end(); } } } else { for (int j = mLastEventId + 1; j < mEvents.size(); j++) { AnimationEvent event = mEvents.get(j); Animator anim = event.mNode.mAnimation; if (event.mEvent == AnimationEvent.ANIMATION_START) { event.mNode.mAnimation.start(); } else if (event.mEvent == AnimationEvent.ANIMATION_END) { event.mNode.mAnimation.end(); anim.start(); } else if (event.mEvent == AnimationEvent.ANIMATION_END && anim.isStarted()) { // Make sure anim hasn't finished before calling end() so that we don't end // already ended animations, which will cause start and end callbacks to be // triggered again. anim.end(); } } } Loading @@ -476,12 +519,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim */ @Override public boolean isRunning() { if (mStartDelay > 0) { return mStarted && !mDelayAnim.isRunning(); } else { // No start delay, animation should start right away if (mStartDelay == 0) { return mStarted; } return mLastFrameTime > 0; } @Override Loading Loading @@ -673,8 +714,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim mReversing = inReverse; // Now that all dependencies are set up, start the animations that should be started. boolean setIsEmpty = isEmptySet(this); if (!setIsEmpty) { boolean isZeroDuration = ValueAnimator.getDurationScale() == 0f || isEmptySet(this); if (!isZeroDuration) { startAnimation(); } Loading @@ -686,9 +727,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim tmpListeners.get(i).onAnimationStart(this, inReverse); } } if (setIsEmpty) { // In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away. end(); if (isZeroDuration) { // In the case of empty AnimatorSet, or 0 duration scale, we will trigger the // onAnimationEnd() right away. forceToEnd(); } } Loading Loading @@ -815,6 +857,9 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim for (int i = 0; i < unfinishedNodes.size(); i++) { Node node = unfinishedNodes.get(i); long playTime = getPlayTimeForNode(currentPlayTime, node, inReverse); if (!inReverse) { playTime -= node.mAnimation.getStartDelay(); } node.mAnimation.animateBasedOnPlayTime(playTime, lastPlayTime, inReverse); } } Loading Loading @@ -889,6 +934,31 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } /** * Gets the current position of the animation in time, which is equal to the current * time minus the time that the animation started. An animation that is not yet started will * return a value of zero, unless the animation has has its play time set via * {@link #setCurrentPlayTime(long)}, in which case it will return the time that was set. * * @return The current position in time of the animation. */ public long getCurrentPlayTime() { if (mSeekState.isActive()) { return mSeekState.getPlayTime(); } if (mLastFrameTime == -1) { // Not yet started or during start delay return 0; } float durationScale = ValueAnimator.getDurationScale(); durationScale = durationScale == 0 ? 1 : durationScale; if (mReversing) { return (long) ((mLastFrameTime - mFirstFrame) / durationScale); } else { return (long) ((mLastFrameTime - mFirstFrame - mStartDelay) / durationScale); } } private void initChildren() { if (!isInitialized()) { mChildrenInitialized = true; Loading @@ -907,8 +977,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim */ @Override public boolean doAnimationFrame(long frameTime) { if (mLastFrameTime < 0) { mFirstFrame = mLastFrameTime = frameTime; float durationScale = ValueAnimator.getDurationScale(); if (durationScale == 0f) { // Duration scale changed to 0 amid animation, end the animation right away. forceToEnd(); return true; } // After the first frame comes in, we need to wait for start delay to pass before updating // any animation values. if (mFirstFrame < 0) { mFirstFrame = frameTime; } // Handle pause/resume Loading @@ -928,19 +1007,31 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // Continue at seeked position if (mSeekState.isActive()) { mSeekState.updateSeekDirection(mReversing); mFirstFrame = frameTime - mSeekState.getPlayTime() - mStartDelay; if (mReversing) { mFirstFrame = (long) (frameTime - mSeekState.getPlayTime() * durationScale); } else { mFirstFrame = (long) (frameTime - (mSeekState.getPlayTime() + mStartDelay) * durationScale); } mSeekState.reset(); } // This playTime includes the start delay. long playTime = frameTime - mFirstFrame; if (!mReversing && frameTime < mFirstFrame + mStartDelay * durationScale) { // Still during start delay in a forward playing case. return false; } // From here on, we always use unscaled play time. Note this unscaled playtime includes // the start delay. long unscaledPlayTime = (long) ((frameTime - mFirstFrame) / durationScale); mLastFrameTime = frameTime; // 1. Pulse the animators that will start or end in this frame // 2. Pulse the animators that will finish in a later frame int latestId = findLatestEventIdForTime(playTime); int latestId = findLatestEventIdForTime(unscaledPlayTime); int startId = mLastEventId; handleAnimationEvents(startId, latestId, playTime); handleAnimationEvents(startId, latestId, unscaledPlayTime); mLastEventId = latestId; Loading @@ -948,8 +1039,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim for (int i = 0; i < mPlayingSet.size(); i++) { Node node = mPlayingSet.get(i); if (!node.mEnded) { node.mEnded = node.mAnimation.pulseAnimationFrame( getPlayTimeForNode(playTime, node)); pulseFrame(node, getPlayTimeForNode(unscaledPlayTime, node)); } } Loading @@ -960,21 +1050,23 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } mLastFrameTime = frameTime; if (mPlayingSet.isEmpty()) { boolean finished; boolean finished = false; if (mReversing) { // Make sure there's no more END event before current event id and after start delay finished = mLastEventId <= 3; if (mPlayingSet.size() == 1 && mPlayingSet.get(0) == mRootNode) { // The only animation that is running is the delay animation. finished = true; } else if (mPlayingSet.isEmpty() && mLastEventId < 3) { // The only remaining animation is the delay animation finished = true; } } else { // Make sure there's no more START event before current event id: finished = (mLastEventId == mEvents.size() - 1); finished = mPlayingSet.isEmpty() && mLastEventId == mEvents.size() - 1; } if (finished) { endAnimation(); return true; } } return false; } Loading Loading @@ -1029,9 +1121,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } private void pulseFrame(Node node, long frameTime) { /** * This method pulses frames into child animations. It scales the input animation play time * with the duration scale and pass that to the child animation via pulseAnimationFrame(long). * * @param node child animator node * @param animPlayTime unscaled play time (including start delay) for the child animator */ private void pulseFrame(Node node, long animPlayTime) { if (!node.mEnded) { node.mEnded = node.mAnimation.pulseAnimationFrame(frameTime); node.mEnded = node.mAnimation.pulseAnimationFrame( (long) (animPlayTime * ValueAnimator.getDurationScale())); } } Loading @@ -1052,7 +1152,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim addDummyListener(); // Register animation callback addAnimationCallback(mStartDelay); addAnimationCallback(0); if (mSeekState.getPlayTimeNormalized() == 0 && mReversing) { // Maintain old behavior, if seeked to 0 then call reverse, we'll treat the case Loading @@ -1061,7 +1161,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } // Set the child animators to the right end: if (mShouldResetValuesAtStart) { if (mReversing || isInitialized()) { if (isInitialized()) { skipToEndValue(!mReversing); } else if (mReversing) { // Reversing but haven't initialized all the children yet. initChildren(); skipToEndValue(!mReversing); } else { // If not all children are initialized and play direction is forward Loading Loading @@ -1091,6 +1195,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } int toId = findLatestEventIdForTime(playTime); handleAnimationEvents(-1, toId, playTime); for (int i = mPlayingSet.size() - 1; i >= 0; i--) { if (mPlayingSet.get(i).mEnded) { mPlayingSet.remove(i); } } mLastEventId = toId; } } Loading Loading @@ -1797,6 +1906,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim if (mPlayTime >= 0) { if (inReverse != mSeekingInReverse) { mPlayTime = getTotalDuration() - mStartDelay - mPlayTime; mSeekingInReverse = inReverse; } } } Loading core/java/android/animation/ValueAnimator.java +17 −16 Original line number Diff line number Diff line Loading @@ -1031,6 +1031,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio // started-but-not-yet-reached-the-first-frame phase. mLastFrameTime = -1; mFirstFrameTime = -1; mStartTime = -1; addAnimationCallback(0); if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) { Loading Loading @@ -1199,7 +1200,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio mStartListenersCalled = false; mLastFrameTime = -1; mFirstFrameTime = -1; mReversing = false; mStartTime = -1; if (notify && mListeners != null) { ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); Loading @@ -1208,6 +1209,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio tmpListeners.get(i).onAnimationEnd(this, mReversing); } } // mReversing needs to be reset *after* notifying the listeners for the end callbacks. mReversing = false; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), Loading Loading @@ -1392,9 +1394,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * @hide */ public final boolean doAnimationFrame(long frameTime) { if (!mRunning && mStartTime < 0) { // First frame during delay mStartTime = frameTime + mStartDelay; if (mStartTime < 0) { // First frame. If there is start delay, start delay count down will happen *after* this // frame. mStartTime = mReversing ? frameTime : frameTime + mStartDelay; } // Handle pause/resume Loading @@ -1411,25 +1414,23 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio } if (!mRunning) { // If not running, that means the animation is in the start delay phase. In the case of // reversing, we want to run start delay in the end. if (mStartTime > frameTime) { // During start delay // If not running, that means the animation is in the start delay phase of a forward // running animation. In the case of reversing, we want to run start delay in the end. if (mStartTime > frameTime && mSeekFraction == -1) { // This is when no seek fraction is set during start delay. If developers change the // seek fraction during the delay, animation will start from the seeked position // right away. return false; } else { // Start delay has passed. // If mRunning is not set by now, that means non-zero start delay, // no seeking, not reversing. At this point, start delay has passed. mRunning = true; startAnimation(); } } if (mLastFrameTime < 0) { // First frame if (mStartDelay > 0) { startAnimation(); } if (mSeekFraction < 0) { mStartTime = frameTime; } else { if (mSeekFraction >= 0) { long seekTime = (long) (getScaledDuration() * mSeekFraction); mStartTime = frameTime - seekTime; mSeekFraction = -1; Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3140,6 +3140,7 @@ package android.animation { public final class AnimatorSet extends android.animation.Animator { ctor public AnimatorSet(); method public java.util.ArrayList<android.animation.Animator> getChildAnimations(); method public long getCurrentPlayTime(); method public long getDuration(); method public long getStartDelay(); method public boolean isRunning();
api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3260,6 +3260,7 @@ package android.animation { public final class AnimatorSet extends android.animation.Animator { ctor public AnimatorSet(); method public java.util.ArrayList<android.animation.Animator> getChildAnimations(); method public long getCurrentPlayTime(); method public long getDuration(); method public long getStartDelay(); method public boolean isRunning();
api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3140,6 +3140,7 @@ package android.animation { public final class AnimatorSet extends android.animation.Animator { ctor public AnimatorSet(); method public java.util.ArrayList<android.animation.Animator> getChildAnimations(); method public long getCurrentPlayTime(); method public long getDuration(); method public long getStartDelay(); method public boolean isRunning();
core/java/android/animation/AnimatorSet.java +158 −48 Original line number Diff line number Diff line Loading @@ -142,11 +142,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // the animation was previously seeked and therefore doesn't start from the beginning). private final boolean mShouldResetValuesAtStart; // In pre-O releases, end() may never explicitly called on a child animator. As a result, end() // may not even be properly implemented in a lot of cases. After a few apps crashing on this, // it became necessary to use an sdk target guard for calling end(). private final boolean mEndCanBeCalled; // The time, in milliseconds, when last frame of the animation came in. -1 when the animation is // not running. private long mLastFrameTime = -1; // The time, in milliseconds, when the first frame of the animation came in. // The time, in milliseconds, when the first frame of the animation came in. This is the // frame before we start counting down the start delay, if any. // -1 when the animation is not running. private long mFirstFrame = -1; Loading Loading @@ -191,11 +197,12 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim super(); mNodeMap.put(mDelayAnim, mRootNode); mNodes.add(mRootNode); boolean isPreO; // Set the flag to ignore calling end() without start() for pre-N releases Application app = ActivityThread.currentApplication(); if (app == null || app.getApplicationInfo() == null) { mShouldIgnoreEndWithoutStart = true; mShouldResetValuesAtStart = false; isPreO = true; } else { if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { mShouldIgnoreEndWithoutStart = true; Loading @@ -203,12 +210,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim mShouldIgnoreEndWithoutStart = false; } if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) { mShouldResetValuesAtStart = false; } else { mShouldResetValuesAtStart = true; } isPreO = app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O; } mShouldResetValuesAtStart = !isPreO; mEndCanBeCalled = !isPreO; } /** Loading Loading @@ -424,6 +429,35 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } // Force all the animations to end when the duration scale is 0. private void forceToEnd() { if (mEndCanBeCalled) { end(); } else { // Note: we don't want to combine this case with the end() method below because in // the case of developer calling end(), we still need to make sure end() is explicitly // called on the child animators to maintain the old behavior. if (mReversing) { mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId; for (int j = mLastEventId - 1; j >= 0; j--) { AnimationEvent event = mEvents.get(j); if (event.mEvent == AnimationEvent.ANIMATION_END) { event.mNode.mAnimation.reverse(); } } } else { for (int j = mLastEventId + 1; j < mEvents.size(); j++) { AnimationEvent event = mEvents.get(j); if (event.mEvent == AnimationEvent.ANIMATION_START) { event.mNode.mAnimation.start(); } } } mPlayingSet.clear(); endAnimation(); } } /** * {@inheritDoc} * Loading @@ -445,19 +479,28 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim mLastEventId = mLastEventId == -1 ? mEvents.size() : mLastEventId; for (int j = mLastEventId - 1; j >= 0; j--) { AnimationEvent event = mEvents.get(j); Animator anim = event.mNode.mAnimation; if (event.mEvent == AnimationEvent.ANIMATION_END) { event.mNode.mAnimation.reverse(); } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED) { event.mNode.mAnimation.end(); anim.reverse(); } else if (event.mEvent == AnimationEvent.ANIMATION_DELAY_ENDED && anim.isStarted()) { // Make sure anim hasn't finished before calling end() so that we don't end // already ended animations, which will cause start and end callbacks to be // triggered again. anim.end(); } } } else { for (int j = mLastEventId + 1; j < mEvents.size(); j++) { AnimationEvent event = mEvents.get(j); Animator anim = event.mNode.mAnimation; if (event.mEvent == AnimationEvent.ANIMATION_START) { event.mNode.mAnimation.start(); } else if (event.mEvent == AnimationEvent.ANIMATION_END) { event.mNode.mAnimation.end(); anim.start(); } else if (event.mEvent == AnimationEvent.ANIMATION_END && anim.isStarted()) { // Make sure anim hasn't finished before calling end() so that we don't end // already ended animations, which will cause start and end callbacks to be // triggered again. anim.end(); } } } Loading @@ -476,12 +519,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim */ @Override public boolean isRunning() { if (mStartDelay > 0) { return mStarted && !mDelayAnim.isRunning(); } else { // No start delay, animation should start right away if (mStartDelay == 0) { return mStarted; } return mLastFrameTime > 0; } @Override Loading Loading @@ -673,8 +714,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim mReversing = inReverse; // Now that all dependencies are set up, start the animations that should be started. boolean setIsEmpty = isEmptySet(this); if (!setIsEmpty) { boolean isZeroDuration = ValueAnimator.getDurationScale() == 0f || isEmptySet(this); if (!isZeroDuration) { startAnimation(); } Loading @@ -686,9 +727,10 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim tmpListeners.get(i).onAnimationStart(this, inReverse); } } if (setIsEmpty) { // In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away. end(); if (isZeroDuration) { // In the case of empty AnimatorSet, or 0 duration scale, we will trigger the // onAnimationEnd() right away. forceToEnd(); } } Loading Loading @@ -815,6 +857,9 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim for (int i = 0; i < unfinishedNodes.size(); i++) { Node node = unfinishedNodes.get(i); long playTime = getPlayTimeForNode(currentPlayTime, node, inReverse); if (!inReverse) { playTime -= node.mAnimation.getStartDelay(); } node.mAnimation.animateBasedOnPlayTime(playTime, lastPlayTime, inReverse); } } Loading Loading @@ -889,6 +934,31 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } /** * Gets the current position of the animation in time, which is equal to the current * time minus the time that the animation started. An animation that is not yet started will * return a value of zero, unless the animation has has its play time set via * {@link #setCurrentPlayTime(long)}, in which case it will return the time that was set. * * @return The current position in time of the animation. */ public long getCurrentPlayTime() { if (mSeekState.isActive()) { return mSeekState.getPlayTime(); } if (mLastFrameTime == -1) { // Not yet started or during start delay return 0; } float durationScale = ValueAnimator.getDurationScale(); durationScale = durationScale == 0 ? 1 : durationScale; if (mReversing) { return (long) ((mLastFrameTime - mFirstFrame) / durationScale); } else { return (long) ((mLastFrameTime - mFirstFrame - mStartDelay) / durationScale); } } private void initChildren() { if (!isInitialized()) { mChildrenInitialized = true; Loading @@ -907,8 +977,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim */ @Override public boolean doAnimationFrame(long frameTime) { if (mLastFrameTime < 0) { mFirstFrame = mLastFrameTime = frameTime; float durationScale = ValueAnimator.getDurationScale(); if (durationScale == 0f) { // Duration scale changed to 0 amid animation, end the animation right away. forceToEnd(); return true; } // After the first frame comes in, we need to wait for start delay to pass before updating // any animation values. if (mFirstFrame < 0) { mFirstFrame = frameTime; } // Handle pause/resume Loading @@ -928,19 +1007,31 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim // Continue at seeked position if (mSeekState.isActive()) { mSeekState.updateSeekDirection(mReversing); mFirstFrame = frameTime - mSeekState.getPlayTime() - mStartDelay; if (mReversing) { mFirstFrame = (long) (frameTime - mSeekState.getPlayTime() * durationScale); } else { mFirstFrame = (long) (frameTime - (mSeekState.getPlayTime() + mStartDelay) * durationScale); } mSeekState.reset(); } // This playTime includes the start delay. long playTime = frameTime - mFirstFrame; if (!mReversing && frameTime < mFirstFrame + mStartDelay * durationScale) { // Still during start delay in a forward playing case. return false; } // From here on, we always use unscaled play time. Note this unscaled playtime includes // the start delay. long unscaledPlayTime = (long) ((frameTime - mFirstFrame) / durationScale); mLastFrameTime = frameTime; // 1. Pulse the animators that will start or end in this frame // 2. Pulse the animators that will finish in a later frame int latestId = findLatestEventIdForTime(playTime); int latestId = findLatestEventIdForTime(unscaledPlayTime); int startId = mLastEventId; handleAnimationEvents(startId, latestId, playTime); handleAnimationEvents(startId, latestId, unscaledPlayTime); mLastEventId = latestId; Loading @@ -948,8 +1039,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim for (int i = 0; i < mPlayingSet.size(); i++) { Node node = mPlayingSet.get(i); if (!node.mEnded) { node.mEnded = node.mAnimation.pulseAnimationFrame( getPlayTimeForNode(playTime, node)); pulseFrame(node, getPlayTimeForNode(unscaledPlayTime, node)); } } Loading @@ -960,21 +1050,23 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } mLastFrameTime = frameTime; if (mPlayingSet.isEmpty()) { boolean finished; boolean finished = false; if (mReversing) { // Make sure there's no more END event before current event id and after start delay finished = mLastEventId <= 3; if (mPlayingSet.size() == 1 && mPlayingSet.get(0) == mRootNode) { // The only animation that is running is the delay animation. finished = true; } else if (mPlayingSet.isEmpty() && mLastEventId < 3) { // The only remaining animation is the delay animation finished = true; } } else { // Make sure there's no more START event before current event id: finished = (mLastEventId == mEvents.size() - 1); finished = mPlayingSet.isEmpty() && mLastEventId == mEvents.size() - 1; } if (finished) { endAnimation(); return true; } } return false; } Loading Loading @@ -1029,9 +1121,17 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } } private void pulseFrame(Node node, long frameTime) { /** * This method pulses frames into child animations. It scales the input animation play time * with the duration scale and pass that to the child animation via pulseAnimationFrame(long). * * @param node child animator node * @param animPlayTime unscaled play time (including start delay) for the child animator */ private void pulseFrame(Node node, long animPlayTime) { if (!node.mEnded) { node.mEnded = node.mAnimation.pulseAnimationFrame(frameTime); node.mEnded = node.mAnimation.pulseAnimationFrame( (long) (animPlayTime * ValueAnimator.getDurationScale())); } } Loading @@ -1052,7 +1152,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim addDummyListener(); // Register animation callback addAnimationCallback(mStartDelay); addAnimationCallback(0); if (mSeekState.getPlayTimeNormalized() == 0 && mReversing) { // Maintain old behavior, if seeked to 0 then call reverse, we'll treat the case Loading @@ -1061,7 +1161,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } // Set the child animators to the right end: if (mShouldResetValuesAtStart) { if (mReversing || isInitialized()) { if (isInitialized()) { skipToEndValue(!mReversing); } else if (mReversing) { // Reversing but haven't initialized all the children yet. initChildren(); skipToEndValue(!mReversing); } else { // If not all children are initialized and play direction is forward Loading Loading @@ -1091,6 +1195,11 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim } int toId = findLatestEventIdForTime(playTime); handleAnimationEvents(-1, toId, playTime); for (int i = mPlayingSet.size() - 1; i >= 0; i--) { if (mPlayingSet.get(i).mEnded) { mPlayingSet.remove(i); } } mLastEventId = toId; } } Loading Loading @@ -1797,6 +1906,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim if (mPlayTime >= 0) { if (inReverse != mSeekingInReverse) { mPlayTime = getTotalDuration() - mStartDelay - mPlayTime; mSeekingInReverse = inReverse; } } } Loading
core/java/android/animation/ValueAnimator.java +17 −16 Original line number Diff line number Diff line Loading @@ -1031,6 +1031,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio // started-but-not-yet-reached-the-first-frame phase. mLastFrameTime = -1; mFirstFrameTime = -1; mStartTime = -1; addAnimationCallback(0); if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) { Loading Loading @@ -1199,7 +1200,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio mStartListenersCalled = false; mLastFrameTime = -1; mFirstFrameTime = -1; mReversing = false; mStartTime = -1; if (notify && mListeners != null) { ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone(); Loading @@ -1208,6 +1209,7 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio tmpListeners.get(i).onAnimationEnd(this, mReversing); } } // mReversing needs to be reset *after* notifying the listeners for the end callbacks. mReversing = false; if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), Loading Loading @@ -1392,9 +1394,10 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio * @hide */ public final boolean doAnimationFrame(long frameTime) { if (!mRunning && mStartTime < 0) { // First frame during delay mStartTime = frameTime + mStartDelay; if (mStartTime < 0) { // First frame. If there is start delay, start delay count down will happen *after* this // frame. mStartTime = mReversing ? frameTime : frameTime + mStartDelay; } // Handle pause/resume Loading @@ -1411,25 +1414,23 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio } if (!mRunning) { // If not running, that means the animation is in the start delay phase. In the case of // reversing, we want to run start delay in the end. if (mStartTime > frameTime) { // During start delay // If not running, that means the animation is in the start delay phase of a forward // running animation. In the case of reversing, we want to run start delay in the end. if (mStartTime > frameTime && mSeekFraction == -1) { // This is when no seek fraction is set during start delay. If developers change the // seek fraction during the delay, animation will start from the seeked position // right away. return false; } else { // Start delay has passed. // If mRunning is not set by now, that means non-zero start delay, // no seeking, not reversing. At this point, start delay has passed. mRunning = true; startAnimation(); } } if (mLastFrameTime < 0) { // First frame if (mStartDelay > 0) { startAnimation(); } if (mSeekFraction < 0) { mStartTime = frameTime; } else { if (mSeekFraction >= 0) { long seekTime = (long) (getScaledDuration() * mSeekFraction); mStartTime = frameTime - seekTime; mSeekFraction = -1; Loading