OSDN Git Service

Animator refactoring & fixes
authorJohn Reck <jreck@google.com>
Tue, 24 Jun 2014 22:34:58 +0000 (15:34 -0700)
committerJohn Reck <jreck@google.com>
Thu, 26 Jun 2014 17:45:43 +0000 (10:45 -0700)
 Tweaks animators to have less unnecessary refcounting

 Pull animator management out into seperate class

 More control to tweak animator lifecycle, such as doing
 Java-side handling of start delay by attaching but not
 starting the animator

Change-Id: I4ff8207580ca11fb38f45ef0007b406e0097281c

17 files changed:
core/java/android/view/RenderNode.java
core/java/android/view/RenderNodeAnimator.java
core/jni/android_view_RenderNode.cpp
core/jni/android_view_RenderNodeAnimator.cpp
libs/hwui/Android.mk
libs/hwui/Animator.cpp
libs/hwui/Animator.h
libs/hwui/AnimatorManager.cpp [new file with mode: 0644]
libs/hwui/AnimatorManager.h [new file with mode: 0644]
libs/hwui/DeferredLayerUpdater.cpp
libs/hwui/DeferredLayerUpdater.h
libs/hwui/RenderNode.cpp
libs/hwui/RenderNode.h
libs/hwui/TreeInfo.h
libs/hwui/renderthread/CanvasContext.cpp
libs/hwui/renderthread/CanvasContext.h
libs/hwui/renderthread/DrawFrameTask.cpp

index d86b699..ddc185c 100644 (file)
@@ -21,9 +21,6 @@ import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * <p>A display list records a series of graphics related operations and can replay
  * them later. Display lists are usually built by recording operations on a
@@ -180,12 +177,6 @@ public class RenderNode {
     private boolean mValid;
     private final long mNativeRenderNode;
 
-    // We need to keep a strong reference to all running animators to ensure that
-    // they can call removeAnimator when they have finished, as the native-side
-    // object can only hold a WeakReference<> to avoid leaking memory due to
-    // cyclic references.
-    private List<RenderNodeAnimator> mActiveAnimators;
-
     private RenderNode(String name) {
         mNativeRenderNode = nCreate(name);
     }
@@ -866,18 +857,9 @@ public class RenderNode {
     ///////////////////////////////////////////////////////////////////////////
 
     public void addAnimator(RenderNodeAnimator animator) {
-        if (mActiveAnimators == null) {
-            mActiveAnimators = new ArrayList<RenderNodeAnimator>();
-        }
-        mActiveAnimators.add(animator);
         nAddAnimator(mNativeRenderNode, animator.getNativeAnimator());
     }
 
-    public void removeAnimator(RenderNodeAnimator animator) {
-        nRemoveAnimator(mNativeRenderNode, animator.getNativeAnimator());
-        mActiveAnimators.remove(animator);
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Native methods
     ///////////////////////////////////////////////////////////////////////////
@@ -960,7 +942,6 @@ public class RenderNode {
     ///////////////////////////////////////////////////////////////////////////
 
     private static native void nAddAnimator(long renderNode, long animatorPtr);
-    private static native void nRemoveAnimator(long renderNode, long animatorPtr);
 
     ///////////////////////////////////////////////////////////////////////////
     // Finalization
index 4979059..1363a5c 100644 (file)
@@ -172,12 +172,14 @@ public final class RenderNodeAnimator extends Animator {
 
     @Override
     public void cancel() {
-        mTarget.removeAnimator(this);
-
-        final ArrayList<AnimatorListener> listeners = getListeners();
-        final int numListeners = listeners == null ? 0 : listeners.size();
-        for (int i = 0; i < numListeners; i++) {
-            listeners.get(i).onAnimationCancel(this);
+        if (!mFinished) {
+            nCancel(mNativePtr.get());
+
+            final ArrayList<AnimatorListener> listeners = getListeners();
+            final int numListeners = listeners == null ? 0 : listeners.size();
+            for (int i = 0; i < numListeners; i++) {
+                listeners.get(i).onAnimationCancel(this);
+            }
         }
     }
 
@@ -219,10 +221,6 @@ public final class RenderNodeAnimator extends Animator {
         return mTarget;
     }
 
-    /**
-     * WARNING: May only be called once!!!
-     * TODO: Fix above -_-
-     */
     public void setStartValue(float startValue) {
         checkMutable();
         nSetStartValue(mNativePtr.get(), startValue);
@@ -231,6 +229,9 @@ public final class RenderNodeAnimator extends Animator {
     @Override
     public void setStartDelay(long startDelay) {
         checkMutable();
+        if (startDelay < 0) {
+            throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
+        }
         nSetStartDelay(mNativePtr.get(), startDelay);
     }
 
@@ -242,6 +243,9 @@ public final class RenderNodeAnimator extends Animator {
     @Override
     public RenderNodeAnimator setDuration(long duration) {
         checkMutable();
+        if (duration < 0) {
+            throw new IllegalArgumentException("duration must be positive; " + duration);
+        }
         nSetDuration(mNativePtr.get(), duration);
         return this;
     }
@@ -269,7 +273,6 @@ public final class RenderNodeAnimator extends Animator {
 
     private void onFinished() {
         mFinished = true;
-        mTarget.removeAnimator(this);
 
         final ArrayList<AnimatorListener> listeners = getListeners();
         final int numListeners = listeners == null ? 0 : listeners.size();
@@ -296,10 +299,13 @@ public final class RenderNodeAnimator extends Animator {
             long canvasProperty, float finalValue);
     private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
             long canvasProperty, int paintField, float finalValue);
+
     private static native void nSetStartValue(long nativePtr, float startValue);
     private static native void nSetDuration(long nativePtr, long duration);
     private static native long nGetDuration(long nativePtr);
     private static native void nSetStartDelay(long nativePtr, long startDelay);
     private static native long nGetStartDelay(long nativePtr);
     private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
+
+    private static native void nCancel(long animPtr);
 }
index 3ffde2d..6ba22bf 100644 (file)
@@ -456,16 +456,9 @@ static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz,
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
     renderNode->addAnimator(animator);
+    animator->start();
 }
 
-static void android_view_RenderNode_removeAnimator(JNIEnv* env, jobject clazz,
-        jlong renderNodePtr, jlong animatorPtr) {
-    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
-    renderNode->removeAnimator(animator);
-}
-
-
 #endif // USE_OPENGL_RENDERER
 
 // ----------------------------------------------------------------------------
@@ -546,7 +539,6 @@ static JNINativeMethod gMethods[] = {
     { "nGetPivotY",                "(J)F",  (void*) android_view_RenderNode_getPivotY },
 
     { "nAddAnimator",              "(JJ)V", (void*) android_view_RenderNode_addAnimator },
-    { "nRemoveAnimator",           "(JJ)V", (void*) android_view_RenderNode_removeAnimator },
 #endif
 };
 
index d689864..de3dd16 100644 (file)
@@ -149,6 +149,11 @@ static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong
     animator->setInterpolator(interpolator);
 }
 
+static void cancel(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    animator->cancel();
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -168,6 +173,7 @@ static JNINativeMethod gMethods[] = {
     { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
     { "nGetStartDelay", "(J)J", (void*) getStartDelay },
     { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
+    { "nCancel", "(J)V", (void*) cancel },
 #endif
 };
 
index a704e19..1a96b2f 100644 (file)
@@ -13,6 +13,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
                font/Font.cpp \
                AmbientShadow.cpp \
                Animator.cpp \
+               AnimatorManager.cpp \
                AssetAtlas.cpp \
                DamageAccumulator.cpp \
                FontRenderer.cpp \
index dc6d852..4a8c122 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "Animator.h"
 
+#include <inttypes.h>
 #include <set>
 
 #include "RenderNode.h"
@@ -35,72 +36,105 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
         , mDeltaValue(0)
         , mFromValue(0)
         , mInterpolator(0)
-        , mPlayState(NEEDS_START)
+        , mStagingPlayState(NOT_STARTED)
+        , mPlayState(NOT_STARTED)
+        , mHasStartValue(false)
         , mStartTime(0)
-        , mDelayUntil(0)
         , mDuration(300)
         , mStartDelay(0) {
-
 }
 
 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
-    setInterpolator(NULL);
+    delete mInterpolator;
+}
+
+void BaseRenderNodeAnimator::checkMutable() {
+    // Should be impossible to hit as the Java-side also has guards for this
+    LOG_ALWAYS_FATAL_IF(mStagingPlayState != NOT_STARTED,
+            "Animator has already been started!");
 }
 
 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
+    checkMutable();
     delete mInterpolator;
     mInterpolator = interpolator;
 }
 
 void BaseRenderNodeAnimator::setStartValue(float value) {
-    LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
-            "Cannot set the start value after the animator has started!");
-    mFromValue = value;
-    mDeltaValue = (mFinalValue - mFromValue);
-    mPlayState = PENDING;
+    checkMutable();
+    doSetStartValue(value);
 }
 
-void BaseRenderNodeAnimator::setupStartValueIfNecessary(RenderNode* target, TreeInfo& info) {
-    if (mPlayState == NEEDS_START) {
-        setStartValue(getValue(target));
-    }
+void BaseRenderNodeAnimator::doSetStartValue(float value) {
+    mFromValue = value;
+    mDeltaValue = (mFinalValue - mFromValue);
+    mHasStartValue = true;
 }
 
 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
+    checkMutable();
     mDuration = duration;
 }
 
 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
+    checkMutable();
     mStartDelay = startDelay;
 }
 
-bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
-    if (mPlayState == PENDING && mStartDelay > 0 && mDelayUntil == 0) {
-        mDelayUntil = info.frameTimeMs + mStartDelay;
-        return false;
+void BaseRenderNodeAnimator::pushStaging(RenderNode* target, TreeInfo& info) {
+    if (!mHasStartValue) {
+        doSetStartValue(getValue(target));
     }
+    if (mStagingPlayState > mPlayState) {
+        mPlayState = mStagingPlayState;
+        // Oh boy, we're starting! Man the battle stations!
+        if (mPlayState == RUNNING) {
+            transitionToRunning(info);
+        }
+    }
+}
 
-    if (mDelayUntil > info.frameTimeMs) {
+void BaseRenderNodeAnimator::transitionToRunning(TreeInfo& info) {
+    LOG_ALWAYS_FATAL_IF(info.frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", info.frameTimeMs);
+    if (mStartDelay < 0 || mStartDelay > 50000) {
+        ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay);
+    }
+    mStartTime = info.frameTimeMs + mStartDelay;
+    if (mStartTime < 0) {
+        ALOGW("Ended up with a really weird start time of %" PRId64
+                " with frame time %" PRId64 " and start delay %" PRId64,
+                mStartTime, info.frameTimeMs, mStartDelay);
+        // Set to 0 so that the animate() basically instantly finishes
+        mStartTime = 0;
+    }
+    // No interpolator was set, use the default
+    if (!mInterpolator) {
+        setInterpolator(Interpolator::createDefaultInterpolator());
+    }
+    if (mDuration < 0 || mDuration > 50000) {
+        ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
+    }
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+    if (mPlayState < RUNNING) {
         return false;
     }
 
-    if (mPlayState == PENDING) {
-        mPlayState = RUNNING;
-        mStartTime = info.frameTimeMs;
-        // No interpolator was set, use the default
-        if (!mInterpolator) {
-            setInterpolator(Interpolator::createDefaultInterpolator());
-        }
+    if (mStartTime > info.frameTimeMs) {
+        info.out.hasAnimations |= true;
+        return false;
     }
 
     float fraction = 1.0f;
-    if (mPlayState == RUNNING) {
-        fraction = mDuration > 0 ? (float)(info.frameTimeMs - mStartTime) / mDuration : 1.0f;
-        if (fraction >= 1.0f) {
-            fraction = 1.0f;
-            mPlayState = FINISHED;
-        }
+    if (mPlayState == RUNNING && mDuration > 0) {
+        fraction = (float)(info.frameTimeMs - mStartTime) / mDuration;
     }
+    if (fraction >= 1.0f) {
+        fraction = 1.0f;
+        mPlayState = FINISHED;
+    }
+
     fraction = mInterpolator->interpolate(fraction);
     setValue(target, mFromValue + (mDeltaValue * fraction));
 
@@ -108,6 +142,8 @@ bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
         callOnFinishedListener(info);
         return true;
     }
+
+    info.out.hasAnimations |= true;
     return false;
 }
 
@@ -153,7 +189,7 @@ RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float fi
 }
 
 void RenderPropertyAnimator::onAttached(RenderNode* target) {
-    if (mPlayState == NEEDS_START
+    if (!mHasStartValue
             && target->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
         setStartValue((target->stagingProperties().*mPropertyAccess->getter)());
     }
index 6cb72c4..a981b5a 100644 (file)
@@ -50,12 +50,11 @@ public:
     ANDROID_API void setListener(AnimationListener* listener) {
         mListener = listener;
     }
+    ANDROID_API void start() { mStagingPlayState = RUNNING; }
+    ANDROID_API void cancel() { mStagingPlayState = FINISHED; }
 
-    ANDROID_API virtual void onAttached(RenderNode* target) {}
-
-    // Guaranteed to happen before the staging push
-    void setupStartValueIfNecessary(RenderNode* target, TreeInfo& info);
-
+    virtual void onAttached(RenderNode* target) {}
+    virtual void pushStaging(RenderNode* target, TreeInfo& info);
     bool animate(RenderNode* target, TreeInfo& info);
 
     bool isFinished() { return mPlayState == FINISHED; }
@@ -73,8 +72,7 @@ protected:
     void callOnFinishedListener(TreeInfo& info);
 
     enum PlayState {
-        NEEDS_START,
-        PENDING,
+        NOT_STARTED,
         RUNNING,
         FINISHED,
     };
@@ -84,13 +82,19 @@ protected:
     float mFromValue;
 
     Interpolator* mInterpolator;
+    PlayState mStagingPlayState;
     PlayState mPlayState;
+    bool mHasStartValue;
     nsecs_t mStartTime;
-    nsecs_t mDelayUntil;
     nsecs_t mDuration;
     nsecs_t mStartDelay;
 
     sp<AnimationListener> mListener;
+
+private:
+    void doSetStartValue(float value);
+    inline void checkMutable();
+    void transitionToRunning(TreeInfo& info);
 };
 
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
@@ -112,7 +116,7 @@ public:
 
     ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
 
-    ANDROID_API virtual void onAttached(RenderNode* target);
+    virtual void onAttached(RenderNode* target);
 
     ANDROID_API virtual uint32_t dirtyMask();
 
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
new file mode 100644 (file)
index 0000000..6a10cf8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "AnimatorManager.h"
+
+#include <algorithm>
+
+#include "RenderNode.h"
+
+namespace android {
+namespace uirenderer {
+
+using namespace std;
+
+static void unref(BaseRenderNodeAnimator* animator) {
+    animator->decStrong(0);
+}
+
+AnimatorManager::AnimatorManager(RenderNode& parent)
+        : mParent(parent) {
+}
+
+AnimatorManager::~AnimatorManager() {
+    for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
+    for_each(mAnimators.begin(), mAnimators.end(), unref);
+}
+
+void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+    animator->incStrong(0);
+    animator->onAttached(&mParent);
+    mNewAnimators.push_back(animator.get());
+}
+
+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(TreeInfo& info) {
+    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(&mParent, info);
+    }
+}
+
+class AnimateFunctor {
+public:
+    AnimateFunctor(RenderNode& target, TreeInfo& info)
+            : mTarget(target), mInfo(info) {}
+
+    bool operator() (BaseRenderNodeAnimator* animator) {
+        bool remove = animator->animate(&mTarget, mInfo);
+        if (remove) {
+            animator->decStrong(0);
+        }
+        return remove;
+    }
+private:
+    RenderNode& mTarget;
+    TreeInfo& mInfo;
+};
+
+void AnimatorManager::animate(TreeInfo& info) {
+    if (!mAnimators.size()) return;
+
+    // TODO: Can we target this better? For now treat it like any other staging
+    // property push and just damage self before and after animators are run
+
+    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());
+
+    mParent.mProperties.updateMatrix();
+    info.damageAccumulator->pushTransform(&mParent);
+    mParent.damageSelf(info);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
new file mode 100644 (file)
index 0000000..2568121
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANIMATORMANAGER_H
+#define ANIMATORMANAGER_H
+
+#include <vector>
+
+#include <cutils/compiler.h>
+#include <utils/StrongPointer.h>
+
+#include "TreeInfo.h"
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+class BaseRenderNodeAnimator;
+class RenderNode;
+
+// Responsible for managing the animators for a single RenderNode
+class AnimatorManager {
+    PREVENT_COPY_AND_ASSIGN(AnimatorManager);
+public:
+    AnimatorManager(RenderNode& parent);
+    ~AnimatorManager();
+
+    void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
+
+    void pushStaging(TreeInfo& info);
+    void animate(TreeInfo& info);
+
+private:
+    RenderNode& mParent;
+
+    // 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;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* ANIMATORMANAGER_H */
index 8e99b9a..02b0372 100644 (file)
@@ -58,7 +58,7 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
     SkRefCnt_SafeAssign(mColorFilter, colorFilter);
 }
 
-bool DeferredLayerUpdater::apply(TreeInfo& info) {
+bool DeferredLayerUpdater::apply() {
     bool success = true;
     // These properties are applied the same to both layer types
     mLayer->setColorFilter(mColorFilter);
index c76bd5e..5905b95 100644 (file)
@@ -75,7 +75,7 @@ public:
 
     ANDROID_API void setPaint(const SkPaint* paint);
 
-    ANDROID_API bool apply(TreeInfo& info);
+    ANDROID_API bool apply();
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
index 131384a..e803ec3 100644 (file)
@@ -62,7 +62,7 @@ RenderNode::RenderNode()
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0)
-        , mNeedsAnimatorsSync(false)
+        , mAnimatorManager(*this)
         , mLayer(0) {
 }
 
@@ -117,6 +117,10 @@ void RenderNode::prepareTree(TreeInfo& info) {
     prepareTreeImpl(info);
 }
 
+void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+    mAnimatorManager.addAnimator(animator);
+}
+
 void RenderNode::damageSelf(TreeInfo& info) {
     if (isRenderable()) {
         if (properties().getClipDamageToBounds()) {
@@ -193,11 +197,11 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
     info.damageAccumulator->pushTransform(this);
     if (info.mode == TreeInfo::MODE_FULL) {
         pushStagingPropertiesChanges(info);
-        evaluateAnimations(info);
+        mAnimatorManager.animate(info);
     } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
         pushStagingPropertiesChanges(info);
     } else if (info.mode == TreeInfo::MODE_RT_ONLY) {
-        evaluateAnimations(info);
+        mAnimatorManager.animate(info);
     }
 
     prepareLayer(info);
@@ -210,33 +214,11 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
     info.damageAccumulator->popTransform();
 }
 
-class PushAnimatorsFunctor {
-public:
-    PushAnimatorsFunctor(RenderNode* target, TreeInfo& info)
-            : mTarget(target), mInfo(info) {}
-
-    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
-        animator->setupStartValueIfNecessary(mTarget, mInfo);
-        return animator->isFinished();
-    }
-private:
-    RenderNode* mTarget;
-    TreeInfo& mInfo;
-};
-
 void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
     // Push the animators first so that setupStartValueIfNecessary() is called
     // before properties() is trampled by stagingProperties(), as they are
     // required by some animators.
-    if (mNeedsAnimatorsSync) {
-        mAnimators.resize(mStagingAnimators.size());
-        std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
-        PushAnimatorsFunctor functor(this, info);
-        // hint: this means copy_if_not()
-        it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
-                mAnimators.begin(), functor);
-        mAnimators.resize(std::distance(mAnimators.begin(), it));
-    }
+    mAnimatorManager.pushStaging(info);
     if (mDirtyPropertyFields) {
         mDirtyPropertyFields = 0;
         damageSelf(info);
@@ -267,8 +249,7 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
         // that are no longer used
-        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info.renderState);
-        oldTreeInfo.damageAccumulator = info.damageAccumulator;
+        TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info);
         prepareSubTree(oldTreeInfo, mDisplayListData);
         delete mDisplayListData;
         mDisplayListData = mStagingDisplayListData;
@@ -277,39 +258,6 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
     }
 }
 
-class AnimateFunctor {
-public:
-    AnimateFunctor(RenderNode* target, TreeInfo& info)
-            : mTarget(target), mInfo(info) {}
-
-    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
-        return animator->animate(mTarget, mInfo);
-    }
-private:
-    RenderNode* mTarget;
-    TreeInfo& mInfo;
-};
-
-void RenderNode::evaluateAnimations(TreeInfo& info) {
-    if (!mAnimators.size()) return;
-
-    // TODO: Can we target this better? For now treat it like any other staging
-    // property push and just damage self before and after animators are run
-
-    damageSelf(info);
-    info.damageAccumulator->popTransform();
-
-    AnimateFunctor functor(this, info);
-    std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd;
-    newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
-    mAnimators.erase(newEnd, mAnimators.end());
-    mProperties.updateMatrix();
-    info.out.hasAnimations |= mAnimators.size();
-
-    info.damageAccumulator->pushTransform(this);
-    damageSelf(info);
-}
-
 void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
     if (subtree) {
         TextureCache& cache = Caches::getInstance().textureCache;
index 3980dad..7d42b59 100644 (file)
     #define LOG_TAG "OpenGLRenderer"
 #endif
 
-#include <set>
-#include <vector>
-
 #include <SkCamera.h>
 #include <SkMatrix.h>
 
-#include <private/hwui/DrawGlInfo.h>
-
-#include <utils/KeyedVector.h>
 #include <utils/LinearAllocator.h>
 #include <utils/RefBase.h>
-#include <utils/SortedVector.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
@@ -39,6 +32,7 @@
 
 #include <androidfw/ResourceTypes.h>
 
+#include "AnimatorManager.h"
 #include "DamageAccumulator.h"
 #include "Debug.h"
 #include "Matrix.h"
@@ -176,19 +170,7 @@ public:
     ANDROID_API virtual void prepareTree(TreeInfo& info);
 
     // UI thread only!
-    ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-        animator->onAttached(this);
-        mStagingAnimators.insert(animator);
-        mNeedsAnimatorsSync = true;
-    }
-
-    // UI thread only!
-    ANDROID_API void removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-        mStagingAnimators.erase(animator);
-        // Force a sync of the staging property value
-        mDirtyPropertyFields |= animator->dirtyMask();
-        mNeedsAnimatorsSync = true;
-    }
+    ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
 
 protected:
     virtual void damageSelf(TreeInfo& info);
@@ -262,7 +244,6 @@ private:
     void prepareTreeImpl(TreeInfo& info);
     void pushStagingPropertiesChanges(TreeInfo& info);
     void pushStagingDisplayListChanges(TreeInfo& info);
-    void evaluateAnimations(TreeInfo& info);
     void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
     void applyLayerPropertiesToLayer(TreeInfo& info);
     void prepareLayer(TreeInfo& info);
@@ -278,9 +259,8 @@ private:
     DisplayListData* mDisplayListData;
     DisplayListData* mStagingDisplayListData;
 
-    bool mNeedsAnimatorsSync;
-    std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
-    std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+    friend class AnimatorManager;
+    AnimatorManager mAnimatorManager;
 
     // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
     // being in ~RenderNode() which may happen on any thread.
index 249e525..083100e 100644 (file)
@@ -79,6 +79,17 @@ public:
         , errorHandler(NULL)
     {}
 
+    explicit TreeInfo(TraversalMode mode, const TreeInfo& clone)
+        : mode(mode)
+        , frameTimeMs(clone.frameTimeMs)
+        , animationHook(clone.animationHook)
+        , prepareTextures(mode == MODE_FULL)
+        , damageAccumulator(clone.damageAccumulator)
+        , renderState(clone.renderState)
+        , renderer(clone.renderer)
+        , errorHandler(clone.errorHandler)
+    {}
+
     const TraversalMode mode;
     nsecs_t frameTimeMs;
     AnimationHook* animationHook;
index 281a8e1..9c3cf44 100644 (file)
@@ -123,8 +123,8 @@ void CanvasContext::makeCurrent() {
     mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);
 }
 
-void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info) {
-    bool success = layerUpdater->apply(info);
+void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
+    bool success = layerUpdater->apply();
     LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
     if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
         mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
@@ -237,8 +237,7 @@ void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
 
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
-    TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState());
-    layer->apply(info);
+    layer->apply();
     return LayerRenderer::copyLayer(mRenderThread.renderState(), layer->backingLayer(), bitmap);
 }
 
index d2ce1a6..dbfb3d2 100644 (file)
@@ -56,7 +56,7 @@ public:
     void setup(int width, int height, const Vector3& lightCenter, float lightRadius);
     void setOpaque(bool opaque);
     void makeCurrent();
-    void processLayerUpdate(DeferredLayerUpdater* layerUpdater, TreeInfo& info);
+    void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
     void prepareTree(TreeInfo& info);
     void draw();
     void destroyCanvasAndSurface();
index fddffd5..dd34e09 100644 (file)
@@ -127,7 +127,7 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
     Caches::getInstance().textureCache.resetMarkInUse();
 
     for (size_t i = 0; i < mLayers.size(); i++) {
-        mContext->processLayerUpdate(mLayers[i].get(), info);
+        mContext->processLayerUpdate(mLayers[i].get());
     }
     mLayers.clear();
     mContext->prepareTree(info);