Loading core/java/android/view/RenderNode.java +3 −3 Original line number Diff line number Diff line Loading @@ -793,12 +793,12 @@ public class RenderNode { return mOwningView != null && mOwningView.mAttachInfo != null; } public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { public void registerVectorDrawableAnimator( AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { if (mOwningView == null || mOwningView.mAttachInfo == null) { throw new IllegalStateException("Cannot start this animator on a detached view!"); } nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr()); mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this); mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet); } public void endAllAnimators() { Loading core/java/android/view/ThreadedRenderer.java +8 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading Loading @@ -881,6 +882,12 @@ public final class ThreadedRenderer { nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); } void registerVectorDrawableAnimator( AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode, animator.getAnimatorNativePtr()); } public void serializeDisplayListTree() { nSerializeDisplayListTree(mNativeProxy); } Loading Loading @@ -992,6 +999,7 @@ public final class ThreadedRenderer { private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); private static native void nDestroy(long nativeProxy, long rootRenderNode); private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator); private static native void nInvokeFunctor(long functor, boolean waitForCompletion); Loading core/java/android/view/ViewRootImpl.java +8 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; Loading Loading @@ -825,6 +826,13 @@ public final class ViewRootImpl implements ViewParent, } } public void registerVectorDrawableAnimator( AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator); } } private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { mAttachInfo.mHardwareAccelerated = false; mAttachInfo.mHardwareAccelerationRequested = false; Loading core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,12 @@ static jlong createAnimatorSet(JNIEnv*, jobject) { return reinterpret_cast<jlong>(animatorSet); } static void setVectorDrawableTarget(JNIEnv*, jobject,jlong animatorPtr, jlong vectorDrawablePtr) { VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(vectorDrawablePtr); PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr); set->setVectorDrawable(tree); } static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId, jfloat startValue, jfloat endValue) { VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr); Loading Loading @@ -168,6 +174,7 @@ static void reset(JNIEnv*, jobject, jlong animatorSetPtr) { static const JNINativeMethod gMethods[] = { {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet}, {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget}, {"nAddAnimator", "(JJJJJI)V", (void*)addAnimator}, {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder}, {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder}, Loading core/jni/android_view_ThreadedRenderer.cpp +127 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> #include <utils/StrongPointer.h> #include <utils/Timers.h> #include <android_runtime/android_view_Surface.h> #include <system/window.h> Loading @@ -44,6 +45,7 @@ #include <FrameMetricsObserver.h> #include <IContextFactory.h> #include <JankTracker.h> #include <PropertyValuesAnimatorSet.h> #include <RenderNode.h> #include <renderthread/CanvasContext.h> #include <renderthread/RenderProxy.h> Loading Loading @@ -122,6 +124,31 @@ private: std::vector<OnFinishedEvent> mOnFinishedEvents; }; class FinishAndInvokeListener : public MessageHandler { public: explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim) : mAnimator(anim) { mListener = anim->getOneShotListener(); mRequestId = anim->getRequestId(); } virtual void handleMessage(const Message& message) { if (mAnimator->getRequestId() == mRequestId) { // Request Id has not changed, meaning there's no animation lifecyle change since the // message is posted, so go ahead and call finish to make sure the PlayState is properly // updated. This is needed because before the next frame comes in from UI thread to // trigger an animation update, there could be reverse/cancel etc. So we need to update // the playstate in time to ensure all the subsequent events get chained properly. mAnimator->end(); } mListener->onAnimationFinished(nullptr); } private: sp<PropertyValuesAnimatorSet> mAnimator; sp<AnimationListener> mListener; uint32_t mRequestId; }; class RenderingException : public MessageHandler { public: RenderingException(JavaVM* vm, const std::string& message) Loading Loading @@ -160,6 +187,15 @@ public: virtual void prepareTree(TreeInfo& info) override { info.errorHandler = this; for (auto& anim : mVectorDrawableAnimators) { // Assume that the property change in VD from the animators will not be consumed. Mark // otherwise if the VDs are found in the display list tree. For VDs that are not in // the display list tree, we stop providing animation pulses by 1) removing them from // the animation list, 2) post a delayed message to end them at end time so their // listeners can receive the corresponding callbacks. anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false); } // TODO: This is hacky info.windowInsetLeft = -stagingProperties().getLeft(); info.windowInsetTop = -stagingProperties().getTop(); Loading @@ -169,16 +205,46 @@ public: info.windowInsetLeft = 0; info.windowInsetTop = 0; info.errorHandler = nullptr; for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) { // Vector Drawable is not in the display list, we should remove this animator from // the list and post a delayed message to end the animator. detachVectorDrawableAnimator(it->get()); it = mVectorDrawableAnimators.erase(it); } else { ++it; } } info.out.hasAnimations |= !mVectorDrawableAnimators.empty(); } void sendMessage(const sp<MessageHandler>& handler) { mLooper->sendMessage(handler, 0); } void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) { mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0); } void attachAnimatingNode(RenderNode* animatingNode) { mPendingAnimatingRenderNodes.push_back(animatingNode); } void attachPendingVectorDrawableAnimators() { mVectorDrawableAnimators.insert(mPendingVectorDrawableAnimators.begin(), mPendingVectorDrawableAnimators.end()); mPendingVectorDrawableAnimators.clear(); } void detachAnimators() { // Remove animators from the list and post a delayed message in future to end the animator for (auto& anim : mVectorDrawableAnimators) { detachVectorDrawableAnimator(anim.get()); } mVectorDrawableAnimators.clear(); } void doAttachAnimatingNodes(AnimationContext* context) { for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) { RenderNode* node = mPendingAnimatingRenderNodes[i].get(); Loading @@ -187,17 +253,57 @@ public: mPendingAnimatingRenderNodes.clear(); } void runVectorDrawableAnimators(AnimationContext* context) { for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { (*it)->pushStaging(*context); if ((*it)->animate(*context)) { it = mVectorDrawableAnimators.erase(it); } else { ++it; } } } void destroy() { for (auto& renderNode : mPendingAnimatingRenderNodes) { renderNode->animators().endAllStagingAnimators(); } mPendingAnimatingRenderNodes.clear(); mPendingVectorDrawableAnimators.clear(); } void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { mPendingVectorDrawableAnimators.insert(anim); } private: sp<Looper> mLooper; JavaVM* mVm; std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes; std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators; std::set< sp<PropertyValuesAnimatorSet> > mVectorDrawableAnimators; void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { if (anim->isInfinite() || !anim->isRunning()) { // Do not need to post anything if the animation is infinite (i.e. no meaningful // end listener action), or if the animation has already ended. return; } nsecs_t remainingTimeInMs = anim->getRemainingPlayTime(); // Post a delayed onFinished event that is scheduled to be handled when the animator ends. if (anim->getOneShotListener()) { // VectorDrawable's oneshot listener is updated when there are user triggered animation // lifecycle changes, such as start(), end(), etc. By using checking and clearing // one shot listener, we ensure the same end listener event gets posted only once. // Therefore no duplicates. Another benefit of using one shot listener is that no // removal is necessary: the end time of animation will not change unless triggered by // user events, in which case the already posted listener's id will become stale, and // the onFinished callback will then be ignored. sp<FinishAndInvokeListener> message = new FinishAndInvokeListener(anim); sendMessageDelayed(message, remainingTimeInMs); anim->clearOneShotListener(); } } }; class AnimationContextBridge : public AnimationContext { Loading @@ -213,8 +319,16 @@ public: virtual void startFrame(TreeInfo::TraversalMode mode) { if (mode == TreeInfo::MODE_FULL) { mRootNode->doAttachAnimatingNodes(this); mRootNode->attachPendingVectorDrawableAnimators(); } AnimationContext::startFrame(mode); // Run VectorDrawable animators in the beginning of the frame instead of during prepareTree, // because one VD can be in multiple render nodes' display list. So it's more simple to // run them all at once before prepareTree than running them or checking whether they have // already ran in each RenderNode. Note that these animators don't damage the RenderNodes. // The damaging is done in prepareTree as needed after checking whether a VD has been // modified. mRootNode->runVectorDrawableAnimators(this); } // Runs any animations still left in mCurrentFrameAnimations Loading @@ -223,6 +337,10 @@ public: postOnFinishedEvents(); } virtual void detachAnimators() override { mRootNode->detachAnimators(); } virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) { OnFinishedEvent event(animator, listener); mOnFinishedEvents.push_back(event); Loading @@ -230,6 +348,7 @@ public: virtual void destroy() { AnimationContext::destroy(); detachAnimators(); postOnFinishedEvents(); } Loading Loading @@ -527,6 +646,13 @@ static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* en rootRenderNode->attachAnimatingNode(animatingNode); } static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz, jlong rootNodePtr, jlong animatorPtr) { RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr); PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr); rootRenderNode->addVectorDrawableAnimator(animator); } static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, jlong functorPtr, jboolean waitForCompletion) { Functor* functor = reinterpret_cast<Functor*>(functorPtr); Loading Loading @@ -738,6 +864,7 @@ static const JNINativeMethod gMethods[] = { { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy }, { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator }, { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer }, { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer }, Loading Loading
core/java/android/view/RenderNode.java +3 −3 Original line number Diff line number Diff line Loading @@ -793,12 +793,12 @@ public class RenderNode { return mOwningView != null && mOwningView.mAttachInfo != null; } public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { public void registerVectorDrawableAnimator( AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { if (mOwningView == null || mOwningView.mAttachInfo == null) { throw new IllegalStateException("Cannot start this animator on a detached view!"); } nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr()); mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this); mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet); } public void endAllAnimators() { Loading
core/java/android/view/ThreadedRenderer.java +8 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimatedVectorDrawable; import android.os.Binder; import android.os.Handler; import android.os.IBinder; Loading Loading @@ -881,6 +882,12 @@ public final class ThreadedRenderer { nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); } void registerVectorDrawableAnimator( AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode, animator.getAnimatorNativePtr()); } public void serializeDisplayListTree() { nSerializeDisplayListTree(mNativeProxy); } Loading Loading @@ -992,6 +999,7 @@ public final class ThreadedRenderer { private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); private static native void nDestroy(long nativeProxy, long rootRenderNode); private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator); private static native void nInvokeFunctor(long functor, boolean waitForCompletion); Loading
core/java/android/view/ViewRootImpl.java +8 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; Loading Loading @@ -825,6 +826,13 @@ public final class ViewRootImpl implements ViewParent, } } public void registerVectorDrawableAnimator( AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator); } } private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { mAttachInfo.mHardwareAccelerated = false; mAttachInfo.mHardwareAccelerationRequested = false; Loading
core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,12 @@ static jlong createAnimatorSet(JNIEnv*, jobject) { return reinterpret_cast<jlong>(animatorSet); } static void setVectorDrawableTarget(JNIEnv*, jobject,jlong animatorPtr, jlong vectorDrawablePtr) { VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(vectorDrawablePtr); PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr); set->setVectorDrawable(tree); } static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId, jfloat startValue, jfloat endValue) { VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr); Loading Loading @@ -168,6 +174,7 @@ static void reset(JNIEnv*, jobject, jlong animatorSetPtr) { static const JNINativeMethod gMethods[] = { {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet}, {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget}, {"nAddAnimator", "(JJJJJI)V", (void*)addAnimator}, {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder}, {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder}, Loading
core/jni/android_view_ThreadedRenderer.cpp +127 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> #include <utils/StrongPointer.h> #include <utils/Timers.h> #include <android_runtime/android_view_Surface.h> #include <system/window.h> Loading @@ -44,6 +45,7 @@ #include <FrameMetricsObserver.h> #include <IContextFactory.h> #include <JankTracker.h> #include <PropertyValuesAnimatorSet.h> #include <RenderNode.h> #include <renderthread/CanvasContext.h> #include <renderthread/RenderProxy.h> Loading Loading @@ -122,6 +124,31 @@ private: std::vector<OnFinishedEvent> mOnFinishedEvents; }; class FinishAndInvokeListener : public MessageHandler { public: explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim) : mAnimator(anim) { mListener = anim->getOneShotListener(); mRequestId = anim->getRequestId(); } virtual void handleMessage(const Message& message) { if (mAnimator->getRequestId() == mRequestId) { // Request Id has not changed, meaning there's no animation lifecyle change since the // message is posted, so go ahead and call finish to make sure the PlayState is properly // updated. This is needed because before the next frame comes in from UI thread to // trigger an animation update, there could be reverse/cancel etc. So we need to update // the playstate in time to ensure all the subsequent events get chained properly. mAnimator->end(); } mListener->onAnimationFinished(nullptr); } private: sp<PropertyValuesAnimatorSet> mAnimator; sp<AnimationListener> mListener; uint32_t mRequestId; }; class RenderingException : public MessageHandler { public: RenderingException(JavaVM* vm, const std::string& message) Loading Loading @@ -160,6 +187,15 @@ public: virtual void prepareTree(TreeInfo& info) override { info.errorHandler = this; for (auto& anim : mVectorDrawableAnimators) { // Assume that the property change in VD from the animators will not be consumed. Mark // otherwise if the VDs are found in the display list tree. For VDs that are not in // the display list tree, we stop providing animation pulses by 1) removing them from // the animation list, 2) post a delayed message to end them at end time so their // listeners can receive the corresponding callbacks. anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false); } // TODO: This is hacky info.windowInsetLeft = -stagingProperties().getLeft(); info.windowInsetTop = -stagingProperties().getTop(); Loading @@ -169,16 +205,46 @@ public: info.windowInsetLeft = 0; info.windowInsetTop = 0; info.errorHandler = nullptr; for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) { // Vector Drawable is not in the display list, we should remove this animator from // the list and post a delayed message to end the animator. detachVectorDrawableAnimator(it->get()); it = mVectorDrawableAnimators.erase(it); } else { ++it; } } info.out.hasAnimations |= !mVectorDrawableAnimators.empty(); } void sendMessage(const sp<MessageHandler>& handler) { mLooper->sendMessage(handler, 0); } void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) { mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0); } void attachAnimatingNode(RenderNode* animatingNode) { mPendingAnimatingRenderNodes.push_back(animatingNode); } void attachPendingVectorDrawableAnimators() { mVectorDrawableAnimators.insert(mPendingVectorDrawableAnimators.begin(), mPendingVectorDrawableAnimators.end()); mPendingVectorDrawableAnimators.clear(); } void detachAnimators() { // Remove animators from the list and post a delayed message in future to end the animator for (auto& anim : mVectorDrawableAnimators) { detachVectorDrawableAnimator(anim.get()); } mVectorDrawableAnimators.clear(); } void doAttachAnimatingNodes(AnimationContext* context) { for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) { RenderNode* node = mPendingAnimatingRenderNodes[i].get(); Loading @@ -187,17 +253,57 @@ public: mPendingAnimatingRenderNodes.clear(); } void runVectorDrawableAnimators(AnimationContext* context) { for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { (*it)->pushStaging(*context); if ((*it)->animate(*context)) { it = mVectorDrawableAnimators.erase(it); } else { ++it; } } } void destroy() { for (auto& renderNode : mPendingAnimatingRenderNodes) { renderNode->animators().endAllStagingAnimators(); } mPendingAnimatingRenderNodes.clear(); mPendingVectorDrawableAnimators.clear(); } void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { mPendingVectorDrawableAnimators.insert(anim); } private: sp<Looper> mLooper; JavaVM* mVm; std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes; std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators; std::set< sp<PropertyValuesAnimatorSet> > mVectorDrawableAnimators; void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { if (anim->isInfinite() || !anim->isRunning()) { // Do not need to post anything if the animation is infinite (i.e. no meaningful // end listener action), or if the animation has already ended. return; } nsecs_t remainingTimeInMs = anim->getRemainingPlayTime(); // Post a delayed onFinished event that is scheduled to be handled when the animator ends. if (anim->getOneShotListener()) { // VectorDrawable's oneshot listener is updated when there are user triggered animation // lifecycle changes, such as start(), end(), etc. By using checking and clearing // one shot listener, we ensure the same end listener event gets posted only once. // Therefore no duplicates. Another benefit of using one shot listener is that no // removal is necessary: the end time of animation will not change unless triggered by // user events, in which case the already posted listener's id will become stale, and // the onFinished callback will then be ignored. sp<FinishAndInvokeListener> message = new FinishAndInvokeListener(anim); sendMessageDelayed(message, remainingTimeInMs); anim->clearOneShotListener(); } } }; class AnimationContextBridge : public AnimationContext { Loading @@ -213,8 +319,16 @@ public: virtual void startFrame(TreeInfo::TraversalMode mode) { if (mode == TreeInfo::MODE_FULL) { mRootNode->doAttachAnimatingNodes(this); mRootNode->attachPendingVectorDrawableAnimators(); } AnimationContext::startFrame(mode); // Run VectorDrawable animators in the beginning of the frame instead of during prepareTree, // because one VD can be in multiple render nodes' display list. So it's more simple to // run them all at once before prepareTree than running them or checking whether they have // already ran in each RenderNode. Note that these animators don't damage the RenderNodes. // The damaging is done in prepareTree as needed after checking whether a VD has been // modified. mRootNode->runVectorDrawableAnimators(this); } // Runs any animations still left in mCurrentFrameAnimations Loading @@ -223,6 +337,10 @@ public: postOnFinishedEvents(); } virtual void detachAnimators() override { mRootNode->detachAnimators(); } virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) { OnFinishedEvent event(animator, listener); mOnFinishedEvents.push_back(event); Loading @@ -230,6 +348,7 @@ public: virtual void destroy() { AnimationContext::destroy(); detachAnimators(); postOnFinishedEvents(); } Loading Loading @@ -527,6 +646,13 @@ static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* en rootRenderNode->attachAnimatingNode(animatingNode); } static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz, jlong rootNodePtr, jlong animatorPtr) { RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr); PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr); rootRenderNode->addVectorDrawableAnimator(animator); } static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, jlong functorPtr, jboolean waitForCompletion) { Functor* functor = reinterpret_cast<Functor*>(functorPtr); Loading Loading @@ -738,6 +864,7 @@ static const JNINativeMethod gMethods[] = { { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy }, { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator }, { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer }, { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer }, Loading