Loading core/java/android/animation/PropertyValuesHolder.java +6 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +3 −0 Original line number Diff line number Diff line Loading @@ -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[]; Loading @@ -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++) { Loading core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +15 −4 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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}, Loading graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +80 −36 Original line number Diff line number Diff line Loading @@ -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 = Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -1230,11 +1245,6 @@ 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); } Loading Loading @@ -1268,19 +1278,40 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } 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. // e.g. translateX and translateY can animate along a Path, at any fraction in [0, 1] // 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++) { Loading @@ -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(); Loading Loading @@ -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); Loading libs/hwui/PropertyValuesHolder.cpp +36 −29 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue); T value; mEvaluator->evaluate(&value, mStartValue, mEndValue, fraction); return value; } 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); } Loading Loading
core/java/android/animation/PropertyValuesHolder.java +6 −2 Original line number Diff line number Diff line Loading @@ -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) { Loading
core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +3 −0 Original line number Diff line number Diff line Loading @@ -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[]; Loading @@ -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++) { Loading
core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +15 −4 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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}, Loading
graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +80 −36 Original line number Diff line number Diff line Loading @@ -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 = Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -1230,11 +1245,6 @@ 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); } Loading Loading @@ -1268,19 +1278,40 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } 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. // e.g. translateX and translateY can animate along a Path, at any fraction in [0, 1] // 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++) { Loading @@ -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(); Loading Loading @@ -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); Loading
libs/hwui/PropertyValuesHolder.cpp +36 −29 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue); T value; mEvaluator->evaluate(&value, mStartValue, mEndValue, fraction); return value; } 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); } Loading