Merge "Handle hidden RT VectorDrawable animators" into nyc-mr1-dev
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index ab4cbcf..0164fcd 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -793,12 +793,12 @@
         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() {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e650d95..fcca739 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -23,6 +23,7 @@
 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;
@@ -881,6 +882,12 @@
         nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
     }
 
+    void registerVectorDrawableAnimator(
+        AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+        nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
+                animator.getAnimatorNativePtr());
+    }
+
     public void serializeDisplayListTree() {
         nSerializeDisplayListTree(mNativeProxy);
     }
@@ -992,6 +999,7 @@
     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);
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4742818..06c8e01 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -42,6 +42,7 @@
 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;
@@ -824,6 +825,13 @@
         }
     }
 
+    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;
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 4b2a72d..0ba88e6 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -95,6 +95,12 @@
     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);
@@ -168,6 +174,7 @@
 
 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},
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 5b4bfe9..212bf57 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -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>
 
@@ -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>
@@ -122,6 +124,31 @@
     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)
@@ -160,6 +187,15 @@
 
     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();
@@ -169,16 +205,46 @@
         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();
@@ -187,17 +253,57 @@
         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 {
@@ -213,8 +319,16 @@
     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
@@ -223,6 +337,10 @@
         postOnFinishedEvents();
     }
 
+    virtual void detachAnimators() override {
+        mRootNode->detachAnimators();
+    }
+
     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
         OnFinishedEvent event(animator, listener);
         mOnFinishedEvents.push_back(event);
@@ -230,6 +348,7 @@
 
     virtual void destroy() {
         AnimationContext::destroy();
+        detachAnimators();
         postOnFinishedEvents();
     }
 
@@ -528,6 +647,13 @@
     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);
@@ -739,6 +865,7 @@
     { "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 },
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 7fa3947..44d95d2 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -158,7 +158,7 @@
     private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
 
     /** Local, mutable animator set. */
-    private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorUI(this);
+    private VectorDrawableAnimator mAnimatorSet;
 
     /**
      * The resources against which this drawable was created. Used to attempt
@@ -183,6 +183,7 @@
 
     private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
         mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
+        mAnimatorSet = new VectorDrawableAnimatorRT(this);
         mRes = res;
     }
 
@@ -1033,7 +1034,7 @@
         private WeakReference<RenderNode> mLastSeenTarget = null;
         private int mLastListenerId = 0;
         private final IntArray mPendingAnimationActions = new IntArray();
-        private final Drawable mDrawable;
+        private final AnimatedVectorDrawable mDrawable;
 
         VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
             mDrawable = drawable;
@@ -1052,6 +1053,9 @@
             }
             mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
             parseAnimatorSet(set, 0);
+            long vectorDrawableTreePtr = mDrawable.mAnimatedVectorState.mVectorDrawable
+                    .getNativeTree();
+            nSetVectorDrawableTarget(mSetPtr, vectorDrawableTreePtr);
             mInitialized = true;
             mIsInfinite = set.getTotalDuration() == Animator.DURATION_INFINITE;
 
@@ -1288,16 +1292,19 @@
          * to the last seen RenderNode target and start right away.
          */
         protected void recordLastSeenTarget(DisplayListCanvas canvas) {
-            mLastSeenTarget = new WeakReference<RenderNode>(
-                    RenderNodeAnimatorSetHelper.getTarget(canvas));
-            if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) {
-                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                    Log.d(LOGTAG, "Target is set in the next frame");
+            final RenderNode node = RenderNodeAnimatorSetHelper.getTarget(canvas);
+            mLastSeenTarget = new WeakReference<RenderNode>(node);
+            // Add the animator to the list of animators on every draw
+            if (mInitialized || mPendingAnimationActions.size() > 0) {
+                if (useTarget(node)) {
+                    if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                        Log.d(LOGTAG, "Target is set in the next frame");
+                    }
+                    for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+                        handlePendingAction(mPendingAnimationActions.get(i));
+                    }
+                    mPendingAnimationActions.clear();
                 }
-                for (int i = 0; i < mPendingAnimationActions.size(); i++) {
-                    handlePendingAction(mPendingAnimationActions.get(i));
-                }
-                mPendingAnimationActions.clear();
             }
         }
 
@@ -1319,10 +1326,15 @@
         private boolean useLastSeenTarget() {
             if (mLastSeenTarget != null) {
                 final RenderNode target = mLastSeenTarget.get();
-                if (target != null && target.isAttached()) {
-                    target.addAnimator(this);
-                    return true;
-                }
+                return useTarget(target);
+            }
+            return false;
+        }
+
+        private boolean useTarget(RenderNode target) {
+            if (target != null && target.isAttached()) {
+                target.registerVectorDrawableAnimator(this);
+                return true;
             }
             return false;
         }
@@ -1517,6 +1529,7 @@
     }
 
     private static native long nCreateAnimatorSet();
+    private static native void nSetVectorDrawableTarget(long animatorPtr, long vectorDrawablePtr);
     private static native void nAddAnimator(long setPtr, long propertyValuesHolder,
              long nativeInterpolator, long startDelay, long duration, int repeatCount);
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 237c931..a8c8737 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -761,6 +761,13 @@
         return mVectorState.mAutoMirrored;
     }
 
+    /**
+     * @hide
+     */
+    public long getNativeTree() {
+        return mVectorState.getNativeRenderer();
+    }
+
     static class VectorDrawableState extends ConstantState {
         // Variables below need to be copied (deep copy if applicable) for mutation.
         int[] mThemeAttrs;
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 909ed36..801fd87 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -100,6 +100,8 @@
 
     ANDROID_API virtual void destroy();
 
+    ANDROID_API virtual void detachAnimators() {}
+
 private:
     friend class AnimationHandle;
     void addAnimationHandle(AnimationHandle* handle);
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 4d65782..dc18018 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -274,6 +274,10 @@
     return playTime >= mDuration;
 }
 
+nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
+    return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
+}
+
 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
     if (mPlayState < PlayState::Finished) {
         mPlayState = PlayState::Finished;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fdae0f3..9476750 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -62,19 +62,23 @@
     }
     bool mayRunAsync() { return mMayRunAsync; }
     ANDROID_API void start();
-    ANDROID_API void reset();
+    ANDROID_API virtual 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();
+    ANDROID_API virtual void end();
 
     void attach(RenderNode* target);
     virtual void onAttached() {}
     void detach() { mTarget = nullptr; }
-    void pushStaging(AnimationContext& context);
-    bool animate(AnimationContext& context);
+    ANDROID_API void pushStaging(AnimationContext& context);
+    ANDROID_API bool animate(AnimationContext& context);
+
+    // Returns the remaining time in ms for the animation. Note this should only be called during
+    // an animation on RenderThread.
+    ANDROID_API nsecs_t getRemainingPlayTime();
 
     bool isRunning() { return mPlayState == PlayState::Running
             || mPlayState == PlayState::Reversing; }
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index b572bda..28be05c 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,7 +45,7 @@
         , regions(stdAllocator)
         , referenceHolders(stdAllocator)
         , functors(stdAllocator)
-        , pushStagingFunctors(stdAllocator)
+        , vectorDrawables(stdAllocator)
         , hasDrawOps(false) {
 }
 
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5b3227b..ccf71c6 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -69,6 +69,11 @@
 typedef DrawRenderNodeOp NodeOpType;
 #endif
 
+namespace VectorDrawable {
+class Tree;
+};
+typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
+
 /**
  * Holds data used in the playback a tree of DisplayLists.
  */
@@ -110,16 +115,6 @@
     LinearAllocator mReplayAllocator;
 };
 
-/**
- * Functor that can be used for objects with data in both UI thread and RT to keep the data
- * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
- */
-struct PushStagingFunctor {
-    PushStagingFunctor() {}
-    virtual ~PushStagingFunctor() {}
-    virtual void operator ()() {}
-};
-
 struct FunctorContainer {
     Functor* functor;
     GlFunctorLifecycleListener* listener;
@@ -161,7 +156,7 @@
 
     const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
     const LsaVector<FunctorContainer>& getFunctors() const { return functors; }
-    const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
+    const LsaVector<VectorDrawableRoot*>& getVectorDrawables() { return vectorDrawables; }
 
     size_t addChild(NodeOpType* childOp);
 
@@ -203,10 +198,10 @@
     // List of functors
     LsaVector<FunctorContainer> functors;
 
-    // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+    // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
     // but a callback during sync DisplayList, unlike the list of functors defined above, which
     // gets special treatment exclusive for webview.
-    LsaVector<PushStagingFunctor*> pushStagingFunctors;
+    LsaVector<VectorDrawableRoot*> vectorDrawables;
 
     bool hasDrawOps; // only used if !HWUI_NEW_OPS
 
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index ca968ce..bec66295 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -417,7 +417,7 @@
 
 void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
     mDisplayList->ref(tree);
-    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+    mDisplayList->vectorDrawables.push_back(tree);
     addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
 }
 
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index b29f91f..e416e0c 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -30,6 +30,11 @@
             interpolator, startDelay, duration, repeatCount);
     mAnimators.emplace_back(animator);
     setListener(new PropertyAnimatorSetListener(this));
+
+    // Check whether any child animator is infinite after adding it them to the set.
+    if (repeatCount == -1) {
+        mIsInfinite = true;
+    }
 }
 
 PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
@@ -78,15 +83,27 @@
 void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
     init();
     mOneShotListener = listener;
+    mRequestId++;
     BaseRenderNodeAnimator::start();
 }
 
 void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
     init();
     mOneShotListener = listener;
+    mRequestId++;
     BaseRenderNodeAnimator::reverse();
 }
 
+void PropertyValuesAnimatorSet::reset() {
+    mRequestId++;
+    BaseRenderNodeAnimator::reset();
+}
+
+void PropertyValuesAnimatorSet::end() {
+    mRequestId++;
+    BaseRenderNodeAnimator::end();
+}
+
 void PropertyValuesAnimatorSet::init() {
     if (mInitialized) {
         return;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index c7ae7c0..49021bc 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -43,6 +43,7 @@
     float mLatestFraction = 0.0f;
 };
 
+// TODO: This class should really be named VectorDrawableAnimator
 class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator {
 public:
     friend class PropertyAnimatorSetListener;
@@ -50,11 +51,19 @@
 
     void start(AnimationListener* listener);
     void reverse(AnimationListener* listener);
+    virtual void reset() override;
+    virtual void end() override;
 
     void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
             Interpolator* interpolators, int64_t startDelays,
             nsecs_t durations, int repeatCount);
     virtual uint32_t dirtyMask();
+    bool isInfinite() { return mIsInfinite; }
+    void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
+    VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable; }
+    AnimationListener* getOneShotListener() { return mOneShotListener.get(); }
+    void clearOneShotListener() { mOneShotListener = nullptr; }
+    uint32_t getRequestId() const { return mRequestId; }
 
 protected:
     virtual float getValue(RenderNode* target) const override;
@@ -69,6 +78,11 @@
     std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
     float mLastFraction = 0.0f;
     bool mInitialized = false;
+    VectorDrawableRoot* mVectorDrawable = nullptr;
+    bool mIsInfinite = false;
+    // This request id gets incremented (on UI thread only) when a new request to modfiy the
+    // lifecycle of an animation happens, namely when start/end/reset/reverse is called.
+    uint32_t mRequestId = 0;
 };
 
 class PropertyAnimatorSetListener : public AnimationListener {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b49f9b5..b35c926 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -440,8 +440,8 @@
 }
 
 void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
-    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
     mDisplayList->ref(tree);
+    mDisplayList->vectorDrawables.push_back(tree);
     addOp(alloc().create_trivial<VectorDrawableOp>(
             tree,
             Rect(tree->stagingProperties()->getBounds()),
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6e848fd..0f6c43e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -419,6 +419,14 @@
     prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
     pushLayerUpdate(info);
 
+    for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+        // If any vector drawable in the display list needs update, damage the node.
+        if (vectorDrawable->isDirty()) {
+            damageSelf(info);
+        }
+        vectorDrawable->setPropertyChangeWillBeConsumed(true);
+    }
+
     info.damageAccumulator->popTransform();
 }
 
@@ -477,8 +485,8 @@
         for (auto& iter : mDisplayList->getFunctors()) {
             (*iter.functor)(DrawGlInfo::kModeSync, nullptr);
         }
-        for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
-            (*mDisplayList->getPushStagingFunctors()[i])();
+        for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+            vectorDrawable->syncProperties();
         }
     }
 }
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index a5d1d4b..e67dfdd 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -673,21 +673,16 @@
     void onPropertyChanged(TreeProperties* prop);
     TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
     const TreeProperties* stagingProperties() const { return &mStagingProperties; }
-    PushStagingFunctor* getFunctor() { return &mFunctor;}
 
     // This should only be called from animations on RT
     TreeProperties* mutateProperties() { return &mProperties; }
 
+    // This should always be called from RT.
+    bool isDirty() const { return mCache.dirty; }
+    bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
+    void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
+
 private:
-    class VectorDrawableFunctor : public PushStagingFunctor {
-    public:
-        VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
-        virtual void operator ()() {
-            mTree->syncProperties();
-        }
-    private:
-        Tree* mTree;
-    };
 
     SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
     bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
@@ -704,8 +699,6 @@
     TreeProperties mProperties = TreeProperties(this);
     TreeProperties mStagingProperties = TreeProperties(this);
 
-    VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
-
     SkPaint mPaint;
     struct Cache {
         SkBitmap bitmap;
@@ -717,6 +710,8 @@
 
     PropertyChangedListener mPropertyChangedListener
             = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+
+    mutable bool mWillBeConsumed = false;
 };
 
 } // namespace VectorDrawable
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e6399d4..597c5c5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -278,6 +278,7 @@
 
 void CanvasContext::stopDrawing() {
     mRenderThread.removeFrameCallback(this);
+    mAnimationContext->detachAnimators();
 }
 
 void CanvasContext::notifyFramePending() {