Animator stuff

 Bug: 17228458

Change-Id: Id884a429a512f9cd2be0ed16dbd0f10e92b4440d
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 7221295a4..3832d42 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -17,6 +17,7 @@
 
 #include <algorithm>
 
+#include "AnimationContext.h"
 #include "RenderNode.h"
 
 namespace android {
@@ -30,7 +31,8 @@
 }
 
 AnimatorManager::AnimatorManager(RenderNode& parent)
-        : mParent(parent) {
+        : mParent(parent)
+        , mAnimationHandle(NULL) {
 }
 
 AnimatorManager::~AnimatorManager() {
@@ -44,6 +46,11 @@
     mNewAnimators.push_back(animator.get());
 }
 
+void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
+    LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
+    mAnimationHandle = handle;
+}
+
 template<typename T>
 static void move_all(T& source, T& dest) {
     dest.reserve(source.size() + dest.size());
@@ -53,26 +60,30 @@
     source.clear();
 }
 
-void AnimatorManager::pushStaging(TreeInfo& info) {
+void AnimatorManager::pushStaging() {
     if (mNewAnimators.size()) {
         // Since this is a straight move, we don't need to inc/dec the ref count
         move_all(mNewAnimators, mAnimators);
     }
     for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
-        (*it)->pushStaging(info);
+        (*it)->pushStaging(mAnimationHandle->context());
     }
 }
 
 class AnimateFunctor {
 public:
-    AnimateFunctor(RenderNode& target, TreeInfo& info)
-            : dirtyMask(0), mTarget(target), mInfo(info) {}
+    AnimateFunctor(TreeInfo& info, AnimationContext& context)
+            : dirtyMask(0), mInfo(info), mContext(context) {}
 
     bool operator() (BaseRenderNodeAnimator* animator) {
         dirtyMask |= animator->dirtyMask();
-        bool remove = animator->animate(mInfo);
+        bool remove = animator->animate(mContext);
         if (remove) {
             animator->decStrong(0);
+        } else {
+            if (animator->isRunning()) {
+                mInfo.out.hasAnimations = true;
+            }
         }
         return remove;
     }
@@ -80,8 +91,8 @@
     uint32_t dirtyMask;
 
 private:
-    RenderNode& mTarget;
     TreeInfo& mInfo;
+    AnimationContext& mContext;
 };
 
 uint32_t AnimatorManager::animate(TreeInfo& info) {
@@ -93,17 +104,70 @@
     mParent.damageSelf(info);
     info.damageAccumulator->popTransform();
 
-    AnimateFunctor functor(mParent, info);
-    std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
-    newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
-    mAnimators.erase(newEnd, mAnimators.end());
+    uint32_t dirty = animateCommon(info);
 
     mParent.mProperties.updateMatrix();
     info.damageAccumulator->pushTransform(&mParent);
     mParent.damageSelf(info);
 
+    return dirty;
+}
+
+void AnimatorManager::animateNoDamage(TreeInfo& info) {
+    if (!mAnimators.size()) return;
+
+    animateCommon(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);
+    mAnimators.erase(newEnd, mAnimators.end());
+    mAnimationHandle->notifyAnimationsRan();
     return functor.dirtyMask;
 }
 
+class EndAnimatorsFunctor {
+public:
+    EndAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
+
+    void operator() (BaseRenderNodeAnimator* animator) {
+        animator->end();
+        animator->pushStaging(mContext);
+        animator->animate(mContext);
+        animator->decStrong(0);
+    }
+
+private:
+    AnimationContext& mContext;
+};
+
+static void endAnimatorsHard(BaseRenderNodeAnimator* animator) {
+    animator->end();
+    if (animator->listener()) {
+        animator->listener()->onAnimationFinished(animator);
+    }
+    animator->decStrong(0);
+}
+
+void AnimatorManager::endAllAnimators() {
+    if (mNewAnimators.size()) {
+        // Since this is a straight move, we don't need to inc/dec the ref count
+        move_all(mNewAnimators, mAnimators);
+    }
+    // First try gracefully ending them
+    if (mAnimationHandle) {
+        EndAnimatorsFunctor functor(mAnimationHandle->context());
+        for_each(mAnimators.begin(), mAnimators.end(), functor);
+    } else {
+        // We have no context, so bust out the sledgehammer
+        // This works because this state can only happen on the UI thread,
+        // which means we're already on the right thread to invoke listeners
+        for_each(mAnimators.begin(), mAnimators.end(), endAnimatorsHard);
+    }
+    mAnimators.clear();
+}
+
 } /* namespace uirenderer */
 } /* namespace android */