Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e1d4932 authored by Doris Liu's avatar Doris Liu Committed by Android (Google) Code Review
Browse files

Merge "Support Keyframe definition for AVD on RT"

parents 7fbaf2a6 a6b967cf
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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) {
+3 −0
Original line number Diff line number Diff line
@@ -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++) {
+15 −4
Original line number Diff line number Diff line
@@ -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},
+80 −36
Original line number Diff line number Diff line
@@ -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,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);
        }

@@ -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++) {
@@ -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);
+36 −29
Original line number Diff line number Diff line
@@ -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;
    }
    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