diff options
author | 2016-06-02 16:20:18 -0700 | |
---|---|---|
committer | 2016-06-08 15:21:15 -0700 | |
commit | a6b967cfc54408f6ee78ae0e4695eca6efd62e89 (patch) | |
tree | 3d0925d10d43e0e24813aded642533ccabc644ef | |
parent | 186a7a492d8ca9150141dd643cc68a7b6d080c72 (diff) |
Support Keyframe definition for AVD on RT
BUG: 27441613
Change-Id: Iece386f65f3704d1b7caa2b3690a8d3048ccf6e2
6 files changed, 218 insertions, 110 deletions
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index 3e7cbbdd5533..ba16e673ea69 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -1095,8 +1095,12 @@ public class PropertyValuesHolder implements Cloneable { } // TODO: We need a better way to get data out of keyframes. if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase - || mKeyframes instanceof PathKeyframes.IntKeyframesBase) { - // property values will animate based on external data source (e.g. Path) + || mKeyframes instanceof PathKeyframes.IntKeyframesBase + || (mKeyframes.getKeyframes() != null && mKeyframes.getKeyframes().size() > 2)) { + // When a pvh has more than 2 keyframes, that means there are intermediate values in + // addition to start/end values defined for animators. Another case where such + // intermediate values are defined is when animator has a path to animate along. In + // these cases, a data source is needed to capture these intermediate values. values.dataSource = new PropertyValues.DataSource() { @Override public Object getValueAtFraction(float fraction) { diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java index 9e2cbdba44d4..d28ab078d74a 100644 --- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java @@ -30,6 +30,8 @@ import android.view.Choreographer; @HasNativeInterpolator public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator { + // If the duration of an animation is more than 300 frames, we cap the sample size to 300. + private static final int MAX_SAMPLE_POINTS = 300; private TimeInterpolator mSourceInterpolator; private final float mLut[]; @@ -47,6 +49,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS); // We need 2 frame values as the minimal. int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs)); + numAnimFrames = Math.min(numAnimFrames, MAX_SAMPLE_POINTS); float values[] = new float[numAnimFrames]; float lastFrame = numAnimFrames - 1; for (int i = 0; i < numAnimFrames; i++) { diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp index 0ba88e6b066b..47252ad54468 100644 --- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp @@ -142,14 +142,24 @@ static jlong createRootAlphaPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jf startValue, endValue); return reinterpret_cast<jlong>(newHolder); } -static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr, +static void setFloatPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr, jfloatArray srcData, jint length) { - jfloat* propertyData = env->GetFloatArrayElements(srcData, nullptr); - PropertyValuesHolder* holder = reinterpret_cast<PropertyValuesHolder*>(propertyHolderPtr); + PropertyValuesHolderImpl<float>* holder = + reinterpret_cast<PropertyValuesHolderImpl<float>*>(propertyHolderPtr); holder->setPropertyDataSource(propertyData, length); env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT); } + +static void setIntPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr, + jintArray srcData, jint length) { + jint* propertyData = env->GetIntArrayElements(srcData, nullptr); + PropertyValuesHolderImpl<int>* holder = + reinterpret_cast<PropertyValuesHolderImpl<int>*>(propertyHolderPtr); + holder->setPropertyDataSource(propertyData, length); + env->ReleaseIntArrayElements(srcData, propertyData, JNI_ABORT); +} + static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) { PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr); AnimationListener* listener = createAnimationListener(env, finishListener, id); @@ -181,7 +191,8 @@ static const JNINativeMethod gMethods[] = { {"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder}, {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder}, {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder}, - {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData}, + {"nSetPropertyHolderData", "(J[FI)V", (void*)setFloatPropertyHolderData}, + {"nSetPropertyHolderData", "(J[II)V", (void*)setIntPropertyHolderData}, {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start}, {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse}, {"nEnd", "!(J)V", (void*)end}, diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 3eace301777b..6bb93aec49b9 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -1041,6 +1041,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static final int REVERSE_ANIMATION = 2; private static final int RESET_ANIMATION = 3; private static final int END_ANIMATION = 4; + + // If the duration of an animation is more than 300 frames, we cap the sample size to 300. + private static final int MAX_SAMPLE_POINTS = 300; private AnimatorListener mListener = null; private final LongArray mStartDelays = new LongArray(); private PropertyValuesHolder.PropertyValues mTmpValues = @@ -1180,8 +1183,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { long propertyPtr = nCreateGroupPropertyHolder(nativePtr, propertyId, (Float) mTmpValues.startValue, (Float) mTmpValues.endValue); if (mTmpValues.dataSource != null) { - float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator - .getDuration()); + float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource, + animator.getDuration()); nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); } createNativeChildAnimator(propertyPtr, startTime, animator); @@ -1217,10 +1220,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } propertyPtr = nCreatePathPropertyHolder(nativePtr, propertyId, (Float) mTmpValues.startValue, (Float) mTmpValues.endValue); + if (mTmpValues.dataSource != null) { + // Pass keyframe data to native, if any. + float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource, + animator.getDuration()); + nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); + } } else if (mTmpValues.type == Integer.class || mTmpValues.type == int.class) { propertyPtr = nCreatePathColorPropertyHolder(nativePtr, propertyId, (Integer) mTmpValues.startValue, (Integer) mTmpValues.endValue); + if (mTmpValues.dataSource != null) { + // Pass keyframe data to native, if any. + int[] dataPoints = createIntDataPoints(mTmpValues.dataSource, + animator.getDuration()); + nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); + } } else { if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) { return; @@ -1230,45 +1245,63 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { "supported for Paths."); } } - if (mTmpValues.dataSource != null) { - float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator - .getDuration()); - nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); - } createNativeChildAnimator(propertyPtr, startTime, animator); } private void createRTAnimatorForRootGroup(PropertyValuesHolder[] values, ObjectAnimator animator, VectorDrawable.VectorDrawableState target, long startTime) { - long nativePtr = target.getNativeRenderer(); - if (!animator.getPropertyName().equals("alpha")) { - if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) { - return; - } else { - throw new UnsupportedOperationException("Only alpha is supported for root " - + "group"); - } + long nativePtr = target.getNativeRenderer(); + if (!animator.getPropertyName().equals("alpha")) { + if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) { + return; + } else { + throw new UnsupportedOperationException("Only alpha is supported for root " + + "group"); } - Float startValue = null; - Float endValue = null; - for (int i = 0; i < values.length; i++) { - values[i].getPropertyValues(mTmpValues); - if (mTmpValues.propertyName.equals("alpha")) { - startValue = (Float) mTmpValues.startValue; - endValue = (Float) mTmpValues.endValue; - break; - } + } + Float startValue = null; + Float endValue = null; + for (int i = 0; i < values.length; i++) { + values[i].getPropertyValues(mTmpValues); + if (mTmpValues.propertyName.equals("alpha")) { + startValue = (Float) mTmpValues.startValue; + endValue = (Float) mTmpValues.endValue; + break; } - if (startValue == null && endValue == null) { - if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) { - return; - } else { - throw new UnsupportedOperationException("No alpha values are specified"); - } + } + if (startValue == null && endValue == null) { + if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) { + return; + } else { + throw new UnsupportedOperationException("No alpha values are specified"); } - long propertyPtr = nCreateRootAlphaPropertyHolder(nativePtr, startValue, endValue); - createNativeChildAnimator(propertyPtr, startTime, animator); + } + long propertyPtr = nCreateRootAlphaPropertyHolder(nativePtr, startValue, endValue); + if (mTmpValues.dataSource != null) { + // Pass keyframe data to native, if any. + float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource, + animator.getDuration()); + nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length); + } + createNativeChildAnimator(propertyPtr, startTime, animator); + } + + /** + * Calculate the amount of frames an animation will run based on duration. + */ + private static int getFrameCount(long duration) { + long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos(); + int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS); + int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs); + // We need 2 frames of data minimum. + numAnimFrames = Math.max(2, numAnimFrames); + if (numAnimFrames > MAX_SAMPLE_POINTS) { + Log.w("AnimatedVectorDrawable", "Duration for the animation is too long :" + + duration + ", the animation will subsample the keyframe or path data."); + numAnimFrames = MAX_SAMPLE_POINTS; + } + return numAnimFrames; } // These are the data points that define the value of the animating properties. @@ -1276,11 +1309,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { // a point on the path corresponds to the values of translateX and translateY. // TODO: (Optimization) We should pass the path down in native and chop it into segments // in native. - private static float[] createDataPoints( + private static float[] createFloatDataPoints( PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) { - long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos(); - int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS); - int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs); + int numAnimFrames = getFrameCount(duration); float values[] = new float[numAnimFrames]; float lastFrame = numAnimFrames - 1; for (int i = 0; i < numAnimFrames; i++) { @@ -1290,6 +1321,18 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return values; } + private static int[] createIntDataPoints( + PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) { + int numAnimFrames = getFrameCount(duration); + int values[] = new int[numAnimFrames]; + float lastFrame = numAnimFrames - 1; + for (int i = 0; i < numAnimFrames; i++) { + float fraction = i / lastFrame; + values[i] = (Integer) dataSource.getValueAtFraction(fraction); + } + return values; + } + private void createNativeChildAnimator(long propertyPtr, long extraDelay, ObjectAnimator animator) { long duration = animator.getDuration(); @@ -1566,6 +1609,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue, float endValue); private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length); + private static native void nSetPropertyHolderData(long nativePtr, int[] data, int length); private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id); private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id); private static native void nEnd(long animatorSetPtr); diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp index 0932d653fd5e..6ba0ab59a88c 100644 --- a/libs/hwui/PropertyValuesHolder.cpp +++ b/libs/hwui/PropertyValuesHolder.cpp @@ -25,7 +25,27 @@ namespace uirenderer { using namespace VectorDrawable; -float PropertyValuesHolder::getValueFromData(float fraction) { +inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) { + return (U8CPU) (fromValue * (1 - fraction) + toValue * fraction); +} + +// TODO: Add a test for this +void ColorEvaluator::evaluate(SkColor* outColor, + const SkColor& fromColor, const SkColor& toColor, float fraction) const { + U8CPU alpha = lerp(SkColorGetA(fromColor), SkColorGetA(toColor), fraction); + U8CPU red = lerp(SkColorGetR(fromColor), SkColorGetR(toColor), fraction); + U8CPU green = lerp(SkColorGetG(fromColor), SkColorGetG(toColor), fraction); + U8CPU blue = lerp(SkColorGetB(fromColor), SkColorGetB(toColor), fraction); + *outColor = SkColorSetARGB(alpha, red, green, blue); +} + +void PathEvaluator::evaluate(PathData* out, + const PathData& from, const PathData& to, float fraction) const { + VectorDrawableUtils::interpolatePaths(out, from, to, fraction); +} + +template<typename T> +const T PropertyValuesHolderImpl<T>::getValueFromData(float fraction) const { if (mDataSource.size() == 0) { LOG_ALWAYS_FATAL("No data source is defined"); return 0; @@ -41,57 +61,44 @@ float PropertyValuesHolder::getValueFromData(float fraction) { int lowIndex = floor(fraction); fraction -= lowIndex; - float value = mDataSource[lowIndex] * (1.0f - fraction) - + mDataSource[lowIndex + 1] * fraction; + T value; + mEvaluator->evaluate(&value, mDataSource[lowIndex], mDataSource[lowIndex + 1], fraction); return value; } -void GroupPropertyValuesHolder::setFraction(float fraction) { - float animatedValue; +template<typename T> +const T PropertyValuesHolderImpl<T>::calculateAnimatedValue(float fraction) const { if (mDataSource.size() > 0) { - animatedValue = getValueFromData(fraction); + return getValueFromData(fraction); } else { - animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction; + T value; + mEvaluator->evaluate(&value, mStartValue, mEndValue, fraction); + return value; } - mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue); } -inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) { - return (U8CPU) (fromValue * (1 - fraction) + toValue * fraction); -} - -// TODO: Add a test for this -SkColor FullPathColorPropertyValuesHolder::interpolateColors(SkColor fromColor, SkColor toColor, - float fraction) { - U8CPU alpha = lerp(SkColorGetA(fromColor), SkColorGetA(toColor), fraction); - U8CPU red = lerp(SkColorGetR(fromColor), SkColorGetR(toColor), fraction); - U8CPU green = lerp(SkColorGetG(fromColor), SkColorGetG(toColor), fraction); - U8CPU blue = lerp(SkColorGetB(fromColor), SkColorGetB(toColor), fraction); - return SkColorSetARGB(alpha, red, green, blue); +void GroupPropertyValuesHolder::setFraction(float fraction) { + float animatedValue = calculateAnimatedValue(fraction); + mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue); } void FullPathColorPropertyValuesHolder::setFraction(float fraction) { - SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction); + SkColor animatedValue = calculateAnimatedValue(fraction); mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue); } void FullPathPropertyValuesHolder::setFraction(float fraction) { - float animatedValue; - if (mDataSource.size() > 0) { - animatedValue = getValueFromData(fraction); - } else { - animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction; - } + float animatedValue = calculateAnimatedValue(fraction); mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue); } void PathDataPropertyValuesHolder::setFraction(float fraction) { - VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction); + mEvaluator->evaluate(&mPathData, mStartValue, mEndValue, fraction); mPath->mutateProperties()->setData(mPathData); } void RootAlphaPropertyValuesHolder::setFraction(float fraction) { - float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction; + float animatedValue = calculateAnimatedValue(fraction); mTree->mutateProperties()->setRootAlpha(animatedValue); } diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h index b905faef104c..432f8ba82afb 100644 --- a/libs/hwui/PropertyValuesHolder.h +++ b/libs/hwui/PropertyValuesHolder.h @@ -31,91 +31,130 @@ namespace uirenderer { class ANDROID_API PropertyValuesHolder { public: virtual void setFraction(float fraction) = 0; - void setPropertyDataSource(float* dataSource, int length) { + virtual ~PropertyValuesHolder() {} +}; + +template <typename T> +class Evaluator { +public: + virtual void evaluate(T* out, const T& from, const T& to, float fraction) const {}; + virtual ~Evaluator() {} +}; + +class FloatEvaluator : public Evaluator<float> { +public: + virtual void evaluate(float* out, const float& from, const float& to, float fraction) + const override { + *out = from * (1 - fraction) + to * fraction; + } +}; + +class ANDROID_API ColorEvaluator : public Evaluator<SkColor> { +public: + virtual void evaluate(SkColor* outColor, const SkColor& from, const SkColor& to, + float fraction) const override; +}; + +class ANDROID_API PathEvaluator : public Evaluator<PathData> { + virtual void evaluate(PathData* out, const PathData& from, const PathData& to, float fraction) + const override; +}; + +template <typename T> +class ANDROID_API PropertyValuesHolderImpl : public PropertyValuesHolder { +public: + PropertyValuesHolderImpl(const T& startValue, const T& endValue) + : mStartValue(startValue) + , mEndValue(endValue) {} + void setPropertyDataSource(T* dataSource, int length) { mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length); } - float getValueFromData(float fraction); - virtual ~PropertyValuesHolder() {} + // Calculate the animated value from the data source. + const T getValueFromData(float fraction) const; + // Convenient method to favor getting animated value from data source. If no data source is set + // fall back to linear interpolation. + const T calculateAnimatedValue(float fraction) const; protected: - std::vector<float> mDataSource; + std::unique_ptr<Evaluator<T>> mEvaluator = nullptr; + // This contains uniformly sampled data throughout the animation duration. The first element + // should be the start value and the last should be the end value of the animation. When the + // data source is set, we'll favor data source over the linear interpolation of start/end value + // for calculation of animated value. + std::vector<T> mDataSource; + T mStartValue; + T mEndValue; }; -class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolder { +class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> { public: GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue, float endValue) - : mGroup(ptr) - , mPropertyId(propertyId) - , mStartValue(startValue) - , mEndValue(endValue){ + : PropertyValuesHolderImpl(startValue, endValue) + , mGroup(ptr) + , mPropertyId(propertyId) { + mEvaluator.reset(new FloatEvaluator()); } void setFraction(float fraction) override; private: VectorDrawable::Group* mGroup; int mPropertyId; - float mStartValue; - float mEndValue; }; -class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolder { +class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> { public: - FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, int32_t startValue, - int32_t endValue) - : mFullPath(ptr) - , mPropertyId(propertyId) - , mStartValue(startValue) - , mEndValue(endValue) {}; + FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, + SkColor startValue, SkColor endValue) + : PropertyValuesHolderImpl(startValue, endValue) + , mFullPath(ptr) + , mPropertyId(propertyId) { + mEvaluator.reset(new ColorEvaluator()); + } void setFraction(float fraction) override; static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction); private: VectorDrawable::FullPath* mFullPath; int mPropertyId; - int32_t mStartValue; - int32_t mEndValue; }; -class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolder { +class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> { public: FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue, float endValue) - : mFullPath(ptr) - , mPropertyId(propertyId) - , mStartValue(startValue) - , mEndValue(endValue) {}; + : PropertyValuesHolderImpl(startValue, endValue) + , mFullPath(ptr) + , mPropertyId(propertyId) { + mEvaluator.reset(new FloatEvaluator()); + }; void setFraction(float fraction) override; private: VectorDrawable::FullPath* mFullPath; int mPropertyId; - float mStartValue; - float mEndValue; }; -class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolder { +class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> { public: PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue, PathData* endValue) - : mPath(ptr) - , mStartValue(*startValue) - , mEndValue(*endValue) {}; + : PropertyValuesHolderImpl(*startValue, *endValue) + , mPath(ptr) { + mEvaluator.reset(new PathEvaluator()); + }; void setFraction(float fraction) override; private: VectorDrawable::Path* mPath; PathData mPathData; - PathData mStartValue; - PathData mEndValue; }; -class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolder { +class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> { public: RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue) - : mTree(tree) - , mStartValue(startValue) - , mEndValue(endValue) {} + : PropertyValuesHolderImpl(startValue, endValue) + , mTree(tree) { + mEvaluator.reset(new FloatEvaluator()); + } void setFraction(float fraction) override; private: VectorDrawable::Tree* mTree; - float mStartValue; - float mEndValue; }; } } |