diff options
author | 2016-02-19 21:39:21 +0000 | |
---|---|---|
committer | 2016-02-19 13:51:31 -0800 | |
commit | c4bb185d41cfb960ed9a3178a4f8974c351abdb0 (patch) | |
tree | 8fce2eab0422581acb8342def694abe23ed2c824 | |
parent | 53503069895918a59a305addaac84ea11937edcf (diff) |
VectorDrawable native rendering - Step 5 of MANY
This is reverting the revert of what reverts the revert of the original
implementation. Fourth revert is a charm!
This reverts commit df7fdb1e0bdb5c289bbc08047e5c710185503309.
Change-Id: I6fc3a5accfd8b79c3da31bbc101ad9e9b4d6e7dd
-rw-r--r-- | core/java/android/animation/AnimatorSet.java | 2 | ||||
-rw-r--r-- | core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp | 27 | ||||
-rw-r--r-- | core/jni/android_view_RenderNodeAnimator.cpp | 2 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java | 106 | ||||
-rw-r--r-- | libs/hwui/Animator.cpp | 144 | ||||
-rw-r--r-- | libs/hwui/Animator.h | 59 | ||||
-rw-r--r-- | libs/hwui/AnimatorManager.cpp | 64 | ||||
-rw-r--r-- | libs/hwui/AnimatorManager.h | 8 | ||||
-rw-r--r-- | libs/hwui/PropertyValuesAnimatorSet.cpp | 60 | ||||
-rw-r--r-- | libs/hwui/PropertyValuesAnimatorSet.h | 1 |
10 files changed, 304 insertions, 169 deletions
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 980329fe31c8..3385a17002bc 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -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 diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp index 7a3c598e0aed..14badb72a195 100644 --- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp @@ -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() { @@ -63,7 +64,7 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis env->CallStaticVoidMethod( gVectorDrawableAnimatorClassInfo.clazz, gVectorDrawableAnimatorClassInfo.callOnFinished, - mFinishListener); + mFinishListener, mId); releaseJavaObject(); } @@ -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, @@ -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) { @@ -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}, }; @@ -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)); } diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp index 0926e9b76691..c9eac79ef9b6 100644 --- a/core/jni/android_view_RenderNodeAnimator.cpp +++ b/core/jni/android_view_RenderNodeAnimator.cpp @@ -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(); } // ---------------------------------------------------------------------------- diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index af8ccf5018b9..99bc306821ef 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -238,9 +238,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas); } mAnimatedVectorState.mVectorDrawable.draw(canvas); - if (isStarted()) { - invalidateSelf(); - } } @Override @@ -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. */ @@ -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(); } @@ -652,6 +639,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void stop() { mAnimatorSet.end(); + invalidateSelf(); } /** @@ -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 = @@ -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; @@ -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(); @@ -810,6 +801,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mInitialized = true; // Check reversible. + mIsReversible = true; if (mContainsSequentialAnimators) { mIsReversible = false; } else { @@ -821,7 +813,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } } - mIsReversible = true; } private void parseAnimatorSet(AnimatorSet set, long startTime) { @@ -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)); + 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; - start(); - } else { - mLastSeenTarget = new WeakReference<RenderNode>( - RenderNodeAnimatorSetHelper.getTarget(canvas)); + if (mPendingAnimationAction == START_ANIMATION) { + start(); + } 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!"); - } - node.addAnimator(this); mTarget = new WeakReference<RenderNode>(node); return true; @@ -1081,12 +1067,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return; } - if (mStarted) { - return; - } - if (!useLastSeenTarget()) { - mAnimationPending = true; + mPendingAnimationAction = START_ANIMATION; return; } @@ -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; + public void reset() { + if (mInitialized && useLastSeenTarget()) { + // If no target has ever been set, no-op + nReset(mSetPtr); } - // TODO: Need to implement reset. - Log.w(LOGTAG, "Reset is yet to be implemented"); - 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; + } + if (!useLastSeenTarget()) { + mPendingAnimationAction = REVERSE_ANIMATION; return; } - // TODO: Need to support reverse (non-public API) - Log.w(LOGTAG, "Reverse is yet to be implemented"); - nReverse(mSetPtr, this); + 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() { @@ -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); @@ -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); } } @@ -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); } diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp index 7bd2b24bf56b..372bcb3b2375 100644 --- a/libs/hwui/Animator.cpp +++ b/libs/hwui/Animator.cpp @@ -42,7 +42,8 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue) , mStartTime(0) , mDuration(300) , mStartDelay(0) - , mMayRunAsync(true) { + , mMayRunAsync(true) + , mPlayTime(0) { } BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { @@ -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; + } + } + } } } } @@ -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) { diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h index 2c9c9c3fe0f9..fcbc11b0306c 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -24,6 +24,8 @@ #include "utils/Macros.h" +#include <vector> + namespace android { namespace uirenderer { @@ -59,14 +61,14 @@ public: mMayRunAsync = mayRunAsync; } bool mayRunAsync() { return mMayRunAsync; } - ANDROID_API void start() { - if (mStagingPlayState == PlayState::NotStarted) { - mStagingPlayState = PlayState::Running; - } else { - mStagingPlayState = PlayState::Restarted; - } - onStagingPlayStateChanged(); } - ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); } + ANDROID_API void start(); + ANDROID_API void reset(); + ANDROID_API void reverse(); + // Terminates the animation at its current progress. + ANDROID_API void cancel(); + + // Terminates the animation and skip to the end of the animation. + ANDROID_API void end(); void attach(RenderNode* target); virtual void onAttached() {} @@ -74,36 +76,41 @@ public: void pushStaging(AnimationContext& context); bool animate(AnimationContext& context); - bool isRunning() { return mPlayState == PlayState::Running; } + bool isRunning() { return mPlayState == PlayState::Running + || mPlayState == PlayState::Reversing; } bool isFinished() { return mPlayState == PlayState::Finished; } float finalValue() { return mFinalValue; } ANDROID_API virtual uint32_t dirtyMask() = 0; void forceEndNow(AnimationContext& context); + RenderNode* target() { return mTarget; } protected: // PlayState is used by mStagingPlayState and mPlayState to track the state initiated from UI // thread and Render Thread animation state, respectively. // From the UI thread, mStagingPlayState transition looks like - // NotStarted -> Running -> Finished - // ^ | - // | | - // Restarted <------ + // NotStarted -> Running/Reversing -> Finished + // ^ | + // | | + // ---------------------- // Note: For mStagingState, the Finished state (optional) is only set when the animation is // terminated by user. // // On Render Thread, mPlayState transition: - // NotStart -> Running -> Finished - // ^ | - // | | - // ------------- + // NotStart -> Running/Reversing-> Finished + // ^ | + // | | + // ------------------ + // Note that if the animation is in Running/Reversing state, calling start or reverse again + // would do nothing if the animation has the same play direction as the request; otherwise, + // the animation would start from where it is and change direction (i.e. Reversing <-> Running) enum class PlayState { NotStarted, Running, + Reversing, Finished, - Restarted, }; BaseRenderNodeAnimator(float finalValue); @@ -111,7 +118,6 @@ protected: virtual float getValue(RenderNode* target) const = 0; virtual void setValue(RenderNode* target, float value) = 0; - RenderNode* target() { return mTarget; } void callOnFinishedListener(AnimationContext& context); @@ -132,13 +138,28 @@ protected: nsecs_t mDuration; nsecs_t mStartDelay; bool mMayRunAsync; + // Play Time tracks the progress of animation, it should always be [0, mDuration], 0 being + // the beginning of the animation, will reach mDuration at the end of an animation. + nsecs_t mPlayTime; sp<AnimationListener> mListener; private: + enum class Request { + Start, + Reverse, + Reset, + Cancel, + End + }; inline void checkMutable(); virtual void transitionToRunning(AnimationContext& context); void doSetStartValue(float value); + bool updatePlayTime(nsecs_t playTime); + void resolveStagingRequest(Request request); + + std::vector<Request> mStagingRequests; + }; class RenderPropertyAnimator : public BaseRenderNodeAnimator { diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp index cd30b1859384..2b49b4743d89 100644 --- a/libs/hwui/AnimatorManager.cpp +++ b/libs/hwui/AnimatorManager.cpp @@ -27,9 +27,8 @@ namespace uirenderer { using namespace std; -static void unref(BaseRenderNodeAnimator* animator) { +static void detach(sp<BaseRenderNodeAnimator>& animator) { animator->detach(); - animator->decStrong(nullptr); } AnimatorManager::AnimatorManager(RenderNode& parent) @@ -38,14 +37,12 @@ AnimatorManager::AnimatorManager(RenderNode& parent) } AnimatorManager::~AnimatorManager() { - for_each(mNewAnimators.begin(), mNewAnimators.end(), unref); - for_each(mAnimators.begin(), mAnimators.end(), unref); + for_each(mNewAnimators.begin(), mNewAnimators.end(), detach); + for_each(mAnimators.begin(), mAnimators.end(), detach); } void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) { - animator->incStrong(nullptr); - animator->attach(&mParent); - mNewAnimators.push_back(animator.get()); + mNewAnimators.emplace_back(animator.get()); } void AnimatorManager::setAnimationHandle(AnimationHandle* handle) { @@ -56,25 +53,31 @@ void AnimatorManager::setAnimationHandle(AnimationHandle* handle) { &mParent, mParent.getName()); } -template<typename T> -static void move_all(T& source, T& dest) { - dest.reserve(source.size() + dest.size()); - for (typename T::iterator it = source.begin(); it != source.end(); it++) { - dest.push_back(*it); - } - source.clear(); -} - void AnimatorManager::pushStaging() { if (mNewAnimators.size()) { LOG_ALWAYS_FATAL_IF(!mAnimationHandle, "Trying to start new animators on %p (%s) without an animation handle!", &mParent, mParent.getName()); - // Since this is a straight move, we don't need to inc/dec the ref count - move_all(mNewAnimators, mAnimators); + // Only add animators that are not already in the on-going animator list. + for (auto& animator : mNewAnimators) { + RenderNode* targetRenderNode = animator->target(); + if (targetRenderNode == &mParent) { + // Animator already in the animator list: skip adding again + continue; + } + + if (targetRenderNode){ + // If the animator is already in another RenderNode's animator list, remove animator from + // that list and add animator to current RenderNode's list. + targetRenderNode->animators().removeActiveAnimator(animator); + } + animator->attach(&mParent); + mAnimators.push_back(std::move(animator)); + } + mNewAnimators.clear(); } - for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) { - (*it)->pushStaging(mAnimationHandle->context()); + for (auto& animator : mAnimators) { + animator->pushStaging(mAnimationHandle->context()); } } @@ -83,11 +86,11 @@ public: AnimateFunctor(TreeInfo& info, AnimationContext& context) : dirtyMask(0), mInfo(info), mContext(context) {} - bool operator() (BaseRenderNodeAnimator* animator) { + bool operator() (sp<BaseRenderNodeAnimator>& animator) { dirtyMask |= animator->dirtyMask(); bool remove = animator->animate(mContext); if (remove) { - animator->decStrong(nullptr); + animator->detach(); } else { if (animator->isRunning()) { mInfo.out.hasAnimations = true; @@ -129,20 +132,18 @@ void AnimatorManager::animateNoDamage(TreeInfo& info) { uint32_t AnimatorManager::animateCommon(TreeInfo& info) { AnimateFunctor functor(info, mAnimationHandle->context()); - std::vector< BaseRenderNodeAnimator* >::iterator newEnd; - newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor); + auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor); mAnimators.erase(newEnd, mAnimators.end()); mAnimationHandle->notifyAnimationsRan(); mParent.mProperties.updateMatrix(); return functor.dirtyMask; } -static void endStagingAnimator(BaseRenderNodeAnimator* animator) { - animator->end(); +static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) { + animator->cancel(); if (animator->listener()) { - animator->listener()->onAnimationFinished(animator); + animator->listener()->onAnimationFinished(animator.get()); } - animator->decStrong(nullptr); } void AnimatorManager::endAllStagingAnimators() { @@ -153,13 +154,16 @@ void AnimatorManager::endAllStagingAnimators() { mNewAnimators.clear(); } +void AnimatorManager::removeActiveAnimator(const sp<BaseRenderNodeAnimator>& animator) { + std::remove(mAnimators.begin(), mAnimators.end(), animator); +} + class EndActiveAnimatorsFunctor { public: EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {} - void operator() (BaseRenderNodeAnimator* animator) { + void operator() (sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); - animator->decStrong(nullptr); } private: diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h index fb75eb8599b4..c24ef47a4644 100644 --- a/libs/hwui/AnimatorManager.h +++ b/libs/hwui/AnimatorManager.h @@ -62,13 +62,17 @@ public: private: uint32_t animateCommon(TreeInfo& info); + // This would remove the animator from mAnimators list. It should only be called during + // push staging. + void removeActiveAnimator(const sp<BaseRenderNodeAnimator>& animator); + RenderNode& mParent; AnimationHandle* mAnimationHandle; // To improve the efficiency of resizing & removing from the vector // use manual ref counting instead of sp<>. - std::vector<BaseRenderNodeAnimator*> mNewAnimators; - std::vector<BaseRenderNodeAnimator*> mAnimators; + std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators; + std::vector< sp<BaseRenderNodeAnimator> > mAnimators; }; } /* namespace uirenderer */ diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp index eca1afcc54dc..b29f91ff34aa 100644 --- a/libs/hwui/PropertyValuesAnimatorSet.cpp +++ b/libs/hwui/PropertyValuesAnimatorSet.cpp @@ -17,6 +17,8 @@ #include "PropertyValuesAnimatorSet.h" #include "RenderNode.h" +#include <algorithm> + namespace android { namespace uirenderer { @@ -53,16 +55,26 @@ void PropertyValuesAnimatorSet::setValue(RenderNode* target, float value) { } void PropertyValuesAnimatorSet::onPlayTimeChanged(nsecs_t playTime) { - for (size_t i = 0; i < mAnimators.size(); i++) { - mAnimators[i]->setCurrentPlayTime(playTime); + if (playTime == 0 && mDuration > 0) { + // Reset all the animators + for (auto it = mAnimators.rbegin(); it != mAnimators.rend(); it++) { + // Note that this set may containing animators modifying the same property, so when we + // reset the animators, we need to make sure the animators that end the first will + // have the final say on what the property value should be. + (*it)->setFraction(0); + } + } else if (playTime >= mDuration) { + // Skip all the animators to end + for (auto& anim : mAnimators) { + anim->setFraction(1); + } + } else { + for (auto& anim : mAnimators) { + anim->setCurrentPlayTime(playTime); + } } } -void PropertyValuesAnimatorSet::reset() { - // TODO: implement reset through adding a play state because we need to support reset() even - // during an animation run. -} - void PropertyValuesAnimatorSet::start(AnimationListener* listener) { init(); mOneShotListener = listener; @@ -70,20 +82,23 @@ void PropertyValuesAnimatorSet::start(AnimationListener* listener) { } void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) { -// TODO: implement reverse + init(); + mOneShotListener = listener; + BaseRenderNodeAnimator::reverse(); } void PropertyValuesAnimatorSet::init() { if (mInitialized) { return; } - nsecs_t maxDuration = 0; - for (size_t i = 0; i < mAnimators.size(); i++) { - if (maxDuration < mAnimators[i]->getTotalDuration()) { - maxDuration = mAnimators[i]->getTotalDuration(); - } - } - mDuration = maxDuration; + + // Sort the animators by their total duration. Note that all the animators in the set start at + // the same time, so the ones with longer total duration (which includes start delay) will + // be the ones that end later. + std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) { + return a->getTotalDuration() < b->getTotalDuration(); + }); + mDuration = mAnimators[mAnimators.size() - 1]->getTotalDuration(); mInitialized = true; } @@ -106,18 +121,19 @@ PropertyAnimator::PropertyAnimator(PropertyValuesHolder* holder, Interpolator* i void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) { if (playTime >= mStartDelay && playTime < mTotalDuration) { nsecs_t currentIterationPlayTime = (playTime - mStartDelay) % mDuration; - mLatestFraction = currentIterationPlayTime / (float) mDuration; + float fraction = currentIterationPlayTime / (float) mDuration; + setFraction(fraction); } else if (mLatestFraction < 1.0f && playTime >= mTotalDuration) { - mLatestFraction = 1.0f; - } else { - return; + // This makes sure we only set the fraction = 1 once. It is needed because there might + // be another animator modifying the same property after this animator finishes, we need + // to make sure we don't set conflicting values on the same property within one frame. + setFraction(1.0f); } - - setFraction(mLatestFraction); } void PropertyAnimator::setFraction(float fraction) { - float interpolatedFraction = mInterpolator->interpolate(mLatestFraction); + mLatestFraction = fraction; + float interpolatedFraction = mInterpolator->interpolate(fraction); mPropertyValuesHolder->setFraction(interpolatedFraction); } diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h index 4c7ce528bb20..c7ae7c0e8ce1 100644 --- a/libs/hwui/PropertyValuesAnimatorSet.h +++ b/libs/hwui/PropertyValuesAnimatorSet.h @@ -50,7 +50,6 @@ public: void start(AnimationListener* listener); void reverse(AnimationListener* listener); - void reset(); void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder, Interpolator* interpolators, int64_t startDelays, |