Loading core/java/android/animation/AnimatorSet.java +2 −0 Original line number Diff line number Diff line Loading @@ -807,6 +807,8 @@ public final class AnimatorSet extends Animator { } /** * AnimatorSet is only reversible when the set contains no sequential animation, and no child * animators have a start delay. * @hide */ @Override Loading core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +15 −12 Original line number Diff line number Diff line Loading @@ -43,12 +43,13 @@ static JNIEnv* getEnv(JavaVM* vm) { return env; } static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) { static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) { class AnimationListenerBridge : public AnimationListener { public: AnimationListenerBridge(JNIEnv* env, jobject finishListener) { AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) { mFinishListener = env->NewGlobalRef(finishListener); env->GetJavaVM(&mJvm); mId = id; } virtual ~AnimationListenerBridge() { Loading @@ -63,7 +64,7 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis env->CallStaticVoidMethod( gVectorDrawableAnimatorClassInfo.clazz, gVectorDrawableAnimatorClassInfo.callOnFinished, mFinishListener); mFinishListener, mId); releaseJavaObject(); } Loading @@ -76,8 +77,9 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis JavaVM* mJvm; jobject mFinishListener; jint mId; }; return new AnimationListenerBridge(env, finishListener); return new AnimationListenerBridge(env, finishListener, id); } static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr, Loading Loading @@ -142,15 +144,16 @@ static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr, holder->setPropertyDataSource(propertyData, length); env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT); } static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) { static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) { PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); // TODO: keep a ref count in finish listener AnimationListener* listener = createAnimationListener(env, finishListener); AnimationListener* listener = createAnimationListener(env, finishListener, id); set->start(listener); } static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) { // TODO: implement reverse static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) { PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); AnimationListener* listener = createAnimationListener(env, finishListener, id); set->reverse(listener); } static void end(JNIEnv*, jobject, jlong animatorSetPtr) { Loading @@ -172,8 +175,8 @@ static const JNINativeMethod gMethods[] = { {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder}, {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder}, {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData}, {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)start}, {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse}, {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start}, {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse}, {"nEnd", "!(J)V", (void*)end}, {"nReset", "!(J)V", (void*)reset}, }; Loading @@ -186,7 +189,7 @@ int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) { gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie( env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished", "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V"); "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V"); return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable", gMethods, NELEM(gMethods)); } Loading core/jni/android_view_RenderNodeAnimator.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -184,7 +184,7 @@ static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) { static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) { BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); animator->end(); animator->cancel(); } // ---------------------------------------------------------------------------- Loading graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +49 −57 Original line number Diff line number Diff line Loading @@ -238,9 +238,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas); } mAnimatedVectorState.mVectorDrawable.draw(canvas); if (isStarted()) { invalidateSelf(); } } @Override Loading Loading @@ -611,10 +608,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return mAnimatorSet.isRunning(); } private boolean isStarted() { return mAnimatorSet.isStarted(); } /** * Resets the AnimatedVectorDrawable to the start state as specified in the animators. */ Loading @@ -626,12 +619,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void start() { ensureAnimatorSet(); // If any one of the animator has not ended, do nothing. if (isStarted()) { return; } mAnimatorSet.start(); invalidateSelf(); } Loading @@ -652,6 +639,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void stop() { mAnimatorSet.end(); invalidateSelf(); } /** Loading Loading @@ -774,6 +762,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * @hide */ public static class VectorDrawableAnimator { private static final int NONE = 0; private static final int START_ANIMATION = 1; private static final int REVERSE_ANIMATION = 2; private AnimatorListener mListener = null; private final LongArray mStartDelays = new LongArray(); private PropertyValuesHolder.PropertyValues mTmpValues = Loading @@ -782,7 +773,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private boolean mContainsSequentialAnimators = false; private boolean mStarted = false; private boolean mInitialized = false; private boolean mAnimationPending = false; private boolean mIsReversible = false; // This needs to be set before parsing starts. private boolean mShouldIgnoreInvalidAnim; Loading @@ -790,7 +780,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private final VirtualRefBasePtr mSetRefBasePtr; private WeakReference<RenderNode> mTarget = null; private WeakReference<RenderNode> mLastSeenTarget = null; private int mLastListenerId = 0; private int mPendingAnimationAction = NONE; VectorDrawableAnimator() { mSetPtr = nCreateAnimatorSet(); Loading @@ -810,6 +801,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mInitialized = true; // Check reversible. mIsReversible = true; if (mContainsSequentialAnimators) { mIsReversible = false; } else { Loading @@ -821,7 +813,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } } mIsReversible = true; } private void parseAnimatorSet(AnimatorSet set, long startTime) { Loading Loading @@ -1042,27 +1033,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * to the last seen RenderNode target and start right away. */ protected void recordLastSeenTarget(DisplayListCanvas canvas) { if (mAnimationPending) { mLastSeenTarget = new WeakReference<RenderNode>( RenderNodeAnimatorSetHelper.getTarget(canvas)); if (mPendingAnimationAction != NONE) { if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "Target is set in the next frame"); } mAnimationPending = false; if (mPendingAnimationAction == START_ANIMATION) { start(); } else { mLastSeenTarget = new WeakReference<RenderNode>( RenderNodeAnimatorSetHelper.getTarget(canvas)); } else if (mPendingAnimationAction == REVERSE_ANIMATION) { reverse(); } mPendingAnimationAction = NONE; } private boolean setTarget(RenderNode node) { if (mTarget != null && mTarget.get() != null) { // TODO: Maybe we want to support target change. throw new IllegalStateException("Target already set!"); } private boolean setTarget(RenderNode node) { node.addAnimator(this); mTarget = new WeakReference<RenderNode>(node); return true; Loading @@ -1081,12 +1067,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return; } if (mStarted) { return; } if (!useLastSeenTarget()) { mAnimationPending = true; mPendingAnimationAction = START_ANIMATION; return; } Loading @@ -1094,38 +1076,45 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java"); } nStart(mSetPtr, this); mStarted = true; nStart(mSetPtr, this, ++mLastListenerId); if (mListener != null) { mListener.onAnimationStart(null); } mStarted = true; } public void end() { if (mInitialized && mStarted) { if (mInitialized && useLastSeenTarget()) { // If no target has ever been set, no-op nEnd(mSetPtr); onAnimationEnd(); } } void reset() { if (!mInitialized) { return; } // TODO: Need to implement reset. Log.w(LOGTAG, "Reset is yet to be implemented"); public void reset() { if (mInitialized && useLastSeenTarget()) { // If no target has ever been set, no-op nReset(mSetPtr); } } // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential // animators or when the animator set has a start delay void reverse() { if (!mIsReversible) { if (!mIsReversible || !mInitialized) { return; } // TODO: Need to support reverse (non-public API) Log.w(LOGTAG, "Reverse is yet to be implemented"); nReverse(mSetPtr, this); if (!useLastSeenTarget()) { mPendingAnimationAction = REVERSE_ANIMATION; return; } if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java"); } mStarted = true; nReverse(mSetPtr, this, ++mLastListenerId); if (mListener != null) { mListener.onAnimationStart(null); } } public long getAnimatorNativePtr() { Loading Loading @@ -1155,7 +1144,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mListener = null; } private void onAnimationEnd() { private void onAnimationEnd(int listenerId) { if (listenerId != mLastListenerId) { return; } if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "on finished called from native"); } mStarted = false; if (mListener != null) { mListener.onAnimationEnd(null); Loading @@ -1164,11 +1159,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } // onFinished: should be called from native private static void callOnFinished(VectorDrawableAnimator set) { if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "on finished called from native"); } set.onAnimationEnd(); private static void callOnFinished(VectorDrawableAnimator set, int id) { set.onAnimationEnd(id); } } Loading @@ -1188,8 +1180,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue, float endValue); private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length); private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set); private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set); private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set, int id); private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id); private static native void nEnd(long animatorSetPtr); private static native void nReset(long animatorSetPtr); } libs/hwui/Animator.cpp +119 −25 Original line number Diff line number Diff line Loading @@ -42,7 +42,8 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue) , mStartTime(0) , mDuration(300) , mStartDelay(0) , mMayRunAsync(true) { , mMayRunAsync(true) , mPlayTime(0) { } BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { Loading Loading @@ -85,20 +86,113 @@ void BaseRenderNodeAnimator::attach(RenderNode* target) { onAttached(); } void BaseRenderNodeAnimator::start() { mStagingPlayState = PlayState::Running; mStagingRequests.push_back(Request::Start); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::cancel() { mStagingPlayState = PlayState::Finished; mStagingRequests.push_back(Request::Cancel); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::reset() { mStagingPlayState = PlayState::Finished; mStagingRequests.push_back(Request::Reset); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::reverse() { mStagingPlayState = PlayState::Reversing; mStagingRequests.push_back(Request::Reverse); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::end() { mStagingPlayState = PlayState::Finished; mStagingRequests.push_back(Request::End); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::resolveStagingRequest(Request request) { switch (request) { case Request::Start: mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ? mPlayTime : 0; mPlayState = PlayState::Running; break; case Request::Reverse: mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ? mPlayTime : mDuration; mPlayState = PlayState::Reversing; break; case Request::Reset: mPlayTime = 0; mPlayState = PlayState::Finished; break; case Request::Cancel: mPlayState = PlayState::Finished; break; case Request::End: mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration; mPlayState = PlayState::Finished; break; default: LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request)); }; } void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { if (!mHasStartValue) { doSetStartValue(getValue(mTarget)); } if (mStagingPlayState > mPlayState) { if (mStagingPlayState == PlayState::Restarted) { mStagingPlayState = PlayState::Running; if (!mStagingRequests.empty()) { // Keep track of the play state and play time before they are changed when // staging requests are resolved. nsecs_t currentPlayTime = mPlayTime; PlayState prevFramePlayState = mPlayState; // Resolve staging requests one by one. for (Request request : mStagingRequests) { resolveStagingRequest(request); } mPlayState = mStagingPlayState; // Oh boy, we're starting! Man the battle stations! if (mPlayState == PlayState::Running) { transitionToRunning(context); } else if (mPlayState == PlayState::Finished) { mStagingRequests.clear(); if (mStagingPlayState == PlayState::Finished) { // Set the staging play time and end the animation updatePlayTime(mPlayTime); callOnFinishedListener(context); } else if (mStagingPlayState == PlayState::Running || mStagingPlayState == PlayState::Reversing) { bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState; if (prevFramePlayState != mStagingPlayState) { transitionToRunning(context); } if (changed) { // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was // requested from UI thread). It is achieved by modifying mStartTime, such that // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the // case of reversing) nsecs_t currentFrameTime = context.frameTimeMs(); if (mPlayState == PlayState::Reversing) { // Reverse is not supported for animations with a start delay, so here we // assume no start delay. mStartTime = currentFrameTime - (mDuration - mPlayTime); } else { // Animation should play forward if (mPlayTime == 0) { // If the request is to start from the beginning, include start delay. mStartTime = currentFrameTime + mStartDelay; } else { // If the request is to seek to a non-zero play time, then we skip start // delay. mStartTime = currentFrameTime - mPlayTime; } } } } } } Loading Loading @@ -136,37 +230,37 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) { // This should be set before setValue() so animators can query this time when setValue // is called. nsecs_t currentFrameTime = context.frameTimeMs(); onPlayTimeChanged(currentFrameTime - mStartTime); nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime; bool finished = updatePlayTime(currentPlayTime); if (finished && mPlayState != PlayState::Finished) { mPlayState = PlayState::Finished; callOnFinishedListener(context); } return finished; } bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) { mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime; onPlayTimeChanged(mPlayTime); // If BaseRenderNodeAnimator is handling the delay (not typical), then // because the staging properties reflect the final value, we always need // to call setValue even if the animation isn't yet running or is still // being delayed as we need to override the staging value if (mStartTime > context.frameTimeMs()) { if (playTime < 0) { setValue(mTarget, mFromValue); return false; } float fraction = 1.0f; if (mPlayState == PlayState::Running && mDuration > 0) { fraction = (float)(currentFrameTime - mStartTime) / mDuration; } if (fraction >= 1.0f) { fraction = 1.0f; mPlayState = PlayState::Finished; if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) { fraction = mPlayTime / (float) mDuration; } fraction = MathUtils::clamp(fraction, 0.0f, 1.0f); fraction = mInterpolator->interpolate(fraction); setValue(mTarget, mFromValue + (mDeltaValue * fraction)); if (mPlayState == PlayState::Finished) { callOnFinishedListener(context); return true; } return false; return playTime >= mDuration; } void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { Loading Loading
core/java/android/animation/AnimatorSet.java +2 −0 Original line number Diff line number Diff line Loading @@ -807,6 +807,8 @@ public final class AnimatorSet extends Animator { } /** * AnimatorSet is only reversible when the set contains no sequential animation, and no child * animators have a start delay. * @hide */ @Override Loading
core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +15 −12 Original line number Diff line number Diff line Loading @@ -43,12 +43,13 @@ static JNIEnv* getEnv(JavaVM* vm) { return env; } static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) { static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) { class AnimationListenerBridge : public AnimationListener { public: AnimationListenerBridge(JNIEnv* env, jobject finishListener) { AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) { mFinishListener = env->NewGlobalRef(finishListener); env->GetJavaVM(&mJvm); mId = id; } virtual ~AnimationListenerBridge() { Loading @@ -63,7 +64,7 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis env->CallStaticVoidMethod( gVectorDrawableAnimatorClassInfo.clazz, gVectorDrawableAnimatorClassInfo.callOnFinished, mFinishListener); mFinishListener, mId); releaseJavaObject(); } Loading @@ -76,8 +77,9 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis JavaVM* mJvm; jobject mFinishListener; jint mId; }; return new AnimationListenerBridge(env, finishListener); return new AnimationListenerBridge(env, finishListener, id); } static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr, Loading Loading @@ -142,15 +144,16 @@ static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr, holder->setPropertyDataSource(propertyData, length); env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT); } static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) { static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) { PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); // TODO: keep a ref count in finish listener AnimationListener* listener = createAnimationListener(env, finishListener); AnimationListener* listener = createAnimationListener(env, finishListener, id); set->start(listener); } static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) { // TODO: implement reverse static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) { PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); AnimationListener* listener = createAnimationListener(env, finishListener, id); set->reverse(listener); } static void end(JNIEnv*, jobject, jlong animatorSetPtr) { Loading @@ -172,8 +175,8 @@ static const JNINativeMethod gMethods[] = { {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder}, {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder}, {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData}, {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)start}, {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse}, {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start}, {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse}, {"nEnd", "!(J)V", (void*)end}, {"nReset", "!(J)V", (void*)reset}, }; Loading @@ -186,7 +189,7 @@ int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) { gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie( env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished", "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V"); "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V"); return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable", gMethods, NELEM(gMethods)); } Loading
core/jni/android_view_RenderNodeAnimator.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -184,7 +184,7 @@ static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) { static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) { BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr); animator->end(); animator->cancel(); } // ---------------------------------------------------------------------------- Loading
graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +49 −57 Original line number Diff line number Diff line Loading @@ -238,9 +238,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas); } mAnimatedVectorState.mVectorDrawable.draw(canvas); if (isStarted()) { invalidateSelf(); } } @Override Loading Loading @@ -611,10 +608,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return mAnimatorSet.isRunning(); } private boolean isStarted() { return mAnimatorSet.isStarted(); } /** * Resets the AnimatedVectorDrawable to the start state as specified in the animators. */ Loading @@ -626,12 +619,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void start() { ensureAnimatorSet(); // If any one of the animator has not ended, do nothing. if (isStarted()) { return; } mAnimatorSet.start(); invalidateSelf(); } Loading @@ -652,6 +639,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void stop() { mAnimatorSet.end(); invalidateSelf(); } /** Loading Loading @@ -774,6 +762,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * @hide */ public static class VectorDrawableAnimator { private static final int NONE = 0; private static final int START_ANIMATION = 1; private static final int REVERSE_ANIMATION = 2; private AnimatorListener mListener = null; private final LongArray mStartDelays = new LongArray(); private PropertyValuesHolder.PropertyValues mTmpValues = Loading @@ -782,7 +773,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private boolean mContainsSequentialAnimators = false; private boolean mStarted = false; private boolean mInitialized = false; private boolean mAnimationPending = false; private boolean mIsReversible = false; // This needs to be set before parsing starts. private boolean mShouldIgnoreInvalidAnim; Loading @@ -790,7 +780,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private final VirtualRefBasePtr mSetRefBasePtr; private WeakReference<RenderNode> mTarget = null; private WeakReference<RenderNode> mLastSeenTarget = null; private int mLastListenerId = 0; private int mPendingAnimationAction = NONE; VectorDrawableAnimator() { mSetPtr = nCreateAnimatorSet(); Loading @@ -810,6 +801,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mInitialized = true; // Check reversible. mIsReversible = true; if (mContainsSequentialAnimators) { mIsReversible = false; } else { Loading @@ -821,7 +813,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } } mIsReversible = true; } private void parseAnimatorSet(AnimatorSet set, long startTime) { Loading Loading @@ -1042,27 +1033,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * to the last seen RenderNode target and start right away. */ protected void recordLastSeenTarget(DisplayListCanvas canvas) { if (mAnimationPending) { mLastSeenTarget = new WeakReference<RenderNode>( RenderNodeAnimatorSetHelper.getTarget(canvas)); if (mPendingAnimationAction != NONE) { if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "Target is set in the next frame"); } mAnimationPending = false; if (mPendingAnimationAction == START_ANIMATION) { start(); } else { mLastSeenTarget = new WeakReference<RenderNode>( RenderNodeAnimatorSetHelper.getTarget(canvas)); } else if (mPendingAnimationAction == REVERSE_ANIMATION) { reverse(); } mPendingAnimationAction = NONE; } private boolean setTarget(RenderNode node) { if (mTarget != null && mTarget.get() != null) { // TODO: Maybe we want to support target change. throw new IllegalStateException("Target already set!"); } private boolean setTarget(RenderNode node) { node.addAnimator(this); mTarget = new WeakReference<RenderNode>(node); return true; Loading @@ -1081,12 +1067,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return; } if (mStarted) { return; } if (!useLastSeenTarget()) { mAnimationPending = true; mPendingAnimationAction = START_ANIMATION; return; } Loading @@ -1094,38 +1076,45 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java"); } nStart(mSetPtr, this); mStarted = true; nStart(mSetPtr, this, ++mLastListenerId); if (mListener != null) { mListener.onAnimationStart(null); } mStarted = true; } public void end() { if (mInitialized && mStarted) { if (mInitialized && useLastSeenTarget()) { // If no target has ever been set, no-op nEnd(mSetPtr); onAnimationEnd(); } } void reset() { if (!mInitialized) { return; } // TODO: Need to implement reset. Log.w(LOGTAG, "Reset is yet to be implemented"); public void reset() { if (mInitialized && useLastSeenTarget()) { // If no target has ever been set, no-op nReset(mSetPtr); } } // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential // animators or when the animator set has a start delay void reverse() { if (!mIsReversible) { if (!mIsReversible || !mInitialized) { return; } // TODO: Need to support reverse (non-public API) Log.w(LOGTAG, "Reverse is yet to be implemented"); nReverse(mSetPtr, this); if (!useLastSeenTarget()) { mPendingAnimationAction = REVERSE_ANIMATION; return; } if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java"); } mStarted = true; nReverse(mSetPtr, this, ++mLastListenerId); if (mListener != null) { mListener.onAnimationStart(null); } } public long getAnimatorNativePtr() { Loading Loading @@ -1155,7 +1144,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mListener = null; } private void onAnimationEnd() { private void onAnimationEnd(int listenerId) { if (listenerId != mLastListenerId) { return; } if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "on finished called from native"); } mStarted = false; if (mListener != null) { mListener.onAnimationEnd(null); Loading @@ -1164,11 +1159,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } // onFinished: should be called from native private static void callOnFinished(VectorDrawableAnimator set) { if (DBG_ANIMATION_VECTOR_DRAWABLE) { Log.d(LOGTAG, "on finished called from native"); } set.onAnimationEnd(); private static void callOnFinished(VectorDrawableAnimator set, int id) { set.onAnimationEnd(id); } } Loading @@ -1188,8 +1180,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue, float endValue); private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length); private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set); private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set); private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set, int id); private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id); private static native void nEnd(long animatorSetPtr); private static native void nReset(long animatorSetPtr); }
libs/hwui/Animator.cpp +119 −25 Original line number Diff line number Diff line Loading @@ -42,7 +42,8 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue) , mStartTime(0) , mDuration(300) , mStartDelay(0) , mMayRunAsync(true) { , mMayRunAsync(true) , mPlayTime(0) { } BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { Loading Loading @@ -85,20 +86,113 @@ void BaseRenderNodeAnimator::attach(RenderNode* target) { onAttached(); } void BaseRenderNodeAnimator::start() { mStagingPlayState = PlayState::Running; mStagingRequests.push_back(Request::Start); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::cancel() { mStagingPlayState = PlayState::Finished; mStagingRequests.push_back(Request::Cancel); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::reset() { mStagingPlayState = PlayState::Finished; mStagingRequests.push_back(Request::Reset); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::reverse() { mStagingPlayState = PlayState::Reversing; mStagingRequests.push_back(Request::Reverse); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::end() { mStagingPlayState = PlayState::Finished; mStagingRequests.push_back(Request::End); onStagingPlayStateChanged(); } void BaseRenderNodeAnimator::resolveStagingRequest(Request request) { switch (request) { case Request::Start: mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ? mPlayTime : 0; mPlayState = PlayState::Running; break; case Request::Reverse: mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ? mPlayTime : mDuration; mPlayState = PlayState::Reversing; break; case Request::Reset: mPlayTime = 0; mPlayState = PlayState::Finished; break; case Request::Cancel: mPlayState = PlayState::Finished; break; case Request::End: mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration; mPlayState = PlayState::Finished; break; default: LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request)); }; } void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { if (!mHasStartValue) { doSetStartValue(getValue(mTarget)); } if (mStagingPlayState > mPlayState) { if (mStagingPlayState == PlayState::Restarted) { mStagingPlayState = PlayState::Running; if (!mStagingRequests.empty()) { // Keep track of the play state and play time before they are changed when // staging requests are resolved. nsecs_t currentPlayTime = mPlayTime; PlayState prevFramePlayState = mPlayState; // Resolve staging requests one by one. for (Request request : mStagingRequests) { resolveStagingRequest(request); } mPlayState = mStagingPlayState; // Oh boy, we're starting! Man the battle stations! if (mPlayState == PlayState::Running) { transitionToRunning(context); } else if (mPlayState == PlayState::Finished) { mStagingRequests.clear(); if (mStagingPlayState == PlayState::Finished) { // Set the staging play time and end the animation updatePlayTime(mPlayTime); callOnFinishedListener(context); } else if (mStagingPlayState == PlayState::Running || mStagingPlayState == PlayState::Reversing) { bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState; if (prevFramePlayState != mStagingPlayState) { transitionToRunning(context); } if (changed) { // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was // requested from UI thread). It is achieved by modifying mStartTime, such that // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the // case of reversing) nsecs_t currentFrameTime = context.frameTimeMs(); if (mPlayState == PlayState::Reversing) { // Reverse is not supported for animations with a start delay, so here we // assume no start delay. mStartTime = currentFrameTime - (mDuration - mPlayTime); } else { // Animation should play forward if (mPlayTime == 0) { // If the request is to start from the beginning, include start delay. mStartTime = currentFrameTime + mStartDelay; } else { // If the request is to seek to a non-zero play time, then we skip start // delay. mStartTime = currentFrameTime - mPlayTime; } } } } } } Loading Loading @@ -136,37 +230,37 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) { // This should be set before setValue() so animators can query this time when setValue // is called. nsecs_t currentFrameTime = context.frameTimeMs(); onPlayTimeChanged(currentFrameTime - mStartTime); nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime; bool finished = updatePlayTime(currentPlayTime); if (finished && mPlayState != PlayState::Finished) { mPlayState = PlayState::Finished; callOnFinishedListener(context); } return finished; } bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) { mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime; onPlayTimeChanged(mPlayTime); // If BaseRenderNodeAnimator is handling the delay (not typical), then // because the staging properties reflect the final value, we always need // to call setValue even if the animation isn't yet running or is still // being delayed as we need to override the staging value if (mStartTime > context.frameTimeMs()) { if (playTime < 0) { setValue(mTarget, mFromValue); return false; } float fraction = 1.0f; if (mPlayState == PlayState::Running && mDuration > 0) { fraction = (float)(currentFrameTime - mStartTime) / mDuration; } if (fraction >= 1.0f) { fraction = 1.0f; mPlayState = PlayState::Finished; if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) { fraction = mPlayTime / (float) mDuration; } fraction = MathUtils::clamp(fraction, 0.0f, 1.0f); fraction = mInterpolator->interpolate(fraction); setValue(mTarget, mFromValue + (mDeltaValue * fraction)); if (mPlayState == PlayState::Finished) { callOnFinishedListener(context); return true; } return false; return playTime >= mDuration; } void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { Loading