Animator start value...

Change-Id: Ifd35ed95a28c625086d7fa97764fe63ab4a997f1
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index a033f86..83eedfb 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -27,31 +27,48 @@
 namespace uirenderer {
 
 /************************************************************
- *  Base animator
+ *  BaseRenderNodeAnimator
  ************************************************************/
 
-BaseAnimator::BaseAnimator()
-        : mInterpolator(0)
-        , mPlayState(PENDING)
+BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
+        : mFinalValue(finalValue)
+        , mDeltaValue(0)
+        , mFromValue(0)
+        , mInterpolator(0)
+        , mPlayState(NEEDS_START)
         , mStartTime(0)
-        , mDuration(300) {
-
+        , mDuration(300){
 }
 
-BaseAnimator::~BaseAnimator() {
+BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
     setInterpolator(NULL);
 }
 
-void BaseAnimator::setInterpolator(Interpolator* interpolator) {
+void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
     delete mInterpolator;
     mInterpolator = interpolator;
 }
 
-void BaseAnimator::setDuration(nsecs_t duration) {
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
     mDuration = duration;
 }
 
-bool BaseAnimator::animateFrame(TreeInfo& info) {
+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;
+}
+
+void BaseRenderNodeAnimator::setupStartValueIfNecessary(RenderNode* target, TreeInfo& info) {
+    if (mPlayState == NEEDS_START) {
+        setStartValue(getValue(target));
+        mPlayState = PENDING;
+    }
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
     if (mPlayState == PENDING) {
         mPlayState = RUNNING;
         mStartTime = info.frameTimeMs;
@@ -59,7 +76,6 @@
         if (!mInterpolator) {
             setInterpolator(Interpolator::createDefaultInterpolator());
         }
-        onAnimationStarted();
     }
 
     float fraction = 1.0f;
@@ -71,17 +87,16 @@
         }
     }
     fraction = mInterpolator->interpolate(fraction);
-    onAnimationUpdated(fraction);
+    setValue(target, mFromValue + (mDeltaValue * fraction));
 
     if (mPlayState == FINISHED) {
-        onAnimationFinished();
         callOnFinishedListener(info);
         return true;
     }
     return false;
 }
 
-void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
+void BaseRenderNodeAnimator::callOnFinishedListener(TreeInfo& info) {
     if (mListener.get()) {
         if (!info.animationHook) {
             mListener->onAnimationFinished(this);
@@ -92,70 +107,49 @@
 }
 
 /************************************************************
- *  BaseRenderNodeAnimator
- ************************************************************/
-
-BaseRenderNodeAnimator::BaseRenderNodeAnimator(
-                BaseRenderNodeAnimator::DeltaValueType deltaType, float delta)
-        : mTarget(0)
-        , mDeltaValueType(deltaType)
-        , mDeltaValue(delta)
-        , mFromValue(-1) {
-}
-
-bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
-    mTarget = target;
-    bool finished = animateFrame(info);
-    mTarget = NULL;
-    return finished;
-}
-
-void BaseRenderNodeAnimator::onAnimationStarted() {
-    mFromValue = getValue();
-
-    if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) {
-        mDeltaValue = (mDeltaValue - mFromValue);
-        mDeltaValueType = BaseRenderNodeAnimator::DELTA;
-    }
-}
-
-void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) {
-    float value = mFromValue + (mDeltaValue * fraction);
-    setValue(value);
-}
-
-/************************************************************
  *  RenderPropertyAnimator
  ************************************************************/
 
-// Maps RenderProperty enum to accessors
-const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
-    {&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
-    {&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
-    {&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
-    {&RenderProperties::getScaleX, &RenderProperties::setScaleX },
-    {&RenderProperties::getScaleY, &RenderProperties::setScaleY },
-    {&RenderProperties::getRotation, &RenderProperties::setRotation },
-    {&RenderProperties::getRotationX, &RenderProperties::setRotationX },
-    {&RenderProperties::getRotationY, &RenderProperties::setRotationY },
-    {&RenderProperties::getX, &RenderProperties::setX },
-    {&RenderProperties::getY, &RenderProperties::setY },
-    {&RenderProperties::getZ, &RenderProperties::setZ },
-    {&RenderProperties::getAlpha, &RenderProperties::setAlpha },
+struct RenderPropertyAnimator::PropertyAccessors {
+   RenderNode::DirtyPropertyMask dirtyMask;
+   GetFloatProperty getter;
+   SetFloatProperty setter;
 };
 
-RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
-                DeltaValueType deltaType, float deltaValue)
-        : BaseRenderNodeAnimator(deltaType, deltaValue)
-        , mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
+// Maps RenderProperty enum to accessors
+const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
+    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
+    {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
+    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
+    {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
+    {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
+    {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
+    {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
+    {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
+    {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
+    {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
+    {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
+    {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
+};
+
+RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
+        : BaseRenderNodeAnimator(finalValue)
+        , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
 }
 
-float RenderPropertyAnimator::getValue() const {
-    return (target()->animatorProperties().*mPropertyAccess.getter)();
+void RenderPropertyAnimator::onAttached(RenderNode* target) {
+    if (target->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+        setStartValue((target->stagingProperties().*mPropertyAccess->getter)());
+    }
+    (target->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
 }
 
-void RenderPropertyAnimator::setValue(float value) {
-    (target()->animatorProperties().*mPropertyAccess.setter)(value);
+float RenderPropertyAnimator::getValue(RenderNode* target) const {
+    return (target->properties().*mPropertyAccess->getter)();
+}
+
+void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
+    (target->animatorProperties().*mPropertyAccess->setter)(value);
 }
 
 /************************************************************
@@ -163,16 +157,16 @@
  ************************************************************/
 
 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
-                CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
-        : BaseRenderNodeAnimator(deltaType, deltaValue)
+                CanvasPropertyPrimitive* property, float finalValue)
+        : BaseRenderNodeAnimator(finalValue)
         , mProperty(property) {
 }
 
-float CanvasPropertyPrimitiveAnimator::getValue() const {
+float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
     return mProperty->value;
 }
 
-void CanvasPropertyPrimitiveAnimator::setValue(float value) {
+void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
     mProperty->value = value;
 }
 
@@ -181,14 +175,13 @@
  ************************************************************/
 
 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
-                CanvasPropertyPaint* property, PaintField field,
-                DeltaValueType deltaType, float deltaValue)
-        : BaseRenderNodeAnimator(deltaType, deltaValue)
+                CanvasPropertyPaint* property, PaintField field, float finalValue)
+        : BaseRenderNodeAnimator(finalValue)
         , mProperty(property)
         , mField(field) {
 }
 
-float CanvasPropertyPaintAnimator::getValue() const {
+float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
     switch (mField) {
     case STROKE_WIDTH:
         return mProperty->value.getStrokeWidth();
@@ -204,7 +197,7 @@
     return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
 }
 
-void CanvasPropertyPaintAnimator::setValue(float value) {
+void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
     switch (mField) {
     case STROKE_WIDTH:
         mProperty->value.setStrokeWidth(value);
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 52a1807..fe88cbf 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -33,16 +33,14 @@
 
 class AnimationListener : public VirtualLightRefBase {
 public:
-    ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
+    ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
 protected:
     ANDROID_API virtual ~AnimationListener() {}
 };
 
-// Helper class to contain generic animator helpers
-class BaseAnimator : public VirtualLightRefBase {
-    PREVENT_COPY_AND_ASSIGN(BaseAnimator);
+class BaseRenderNodeAnimator : public VirtualLightRefBase {
+    PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
 public:
-
     ANDROID_API void setInterpolator(Interpolator* interpolator);
     ANDROID_API void setDuration(nsecs_t durationInMs);
     ANDROID_API nsecs_t duration() { return mDuration; }
@@ -50,31 +48,38 @@
         mListener = listener;
     }
 
+    ANDROID_API virtual void onAttached(RenderNode* target) {}
+
+    // Guaranteed to happen before the staging push
+    void setupStartValueIfNecessary(RenderNode* target, TreeInfo& info);
+
+    bool animate(RenderNode* target, TreeInfo& info);
+
     bool isFinished() { return mPlayState == FINISHED; }
+    float finalValue() { return mFinalValue; }
 
 protected:
-    BaseAnimator();
-    virtual ~BaseAnimator();
+    BaseRenderNodeAnimator(float finalValue);
+    virtual ~BaseRenderNodeAnimator();
 
-    // This is the main animation entrypoint that subclasses should call
-    // to generate the onAnimation* lifecycle events
-    // Returns true if the animation has finished, false otherwise
-    bool animateFrame(TreeInfo& info);
-
-    // Called when PlayState switches from PENDING to RUNNING
-    virtual void onAnimationStarted() {}
-    virtual void onAnimationUpdated(float fraction) = 0;
-    virtual void onAnimationFinished() {}
+    void setStartValue(float value);
+    virtual float getValue(RenderNode* target) const = 0;
+    virtual void setValue(RenderNode* target, float value) = 0;
 
 private:
     void callOnFinishedListener(TreeInfo& info);
 
     enum PlayState {
+        NEEDS_START,
         PENDING,
         RUNNING,
         FINISHED,
     };
 
+    float mFinalValue;
+    float mDeltaValue;
+    float mFromValue;
+
     Interpolator* mInterpolator;
     PlayState mPlayState;
     long mStartTime;
@@ -83,42 +88,6 @@
    sp<AnimationListener> mListener;
 };
 
-class BaseRenderNodeAnimator : public BaseAnimator {
-public:
-    // Since the UI thread doesn't necessarily know what the current values
-    // actually are and thus can't do the calculations, this is used to inform
-    // the animator how to lazy-resolve the input value
-    enum DeltaValueType {
-        // The delta value represents an absolute value endpoint
-        // mDeltaValue needs to be recalculated to be mDelta = (mDelta - fromValue)
-        // in onAnimationStarted()
-        ABSOLUTE = 0,
-        // The final value represents an offset from the current value
-        // No recalculation is needed
-        DELTA,
-    };
-
-    bool animate(RenderNode* target, TreeInfo& info);
-
-protected:
-    BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue);
-
-    RenderNode* target() const { return mTarget; }
-    virtual float getValue() const = 0;
-    virtual void setValue(float value) = 0;
-
-private:
-    virtual void onAnimationStarted();
-    virtual void onAnimationUpdated(float fraction);
-
-    // mTarget is only valid inside animate()
-    RenderNode* mTarget;
-
-    BaseRenderNodeAnimator::DeltaValueType mDeltaValueType;
-    float mDeltaValue;
-    float mFromValue;
-};
-
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
 public:
     enum RenderProperty {
@@ -136,23 +105,20 @@
         ALPHA,
     };
 
-    ANDROID_API RenderPropertyAnimator(RenderProperty property,
-                DeltaValueType deltaType, float deltaValue);
+    ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
+
+    ANDROID_API virtual void onAttached(RenderNode* target);
 
 protected:
-    ANDROID_API virtual float getValue() const;
-    ANDROID_API virtual void setValue(float value);
+    virtual float getValue(RenderNode* target) const;
+    virtual void setValue(RenderNode* target, float value);
 
 private:
     typedef void (RenderProperties::*SetFloatProperty)(float value);
     typedef float (RenderProperties::*GetFloatProperty)() const;
 
-    struct PropertyAccessors {
-        GetFloatProperty getter;
-        SetFloatProperty setter;
-    };
-
-    PropertyAccessors mPropertyAccess;
+    struct PropertyAccessors;
+    const PropertyAccessors* mPropertyAccess;
 
     static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
 };
@@ -160,10 +126,10 @@
 class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
 public:
     ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
-            DeltaValueType deltaType, float deltaValue);
+            float finalValue);
 protected:
-    ANDROID_API virtual float getValue() const;
-    ANDROID_API virtual void setValue(float value);
+    virtual float getValue(RenderNode* target) const;
+    virtual void setValue(RenderNode* target, float value);
 private:
     sp<CanvasPropertyPrimitive> mProperty;
 };
@@ -176,10 +142,10 @@
     };
 
     ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
-            PaintField field, DeltaValueType deltaType, float deltaValue);
+            PaintField field, float finalValue);
 protected:
-    ANDROID_API virtual float getValue() const;
-    ANDROID_API virtual void setValue(float value);
+    virtual float getValue(RenderNode* target) const;
+    virtual void setValue(RenderNode* target, float value);
 private:
     sp<CanvasPropertyPaint> mProperty;
     PaintField mField;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index fba482d..d4ff4a3 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -53,7 +53,7 @@
 }
 
 RenderNode::RenderNode()
-        : mNeedsPropertiesSync(false)
+        : mDirtyPropertyFields(0)
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0)
@@ -109,23 +109,37 @@
     prepareSubTree(info, mDisplayListData);
 }
 
-static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
-    return animator->isFinished();
-}
+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::pushStagingChanges(TreeInfo& info) {
-    if (mNeedsPropertiesSync) {
-        mNeedsPropertiesSync = false;
-        mProperties = mStagingProperties;
-    }
+    // 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(), is_finished);
+                mAnimators.begin(), functor);
         mAnimators.resize(std::distance(mAnimators.begin(), it));
     }
+    if (mDirtyPropertyFields) {
+        mDirtyPropertyFields = 0;
+        mProperties = mStagingProperties;
+    }
     if (mNeedsDisplayListDataSync) {
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
@@ -144,7 +158,7 @@
     AnimateFunctor(RenderNode* target, TreeInfo& info)
             : mTarget(target), mInfo(info) {}
 
-    bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
         return animator->animate(mTarget, mInfo);
     }
 private:
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index bc62ee1..1811a7b 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -82,6 +82,22 @@
  */
 class RenderNode : public VirtualLightRefBase {
 public:
+    enum DirtyPropertyMask {
+        GENERIC         = 1 << 1,
+        TRANSLATION_X   = 1 << 2,
+        TRANSLATION_Y   = 1 << 3,
+        TRANSLATION_Z   = 1 << 4,
+        SCALE_X         = 1 << 5,
+        SCALE_Y         = 1 << 6,
+        ROTATION        = 1 << 7,
+        ROTATION_X      = 1 << 8,
+        ROTATION_Y      = 1 << 9,
+        X               = 1 << 10,
+        Y               = 1 << 11,
+        Z               = 1 << 12,
+        ALPHA           = 1 << 13,
+    };
+
     ANDROID_API RenderNode();
     ANDROID_API virtual ~RenderNode();
 
@@ -123,6 +139,14 @@
         }
     }
 
+    bool isPropertyFieldDirty(DirtyPropertyMask field) const {
+        return mDirtyPropertyFields & field;
+    }
+
+    void setPropertyFieldsDirty(uint32_t fields) {
+        mDirtyPropertyFields |= fields;
+    }
+
     const RenderProperties& properties() {
         return mProperties;
     }
@@ -136,7 +160,6 @@
     }
 
     RenderProperties& mutateStagingProperties() {
-        mNeedsPropertiesSync = true;
         return mStagingProperties;
     }
 
@@ -152,6 +175,7 @@
 
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+        animator->onAttached(this);
         mStagingAnimators.insert(animator);
         mNeedsAnimatorsSync = true;
     }
@@ -227,7 +251,7 @@
 
     String8 mName;
 
-    bool mNeedsPropertiesSync;
+    uint32_t mDirtyPropertyFields;
     RenderProperties mProperties;
     RenderProperties mStagingProperties;
 
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index fc5994c..d4a23b8 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -21,12 +21,12 @@
 namespace android {
 namespace uirenderer {
 
-class BaseAnimator;
+class BaseRenderNodeAnimator;
 class AnimationListener;
 
 class AnimationHook {
 public:
-    virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
+    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) = 0;
 protected:
     ~AnimationHook() {}
 };