Merge changes from topic 'VectorDrawable polishing cherrypicks from master' into nyc-mr1-dev
* changes: Support Keyframe definition for AVD on RT Throw Exception for wrong valueType with API guard
This commit is contained in:
@@ -1095,8 +1095,12 @@ public class PropertyValuesHolder implements Cloneable {
|
|||||||
}
|
}
|
||||||
// TODO: We need a better way to get data out of keyframes.
|
// TODO: We need a better way to get data out of keyframes.
|
||||||
if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase
|
if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase
|
||||||
|| mKeyframes instanceof PathKeyframes.IntKeyframesBase) {
|
|| mKeyframes instanceof PathKeyframes.IntKeyframesBase
|
||||||
// property values will animate based on external data source (e.g. Path)
|
|| (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() {
|
values.dataSource = new PropertyValues.DataSource() {
|
||||||
@Override
|
@Override
|
||||||
public Object getValueAtFraction(float fraction) {
|
public Object getValueAtFraction(float fraction) {
|
||||||
@@ -1108,6 +1112,13 @@ public class PropertyValuesHolder implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public Class getValueType() {
|
||||||
|
return mValueType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return mPropertyName + ": " + mKeyframes.toString();
|
return mPropertyName + ": " + mKeyframes.toString();
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import android.view.Choreographer;
|
|||||||
@HasNativeInterpolator
|
@HasNativeInterpolator
|
||||||
public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator {
|
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 TimeInterpolator mSourceInterpolator;
|
||||||
private final float mLut[];
|
private final float mLut[];
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI
|
|||||||
int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
|
int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
|
||||||
// We need 2 frame values as the minimal.
|
// We need 2 frame values as the minimal.
|
||||||
int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
|
int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
|
||||||
|
numAnimFrames = Math.min(numAnimFrames, MAX_SAMPLE_POINTS);
|
||||||
float values[] = new float[numAnimFrames];
|
float values[] = new float[numAnimFrames];
|
||||||
float lastFrame = numAnimFrames - 1;
|
float lastFrame = numAnimFrames - 1;
|
||||||
for (int i = 0; i < numAnimFrames; i++) {
|
for (int i = 0; i < numAnimFrames; i++) {
|
||||||
|
|||||||
@@ -142,14 +142,24 @@ static jlong createRootAlphaPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jf
|
|||||||
startValue, endValue);
|
startValue, endValue);
|
||||||
return reinterpret_cast<jlong>(newHolder);
|
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) {
|
jfloatArray srcData, jint length) {
|
||||||
|
|
||||||
jfloat* propertyData = env->GetFloatArrayElements(srcData, nullptr);
|
jfloat* propertyData = env->GetFloatArrayElements(srcData, nullptr);
|
||||||
PropertyValuesHolder* holder = reinterpret_cast<PropertyValuesHolder*>(propertyHolderPtr);
|
PropertyValuesHolderImpl<float>* holder =
|
||||||
|
reinterpret_cast<PropertyValuesHolderImpl<float>*>(propertyHolderPtr);
|
||||||
holder->setPropertyDataSource(propertyData, length);
|
holder->setPropertyDataSource(propertyData, length);
|
||||||
env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
|
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) {
|
static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
|
||||||
PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
|
PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
|
||||||
AnimationListener* listener = createAnimationListener(env, finishListener, id);
|
AnimationListener* listener = createAnimationListener(env, finishListener, id);
|
||||||
@@ -181,7 +191,8 @@ static const JNINativeMethod gMethods[] = {
|
|||||||
{"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder},
|
{"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder},
|
||||||
{"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
|
{"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
|
||||||
{"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
|
{"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},
|
{"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
|
||||||
{"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
|
{"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
|
||||||
{"nEnd", "!(J)V", (void*)end},
|
{"nEnd", "!(J)V", (void*)end},
|
||||||
|
|||||||
@@ -395,7 +395,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
// The animator here could be ObjectAnimator or AnimatorSet.
|
// The animator here could be ObjectAnimator or AnimatorSet.
|
||||||
final Animator animator = AnimatorInflater.loadAnimator(
|
final Animator animator = AnimatorInflater.loadAnimator(
|
||||||
res, theme, animResId, pathErrorScale);
|
res, theme, animResId, pathErrorScale);
|
||||||
updateAnimatorProperty(animator, target, state.mVectorDrawable);
|
updateAnimatorProperty(animator, target, state.mVectorDrawable,
|
||||||
|
state.mShouldIgnoreInvalidAnim);
|
||||||
state.addTargetAnimator(target, animator);
|
state.addTargetAnimator(target, animator);
|
||||||
} else {
|
} else {
|
||||||
// The animation may be theme-dependent. As a
|
// The animation may be theme-dependent. As a
|
||||||
@@ -419,7 +420,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void updateAnimatorProperty(Animator animator, String targetName,
|
private static void updateAnimatorProperty(Animator animator, String targetName,
|
||||||
VectorDrawable vectorDrawable) {
|
VectorDrawable vectorDrawable, boolean ignoreInvalidAnim) {
|
||||||
if (animator instanceof ObjectAnimator) {
|
if (animator instanceof ObjectAnimator) {
|
||||||
// Change the property of the Animator from using reflection based on the property
|
// Change the property of the Animator from using reflection based on the property
|
||||||
// name to a Property object that wraps the setter and getter for modifying that
|
// name to a Property object that wraps the setter and getter for modifying that
|
||||||
@@ -438,16 +439,35 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
.getProperty(propertyName);
|
.getProperty(propertyName);
|
||||||
}
|
}
|
||||||
if (property != null) {
|
if (property != null) {
|
||||||
pvh.setProperty(property);
|
if (containsSameValueType(pvh, property)) {
|
||||||
|
pvh.setProperty(property);
|
||||||
|
} else if (!ignoreInvalidAnim) {
|
||||||
|
throw new RuntimeException("Wrong valueType for Property: " + propertyName
|
||||||
|
+ ". Expected type: " + property.getType().toString() + ". Actual "
|
||||||
|
+ "type defined in resources: " + pvh.getValueType().toString());
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (animator instanceof AnimatorSet) {
|
} else if (animator instanceof AnimatorSet) {
|
||||||
for (Animator anim : ((AnimatorSet) animator).getChildAnimations()) {
|
for (Animator anim : ((AnimatorSet) animator).getChildAnimations()) {
|
||||||
updateAnimatorProperty(anim, targetName, vectorDrawable);
|
updateAnimatorProperty(anim, targetName, vectorDrawable, ignoreInvalidAnim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean containsSameValueType(PropertyValuesHolder holder, Property property) {
|
||||||
|
Class type1 = holder.getValueType();
|
||||||
|
Class type2 = property.getType();
|
||||||
|
if (type1 == float.class || type1 == Float.class) {
|
||||||
|
return type2 == float.class || type2 == Float.class;
|
||||||
|
} else if (type1 == int.class || type1 == Integer.class) {
|
||||||
|
return type2 == int.class || type2 == Integer.class;
|
||||||
|
} else {
|
||||||
|
return type1 == type2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Force to animate on UI thread.
|
* Force to animate on UI thread.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -496,6 +516,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
@Config int mChangingConfigurations;
|
@Config int mChangingConfigurations;
|
||||||
VectorDrawable mVectorDrawable;
|
VectorDrawable mVectorDrawable;
|
||||||
|
|
||||||
|
private final boolean mShouldIgnoreInvalidAnim;
|
||||||
|
|
||||||
/** Animators that require a theme before inflation. */
|
/** Animators that require a theme before inflation. */
|
||||||
ArrayList<PendingAnimator> mPendingAnims;
|
ArrayList<PendingAnimator> mPendingAnims;
|
||||||
|
|
||||||
@@ -507,6 +529,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
|
|
||||||
public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
|
public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
|
||||||
Callback owner, Resources res) {
|
Callback owner, Resources res) {
|
||||||
|
mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
|
||||||
if (copy != null) {
|
if (copy != null) {
|
||||||
mChangingConfigurations = copy.mChangingConfigurations;
|
mChangingConfigurations = copy.mChangingConfigurations;
|
||||||
|
|
||||||
@@ -651,7 +674,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
for (int i = 0, count = pendingAnims.size(); i < count; i++) {
|
for (int i = 0, count = pendingAnims.size(); i < count; i++) {
|
||||||
final PendingAnimator pendingAnimator = pendingAnims.get(i);
|
final PendingAnimator pendingAnimator = pendingAnims.get(i);
|
||||||
final Animator animator = pendingAnimator.newInstance(res, t);
|
final Animator animator = pendingAnimator.newInstance(res, t);
|
||||||
updateAnimatorProperty(animator, pendingAnimator.target, mVectorDrawable);
|
updateAnimatorProperty(animator, pendingAnimator.target, mVectorDrawable,
|
||||||
|
mShouldIgnoreInvalidAnim);
|
||||||
addTargetAnimator(pendingAnimator.target, animator);
|
addTargetAnimator(pendingAnimator.target, animator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1017,6 +1041,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
private static final int REVERSE_ANIMATION = 2;
|
private static final int REVERSE_ANIMATION = 2;
|
||||||
private static final int RESET_ANIMATION = 3;
|
private static final int RESET_ANIMATION = 3;
|
||||||
private static final int END_ANIMATION = 4;
|
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 AnimatorListener mListener = null;
|
||||||
private final LongArray mStartDelays = new LongArray();
|
private final LongArray mStartDelays = new LongArray();
|
||||||
private PropertyValuesHolder.PropertyValues mTmpValues =
|
private PropertyValuesHolder.PropertyValues mTmpValues =
|
||||||
@@ -1027,8 +1054,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
private boolean mInitialized = false;
|
private boolean mInitialized = false;
|
||||||
private boolean mIsReversible = false;
|
private boolean mIsReversible = false;
|
||||||
private boolean mIsInfinite = false;
|
private boolean mIsInfinite = false;
|
||||||
// This needs to be set before parsing starts.
|
|
||||||
private boolean mShouldIgnoreInvalidAnim;
|
|
||||||
// TODO: Consider using NativeAllocationRegistery to track native allocation
|
// TODO: Consider using NativeAllocationRegistery to track native allocation
|
||||||
private final VirtualRefBasePtr mSetRefBasePtr;
|
private final VirtualRefBasePtr mSetRefBasePtr;
|
||||||
private WeakReference<RenderNode> mLastSeenTarget = null;
|
private WeakReference<RenderNode> mLastSeenTarget = null;
|
||||||
@@ -1051,7 +1076,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
|
throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
|
||||||
"re-initialized");
|
"re-initialized");
|
||||||
}
|
}
|
||||||
mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
|
|
||||||
parseAnimatorSet(set, 0);
|
parseAnimatorSet(set, 0);
|
||||||
long vectorDrawableTreePtr = mDrawable.mAnimatedVectorState.mVectorDrawable
|
long vectorDrawableTreePtr = mDrawable.mAnimatedVectorState.mVectorDrawable
|
||||||
.getNativeTree();
|
.getNativeTree();
|
||||||
@@ -1115,7 +1139,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
} else if (target instanceof VectorDrawable.VFullPath) {
|
} else if (target instanceof VectorDrawable.VFullPath) {
|
||||||
createRTAnimatorForFullPath(animator, (VectorDrawable.VFullPath) target,
|
createRTAnimatorForFullPath(animator, (VectorDrawable.VFullPath) target,
|
||||||
startTime);
|
startTime);
|
||||||
} else if (!mShouldIgnoreInvalidAnim) {
|
} else if (!mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
|
||||||
throw new IllegalArgumentException("ClipPath only supports PathData " +
|
throw new IllegalArgumentException("ClipPath only supports PathData " +
|
||||||
"property");
|
"property");
|
||||||
}
|
}
|
||||||
@@ -1124,7 +1148,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
} else if (target instanceof VectorDrawable.VectorDrawableState) {
|
} else if (target instanceof VectorDrawable.VectorDrawableState) {
|
||||||
createRTAnimatorForRootGroup(values, animator,
|
createRTAnimatorForRootGroup(values, animator,
|
||||||
(VectorDrawable.VectorDrawableState) target, startTime);
|
(VectorDrawable.VectorDrawableState) target, startTime);
|
||||||
} else if (!mShouldIgnoreInvalidAnim) {
|
} else if (!mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
|
||||||
// Should never get here
|
// Should never get here
|
||||||
throw new UnsupportedOperationException("Target should be either VGroup, VPath, " +
|
throw new UnsupportedOperationException("Target should be either VGroup, VPath, " +
|
||||||
"or ConstantState, " + target == null ? "Null target" : target.getClass() +
|
"or ConstantState, " + target == null ? "Null target" : target.getClass() +
|
||||||
@@ -1159,8 +1183,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
long propertyPtr = nCreateGroupPropertyHolder(nativePtr, propertyId,
|
long propertyPtr = nCreateGroupPropertyHolder(nativePtr, propertyId,
|
||||||
(Float) mTmpValues.startValue, (Float) mTmpValues.endValue);
|
(Float) mTmpValues.startValue, (Float) mTmpValues.endValue);
|
||||||
if (mTmpValues.dataSource != null) {
|
if (mTmpValues.dataSource != null) {
|
||||||
float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator
|
float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource,
|
||||||
.getDuration());
|
animator.getDuration());
|
||||||
nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
|
nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
|
||||||
}
|
}
|
||||||
createNativeChildAnimator(propertyPtr, startTime, animator);
|
createNativeChildAnimator(propertyPtr, startTime, animator);
|
||||||
@@ -1187,7 +1211,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
long nativePtr = target.getNativePtr();
|
long nativePtr = target.getNativePtr();
|
||||||
if (mTmpValues.type == Float.class || mTmpValues.type == float.class) {
|
if (mTmpValues.type == Float.class || mTmpValues.type == float.class) {
|
||||||
if (propertyId < 0) {
|
if (propertyId < 0) {
|
||||||
if (mShouldIgnoreInvalidAnim) {
|
if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Property: " + mTmpValues.propertyName
|
throw new IllegalArgumentException("Property: " + mTmpValues.propertyName
|
||||||
@@ -1196,12 +1220,24 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
}
|
}
|
||||||
propertyPtr = nCreatePathPropertyHolder(nativePtr, propertyId,
|
propertyPtr = nCreatePathPropertyHolder(nativePtr, propertyId,
|
||||||
(Float) mTmpValues.startValue, (Float) mTmpValues.endValue);
|
(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) {
|
} else if (mTmpValues.type == Integer.class || mTmpValues.type == int.class) {
|
||||||
propertyPtr = nCreatePathColorPropertyHolder(nativePtr, propertyId,
|
propertyPtr = nCreatePathColorPropertyHolder(nativePtr, propertyId,
|
||||||
(Integer) mTmpValues.startValue, (Integer) mTmpValues.endValue);
|
(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 {
|
} else {
|
||||||
if (mShouldIgnoreInvalidAnim) {
|
if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("Unsupported type: " +
|
throw new UnsupportedOperationException("Unsupported type: " +
|
||||||
@@ -1209,45 +1245,63 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
"supported for Paths.");
|
"supported for Paths.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mTmpValues.dataSource != null) {
|
|
||||||
float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator
|
|
||||||
.getDuration());
|
|
||||||
nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
|
|
||||||
}
|
|
||||||
createNativeChildAnimator(propertyPtr, startTime, animator);
|
createNativeChildAnimator(propertyPtr, startTime, animator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createRTAnimatorForRootGroup(PropertyValuesHolder[] values,
|
private void createRTAnimatorForRootGroup(PropertyValuesHolder[] values,
|
||||||
ObjectAnimator animator, VectorDrawable.VectorDrawableState target,
|
ObjectAnimator animator, VectorDrawable.VectorDrawableState target,
|
||||||
long startTime) {
|
long startTime) {
|
||||||
long nativePtr = target.getNativeRenderer();
|
long nativePtr = target.getNativeRenderer();
|
||||||
if (!animator.getPropertyName().equals("alpha")) {
|
if (!animator.getPropertyName().equals("alpha")) {
|
||||||
if (mShouldIgnoreInvalidAnim) {
|
if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedOperationException("Only alpha is supported for root "
|
throw new UnsupportedOperationException("Only alpha is supported for root "
|
||||||
+ "group");
|
+ "group");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Float startValue = null;
|
}
|
||||||
Float endValue = null;
|
Float startValue = null;
|
||||||
for (int i = 0; i < values.length; i++) {
|
Float endValue = null;
|
||||||
values[i].getPropertyValues(mTmpValues);
|
for (int i = 0; i < values.length; i++) {
|
||||||
if (mTmpValues.propertyName.equals("alpha")) {
|
values[i].getPropertyValues(mTmpValues);
|
||||||
startValue = (Float) mTmpValues.startValue;
|
if (mTmpValues.propertyName.equals("alpha")) {
|
||||||
endValue = (Float) mTmpValues.endValue;
|
startValue = (Float) mTmpValues.startValue;
|
||||||
break;
|
endValue = (Float) mTmpValues.endValue;
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
if (startValue == null && endValue == null) {
|
}
|
||||||
if (mShouldIgnoreInvalidAnim) {
|
if (startValue == null && endValue == null) {
|
||||||
return;
|
if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
|
||||||
} else {
|
return;
|
||||||
throw new UnsupportedOperationException("No alpha values are specified");
|
} 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.
|
// These are the data points that define the value of the animating properties.
|
||||||
@@ -1255,11 +1309,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
// a point on the path corresponds to the values of translateX and translateY.
|
// 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
|
// TODO: (Optimization) We should pass the path down in native and chop it into segments
|
||||||
// in native.
|
// in native.
|
||||||
private static float[] createDataPoints(
|
private static float[] createFloatDataPoints(
|
||||||
PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) {
|
PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) {
|
||||||
long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
|
int numAnimFrames = getFrameCount(duration);
|
||||||
int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
|
|
||||||
int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs);
|
|
||||||
float values[] = new float[numAnimFrames];
|
float values[] = new float[numAnimFrames];
|
||||||
float lastFrame = numAnimFrames - 1;
|
float lastFrame = numAnimFrames - 1;
|
||||||
for (int i = 0; i < numAnimFrames; i++) {
|
for (int i = 0; i < numAnimFrames; i++) {
|
||||||
@@ -1269,6 +1321,18 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
return values;
|
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,
|
private void createNativeChildAnimator(long propertyPtr, long extraDelay,
|
||||||
ObjectAnimator animator) {
|
ObjectAnimator animator) {
|
||||||
long duration = animator.getDuration();
|
long duration = animator.getDuration();
|
||||||
@@ -1545,6 +1609,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
|||||||
private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
|
private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
|
||||||
float endValue);
|
float endValue);
|
||||||
private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
|
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 nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
|
||||||
private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
|
private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
|
||||||
private static native void nEnd(long animatorSetPtr);
|
private static native void nEnd(long animatorSetPtr);
|
||||||
|
|||||||
@@ -25,7 +25,27 @@ namespace uirenderer {
|
|||||||
|
|
||||||
using namespace VectorDrawable;
|
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) {
|
if (mDataSource.size() == 0) {
|
||||||
LOG_ALWAYS_FATAL("No data source is defined");
|
LOG_ALWAYS_FATAL("No data source is defined");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -41,57 +61,44 @@ float PropertyValuesHolder::getValueFromData(float fraction) {
|
|||||||
int lowIndex = floor(fraction);
|
int lowIndex = floor(fraction);
|
||||||
fraction -= lowIndex;
|
fraction -= lowIndex;
|
||||||
|
|
||||||
float value = mDataSource[lowIndex] * (1.0f - fraction)
|
T value;
|
||||||
+ mDataSource[lowIndex + 1] * fraction;
|
mEvaluator->evaluate(&value, mDataSource[lowIndex], mDataSource[lowIndex + 1], fraction);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPropertyValuesHolder::setFraction(float fraction) {
|
template<typename T>
|
||||||
float animatedValue;
|
const T PropertyValuesHolderImpl<T>::calculateAnimatedValue(float fraction) const {
|
||||||
if (mDataSource.size() > 0) {
|
if (mDataSource.size() > 0) {
|
||||||
animatedValue = getValueFromData(fraction);
|
return getValueFromData(fraction);
|
||||||
} else {
|
} else {
|
||||||
animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
|
T value;
|
||||||
|
mEvaluator->evaluate(&value, mStartValue, mEndValue, fraction);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GroupPropertyValuesHolder::setFraction(float fraction) {
|
||||||
|
float animatedValue = calculateAnimatedValue(fraction);
|
||||||
mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
|
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 FullPathColorPropertyValuesHolder::setFraction(float fraction) {
|
void FullPathColorPropertyValuesHolder::setFraction(float fraction) {
|
||||||
SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction);
|
SkColor animatedValue = calculateAnimatedValue(fraction);
|
||||||
mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
|
mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FullPathPropertyValuesHolder::setFraction(float fraction) {
|
void FullPathPropertyValuesHolder::setFraction(float fraction) {
|
||||||
float animatedValue;
|
float animatedValue = calculateAnimatedValue(fraction);
|
||||||
if (mDataSource.size() > 0) {
|
|
||||||
animatedValue = getValueFromData(fraction);
|
|
||||||
} else {
|
|
||||||
animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
|
|
||||||
}
|
|
||||||
mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
|
mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathDataPropertyValuesHolder::setFraction(float fraction) {
|
void PathDataPropertyValuesHolder::setFraction(float fraction) {
|
||||||
VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction);
|
mEvaluator->evaluate(&mPathData, mStartValue, mEndValue, fraction);
|
||||||
mPath->mutateProperties()->setData(mPathData);
|
mPath->mutateProperties()->setData(mPathData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
|
void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
|
||||||
float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
|
float animatedValue = calculateAnimatedValue(fraction);
|
||||||
mTree->mutateProperties()->setRootAlpha(animatedValue);
|
mTree->mutateProperties()->setRootAlpha(animatedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,91 +31,130 @@ namespace uirenderer {
|
|||||||
class ANDROID_API PropertyValuesHolder {
|
class ANDROID_API PropertyValuesHolder {
|
||||||
public:
|
public:
|
||||||
virtual void setFraction(float fraction) = 0;
|
virtual void setFraction(float fraction) = 0;
|
||||||
void setPropertyDataSource(float* dataSource, int length) {
|
virtual ~PropertyValuesHolder() {}
|
||||||
mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length);
|
|
||||||
}
|
|
||||||
float getValueFromData(float fraction);
|
|
||||||
virtual ~PropertyValuesHolder() {}
|
|
||||||
protected:
|
|
||||||
std::vector<float> mDataSource;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ANDROID_API GroupPropertyValuesHolder : public 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);
|
||||||
|
}
|
||||||
|
// 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::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 PropertyValuesHolderImpl<float> {
|
||||||
public:
|
public:
|
||||||
GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue,
|
GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue,
|
||||||
float endValue)
|
float endValue)
|
||||||
: mGroup(ptr)
|
: PropertyValuesHolderImpl(startValue, endValue)
|
||||||
, mPropertyId(propertyId)
|
, mGroup(ptr)
|
||||||
, mStartValue(startValue)
|
, mPropertyId(propertyId) {
|
||||||
, mEndValue(endValue){
|
mEvaluator.reset(new FloatEvaluator());
|
||||||
}
|
}
|
||||||
void setFraction(float fraction) override;
|
void setFraction(float fraction) override;
|
||||||
private:
|
private:
|
||||||
VectorDrawable::Group* mGroup;
|
VectorDrawable::Group* mGroup;
|
||||||
int mPropertyId;
|
int mPropertyId;
|
||||||
float mStartValue;
|
|
||||||
float mEndValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolder {
|
class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> {
|
||||||
public:
|
public:
|
||||||
FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, int32_t startValue,
|
FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId,
|
||||||
int32_t endValue)
|
SkColor startValue, SkColor endValue)
|
||||||
: mFullPath(ptr)
|
: PropertyValuesHolderImpl(startValue, endValue)
|
||||||
, mPropertyId(propertyId)
|
, mFullPath(ptr)
|
||||||
, mStartValue(startValue)
|
, mPropertyId(propertyId) {
|
||||||
, mEndValue(endValue) {};
|
mEvaluator.reset(new ColorEvaluator());
|
||||||
|
}
|
||||||
void setFraction(float fraction) override;
|
void setFraction(float fraction) override;
|
||||||
static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction);
|
static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction);
|
||||||
private:
|
private:
|
||||||
VectorDrawable::FullPath* mFullPath;
|
VectorDrawable::FullPath* mFullPath;
|
||||||
int mPropertyId;
|
int mPropertyId;
|
||||||
int32_t mStartValue;
|
|
||||||
int32_t mEndValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolder {
|
class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
|
||||||
public:
|
public:
|
||||||
FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue,
|
FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue,
|
||||||
float endValue)
|
float endValue)
|
||||||
: mFullPath(ptr)
|
: PropertyValuesHolderImpl(startValue, endValue)
|
||||||
, mPropertyId(propertyId)
|
, mFullPath(ptr)
|
||||||
, mStartValue(startValue)
|
, mPropertyId(propertyId) {
|
||||||
, mEndValue(endValue) {};
|
mEvaluator.reset(new FloatEvaluator());
|
||||||
|
};
|
||||||
void setFraction(float fraction) override;
|
void setFraction(float fraction) override;
|
||||||
private:
|
private:
|
||||||
VectorDrawable::FullPath* mFullPath;
|
VectorDrawable::FullPath* mFullPath;
|
||||||
int mPropertyId;
|
int mPropertyId;
|
||||||
float mStartValue;
|
|
||||||
float mEndValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolder {
|
class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> {
|
||||||
public:
|
public:
|
||||||
PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue,
|
PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue,
|
||||||
PathData* endValue)
|
PathData* endValue)
|
||||||
: mPath(ptr)
|
: PropertyValuesHolderImpl(*startValue, *endValue)
|
||||||
, mStartValue(*startValue)
|
, mPath(ptr) {
|
||||||
, mEndValue(*endValue) {};
|
mEvaluator.reset(new PathEvaluator());
|
||||||
|
};
|
||||||
void setFraction(float fraction) override;
|
void setFraction(float fraction) override;
|
||||||
private:
|
private:
|
||||||
VectorDrawable::Path* mPath;
|
VectorDrawable::Path* mPath;
|
||||||
PathData mPathData;
|
PathData mPathData;
|
||||||
PathData mStartValue;
|
|
||||||
PathData mEndValue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolder {
|
class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
|
||||||
public:
|
public:
|
||||||
RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue)
|
RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue)
|
||||||
: mTree(tree)
|
: PropertyValuesHolderImpl(startValue, endValue)
|
||||||
, mStartValue(startValue)
|
, mTree(tree) {
|
||||||
, mEndValue(endValue) {}
|
mEvaluator.reset(new FloatEvaluator());
|
||||||
|
}
|
||||||
void setFraction(float fraction) override;
|
void setFraction(float fraction) override;
|
||||||
private:
|
private:
|
||||||
VectorDrawable::Tree* mTree;
|
VectorDrawable::Tree* mTree;
|
||||||
float mStartValue;
|
|
||||||
float mEndValue;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user