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

Commit a6b967cf authored by Doris Liu's avatar Doris Liu
Browse files

Support Keyframe definition for AVD on RT

BUG: 27441613
Change-Id: Iece386f65f3704d1b7caa2b3690a8d3048ccf6e2
parent 186a7a49
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