VectorDrawable native rendering - Step 5 of MANY
Implemented reset() (public API for AVD) and reverse() (internal API that needs to be supported) Change-Id: Ife1650049f271cad1347943151a5800c40c20aa2
This commit is contained in:
@@ -807,6 +807,8 @@ public final class AnimatorSet extends Animator {
|
||||
}
|
||||
|
||||
/**
|
||||
* AnimatorSet is only reversible when the set contains no sequential animation, and no child
|
||||
* animators have a start delay.
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
|
||||
@@ -43,12 +43,13 @@ static JNIEnv* getEnv(JavaVM* vm) {
|
||||
return env;
|
||||
}
|
||||
|
||||
static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) {
|
||||
static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) {
|
||||
class AnimationListenerBridge : public AnimationListener {
|
||||
public:
|
||||
AnimationListenerBridge(JNIEnv* env, jobject finishListener) {
|
||||
AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) {
|
||||
mFinishListener = env->NewGlobalRef(finishListener);
|
||||
env->GetJavaVM(&mJvm);
|
||||
mId = id;
|
||||
}
|
||||
|
||||
virtual ~AnimationListenerBridge() {
|
||||
@@ -63,7 +64,7 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis
|
||||
env->CallStaticVoidMethod(
|
||||
gVectorDrawableAnimatorClassInfo.clazz,
|
||||
gVectorDrawableAnimatorClassInfo.callOnFinished,
|
||||
mFinishListener);
|
||||
mFinishListener, mId);
|
||||
releaseJavaObject();
|
||||
}
|
||||
|
||||
@@ -76,8 +77,9 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis
|
||||
|
||||
JavaVM* mJvm;
|
||||
jobject mFinishListener;
|
||||
jint mId;
|
||||
};
|
||||
return new AnimationListenerBridge(env, finishListener);
|
||||
return new AnimationListenerBridge(env, finishListener, id);
|
||||
}
|
||||
|
||||
static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr,
|
||||
@@ -142,15 +144,16 @@ static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
|
||||
holder->setPropertyDataSource(propertyData, length);
|
||||
env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
|
||||
}
|
||||
static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
|
||||
static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
|
||||
PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
|
||||
// TODO: keep a ref count in finish listener
|
||||
AnimationListener* listener = createAnimationListener(env, finishListener);
|
||||
AnimationListener* listener = createAnimationListener(env, finishListener, id);
|
||||
set->start(listener);
|
||||
}
|
||||
|
||||
static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
|
||||
// TODO: implement reverse
|
||||
static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
|
||||
PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
|
||||
AnimationListener* listener = createAnimationListener(env, finishListener, id);
|
||||
set->reverse(listener);
|
||||
}
|
||||
|
||||
static void end(JNIEnv*, jobject, jlong animatorSetPtr) {
|
||||
@@ -172,8 +175,8 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
|
||||
{"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
|
||||
{"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData},
|
||||
{"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)start},
|
||||
{"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse},
|
||||
{"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start},
|
||||
{"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse},
|
||||
{"nEnd", "!(J)V", (void*)end},
|
||||
{"nReset", "!(J)V", (void*)reset},
|
||||
};
|
||||
@@ -186,7 +189,7 @@ int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {
|
||||
|
||||
gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
|
||||
env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
|
||||
"(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V");
|
||||
"(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V");
|
||||
return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
|
||||
gMethods, NELEM(gMethods));
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) {
|
||||
|
||||
static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) {
|
||||
BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
|
||||
animator->end();
|
||||
animator->cancel();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -238,9 +238,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas);
|
||||
}
|
||||
mAnimatedVectorState.mVectorDrawable.draw(canvas);
|
||||
if (isStarted()) {
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -611,10 +608,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
return mAnimatorSet.isRunning();
|
||||
}
|
||||
|
||||
private boolean isStarted() {
|
||||
return mAnimatorSet.isStarted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the AnimatedVectorDrawable to the start state as specified in the animators.
|
||||
*/
|
||||
@@ -626,12 +619,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
@Override
|
||||
public void start() {
|
||||
ensureAnimatorSet();
|
||||
|
||||
// If any one of the animator has not ended, do nothing.
|
||||
if (isStarted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAnimatorSet.start();
|
||||
invalidateSelf();
|
||||
}
|
||||
@@ -652,6 +639,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
@Override
|
||||
public void stop() {
|
||||
mAnimatorSet.end();
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -774,6 +762,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
* @hide
|
||||
*/
|
||||
public static class VectorDrawableAnimator {
|
||||
private static final int NONE = 0;
|
||||
private static final int START_ANIMATION = 1;
|
||||
private static final int REVERSE_ANIMATION = 2;
|
||||
private AnimatorListener mListener = null;
|
||||
private final LongArray mStartDelays = new LongArray();
|
||||
private PropertyValuesHolder.PropertyValues mTmpValues =
|
||||
@@ -782,7 +773,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
private boolean mContainsSequentialAnimators = false;
|
||||
private boolean mStarted = false;
|
||||
private boolean mInitialized = false;
|
||||
private boolean mAnimationPending = false;
|
||||
private boolean mIsReversible = false;
|
||||
// This needs to be set before parsing starts.
|
||||
private boolean mShouldIgnoreInvalidAnim;
|
||||
@@ -790,7 +780,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
private final VirtualRefBasePtr mSetRefBasePtr;
|
||||
private WeakReference<RenderNode> mTarget = null;
|
||||
private WeakReference<RenderNode> mLastSeenTarget = null;
|
||||
|
||||
private int mLastListenerId = 0;
|
||||
private int mPendingAnimationAction = NONE;
|
||||
|
||||
VectorDrawableAnimator() {
|
||||
mSetPtr = nCreateAnimatorSet();
|
||||
@@ -810,6 +801,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
mInitialized = true;
|
||||
|
||||
// Check reversible.
|
||||
mIsReversible = true;
|
||||
if (mContainsSequentialAnimators) {
|
||||
mIsReversible = false;
|
||||
} else {
|
||||
@@ -821,7 +813,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
}
|
||||
}
|
||||
}
|
||||
mIsReversible = true;
|
||||
}
|
||||
|
||||
private void parseAnimatorSet(AnimatorSet set, long startTime) {
|
||||
@@ -1042,27 +1033,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
* to the last seen RenderNode target and start right away.
|
||||
*/
|
||||
protected void recordLastSeenTarget(DisplayListCanvas canvas) {
|
||||
if (mAnimationPending) {
|
||||
mLastSeenTarget = new WeakReference<RenderNode>(
|
||||
RenderNodeAnimatorSetHelper.getTarget(canvas));
|
||||
mLastSeenTarget = new WeakReference<RenderNode>(
|
||||
RenderNodeAnimatorSetHelper.getTarget(canvas));
|
||||
if (mPendingAnimationAction != NONE) {
|
||||
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
|
||||
Log.d(LOGTAG, "Target is set in the next frame");
|
||||
}
|
||||
mAnimationPending = false;
|
||||
start();
|
||||
} else {
|
||||
mLastSeenTarget = new WeakReference<RenderNode>(
|
||||
RenderNodeAnimatorSetHelper.getTarget(canvas));
|
||||
if (mPendingAnimationAction == START_ANIMATION) {
|
||||
start();
|
||||
} else if (mPendingAnimationAction == REVERSE_ANIMATION) {
|
||||
reverse();
|
||||
}
|
||||
mPendingAnimationAction = NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean setTarget(RenderNode node) {
|
||||
if (mTarget != null && mTarget.get() != null) {
|
||||
// TODO: Maybe we want to support target change.
|
||||
throw new IllegalStateException("Target already set!");
|
||||
}
|
||||
|
||||
node.addAnimator(this);
|
||||
mTarget = new WeakReference<RenderNode>(node);
|
||||
return true;
|
||||
@@ -1081,12 +1067,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!useLastSeenTarget()) {
|
||||
mAnimationPending = true;
|
||||
mPendingAnimationAction = START_ANIMATION;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1094,38 +1076,45 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
|
||||
}
|
||||
|
||||
nStart(mSetPtr, this);
|
||||
mStarted = true;
|
||||
nStart(mSetPtr, this, ++mLastListenerId);
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(null);
|
||||
}
|
||||
mStarted = true;
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (mInitialized && mStarted) {
|
||||
if (mInitialized && useLastSeenTarget()) {
|
||||
// If no target has ever been set, no-op
|
||||
nEnd(mSetPtr);
|
||||
onAnimationEnd();
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (!mInitialized) {
|
||||
return;
|
||||
public void reset() {
|
||||
if (mInitialized && useLastSeenTarget()) {
|
||||
// If no target has ever been set, no-op
|
||||
nReset(mSetPtr);
|
||||
}
|
||||
// TODO: Need to implement reset.
|
||||
Log.w(LOGTAG, "Reset is yet to be implemented");
|
||||
nReset(mSetPtr);
|
||||
}
|
||||
|
||||
// Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
|
||||
// animators or when the animator set has a start delay
|
||||
void reverse() {
|
||||
if (!mIsReversible) {
|
||||
if (!mIsReversible || !mInitialized) {
|
||||
return;
|
||||
}
|
||||
// TODO: Need to support reverse (non-public API)
|
||||
Log.w(LOGTAG, "Reverse is yet to be implemented");
|
||||
nReverse(mSetPtr, this);
|
||||
if (!useLastSeenTarget()) {
|
||||
mPendingAnimationAction = REVERSE_ANIMATION;
|
||||
return;
|
||||
}
|
||||
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
|
||||
Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
|
||||
}
|
||||
mStarted = true;
|
||||
nReverse(mSetPtr, this, ++mLastListenerId);
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
public long getAnimatorNativePtr() {
|
||||
@@ -1155,7 +1144,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
private void onAnimationEnd() {
|
||||
private void onAnimationEnd(int listenerId) {
|
||||
if (listenerId != mLastListenerId) {
|
||||
return;
|
||||
}
|
||||
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
|
||||
Log.d(LOGTAG, "on finished called from native");
|
||||
}
|
||||
mStarted = false;
|
||||
if (mListener != null) {
|
||||
mListener.onAnimationEnd(null);
|
||||
@@ -1164,11 +1159,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
|
||||
}
|
||||
|
||||
// onFinished: should be called from native
|
||||
private static void callOnFinished(VectorDrawableAnimator set) {
|
||||
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
|
||||
Log.d(LOGTAG, "on finished called from native");
|
||||
}
|
||||
set.onAnimationEnd();
|
||||
private static void callOnFinished(VectorDrawableAnimator set, int id) {
|
||||
set.onAnimationEnd(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1188,8 +1180,8 @@ 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 nStart(long animatorSetPtr, VectorDrawableAnimator set);
|
||||
private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set);
|
||||
private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set, int id);
|
||||
private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id);
|
||||
private static native void nEnd(long animatorSetPtr);
|
||||
private static native void nReset(long animatorSetPtr);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
|
||||
, mStartTime(0)
|
||||
, mDuration(300)
|
||||
, mStartDelay(0)
|
||||
, mMayRunAsync(true) {
|
||||
, mMayRunAsync(true)
|
||||
, mPlayTime(0) {
|
||||
}
|
||||
|
||||
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
|
||||
@@ -85,20 +86,113 @@ void BaseRenderNodeAnimator::attach(RenderNode* target) {
|
||||
onAttached();
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::start() {
|
||||
mStagingPlayState = PlayState::Running;
|
||||
mStagingRequests.push_back(Request::Start);
|
||||
onStagingPlayStateChanged();
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::cancel() {
|
||||
mStagingPlayState = PlayState::Finished;
|
||||
mStagingRequests.push_back(Request::Cancel);
|
||||
onStagingPlayStateChanged();
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::reset() {
|
||||
mStagingPlayState = PlayState::Finished;
|
||||
mStagingRequests.push_back(Request::Reset);
|
||||
onStagingPlayStateChanged();
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::reverse() {
|
||||
mStagingPlayState = PlayState::Reversing;
|
||||
mStagingRequests.push_back(Request::Reverse);
|
||||
onStagingPlayStateChanged();
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::end() {
|
||||
mStagingPlayState = PlayState::Finished;
|
||||
mStagingRequests.push_back(Request::End);
|
||||
onStagingPlayStateChanged();
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
|
||||
switch (request) {
|
||||
case Request::Start:
|
||||
mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
|
||||
mPlayTime : 0;
|
||||
mPlayState = PlayState::Running;
|
||||
break;
|
||||
case Request::Reverse:
|
||||
mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
|
||||
mPlayTime : mDuration;
|
||||
mPlayState = PlayState::Reversing;
|
||||
break;
|
||||
case Request::Reset:
|
||||
mPlayTime = 0;
|
||||
mPlayState = PlayState::Finished;
|
||||
break;
|
||||
case Request::Cancel:
|
||||
mPlayState = PlayState::Finished;
|
||||
break;
|
||||
case Request::End:
|
||||
mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
|
||||
mPlayState = PlayState::Finished;
|
||||
break;
|
||||
default:
|
||||
LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
|
||||
};
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
|
||||
if (!mHasStartValue) {
|
||||
doSetStartValue(getValue(mTarget));
|
||||
}
|
||||
if (mStagingPlayState > mPlayState) {
|
||||
if (mStagingPlayState == PlayState::Restarted) {
|
||||
mStagingPlayState = PlayState::Running;
|
||||
|
||||
if (!mStagingRequests.empty()) {
|
||||
// Keep track of the play state and play time before they are changed when
|
||||
// staging requests are resolved.
|
||||
nsecs_t currentPlayTime = mPlayTime;
|
||||
PlayState prevFramePlayState = mPlayState;
|
||||
|
||||
// Resolve staging requests one by one.
|
||||
for (Request request : mStagingRequests) {
|
||||
resolveStagingRequest(request);
|
||||
}
|
||||
mPlayState = mStagingPlayState;
|
||||
// Oh boy, we're starting! Man the battle stations!
|
||||
if (mPlayState == PlayState::Running) {
|
||||
transitionToRunning(context);
|
||||
} else if (mPlayState == PlayState::Finished) {
|
||||
mStagingRequests.clear();
|
||||
|
||||
if (mStagingPlayState == PlayState::Finished) {
|
||||
// Set the staging play time and end the animation
|
||||
updatePlayTime(mPlayTime);
|
||||
callOnFinishedListener(context);
|
||||
} else if (mStagingPlayState == PlayState::Running
|
||||
|| mStagingPlayState == PlayState::Reversing) {
|
||||
bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
|
||||
if (prevFramePlayState != mStagingPlayState) {
|
||||
transitionToRunning(context);
|
||||
}
|
||||
if (changed) {
|
||||
// Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
|
||||
// requested from UI thread). It is achieved by modifying mStartTime, such that
|
||||
// current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
|
||||
// case of reversing)
|
||||
nsecs_t currentFrameTime = context.frameTimeMs();
|
||||
if (mPlayState == PlayState::Reversing) {
|
||||
// Reverse is not supported for animations with a start delay, so here we
|
||||
// assume no start delay.
|
||||
mStartTime = currentFrameTime - (mDuration - mPlayTime);
|
||||
} else {
|
||||
// Animation should play forward
|
||||
if (mPlayTime == 0) {
|
||||
// If the request is to start from the beginning, include start delay.
|
||||
mStartTime = currentFrameTime + mStartDelay;
|
||||
} else {
|
||||
// If the request is to seek to a non-zero play time, then we skip start
|
||||
// delay.
|
||||
mStartTime = currentFrameTime - mPlayTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,37 +230,37 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
|
||||
|
||||
// This should be set before setValue() so animators can query this time when setValue
|
||||
// is called.
|
||||
nsecs_t currentFrameTime = context.frameTimeMs();
|
||||
onPlayTimeChanged(currentFrameTime - mStartTime);
|
||||
nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
|
||||
bool finished = updatePlayTime(currentPlayTime);
|
||||
if (finished && mPlayState != PlayState::Finished) {
|
||||
mPlayState = PlayState::Finished;
|
||||
callOnFinishedListener(context);
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
|
||||
mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
|
||||
onPlayTimeChanged(mPlayTime);
|
||||
// If BaseRenderNodeAnimator is handling the delay (not typical), then
|
||||
// because the staging properties reflect the final value, we always need
|
||||
// to call setValue even if the animation isn't yet running or is still
|
||||
// being delayed as we need to override the staging value
|
||||
if (mStartTime > context.frameTimeMs()) {
|
||||
if (playTime < 0) {
|
||||
setValue(mTarget, mFromValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
float fraction = 1.0f;
|
||||
|
||||
if (mPlayState == PlayState::Running && mDuration > 0) {
|
||||
fraction = (float)(currentFrameTime - mStartTime) / mDuration;
|
||||
}
|
||||
if (fraction >= 1.0f) {
|
||||
fraction = 1.0f;
|
||||
mPlayState = PlayState::Finished;
|
||||
if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
|
||||
fraction = mPlayTime / (float) mDuration;
|
||||
}
|
||||
fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
|
||||
|
||||
fraction = mInterpolator->interpolate(fraction);
|
||||
setValue(mTarget, mFromValue + (mDeltaValue * fraction));
|
||||
|
||||
if (mPlayState == PlayState::Finished) {
|
||||
callOnFinishedListener(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return playTime >= mDuration;
|
||||
}
|
||||
|
||||
void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include "utils/Macros.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
@@ -59,14 +61,14 @@ public:
|
||||
mMayRunAsync = mayRunAsync;
|
||||
}
|
||||
bool mayRunAsync() { return mMayRunAsync; }
|
||||
ANDROID_API void start() {
|
||||
if (mStagingPlayState == PlayState::NotStarted) {
|
||||
mStagingPlayState = PlayState::Running;
|
||||
} else {
|
||||
mStagingPlayState = PlayState::Restarted;
|
||||
}
|
||||
onStagingPlayStateChanged(); }
|
||||
ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); }
|
||||
ANDROID_API void start();
|
||||
ANDROID_API void reset();
|
||||
ANDROID_API void reverse();
|
||||
// Terminates the animation at its current progress.
|
||||
ANDROID_API void cancel();
|
||||
|
||||
// Terminates the animation and skip to the end of the animation.
|
||||
ANDROID_API void end();
|
||||
|
||||
void attach(RenderNode* target);
|
||||
virtual void onAttached() {}
|
||||
@@ -74,36 +76,41 @@ public:
|
||||
void pushStaging(AnimationContext& context);
|
||||
bool animate(AnimationContext& context);
|
||||
|
||||
bool isRunning() { return mPlayState == PlayState::Running; }
|
||||
bool isRunning() { return mPlayState == PlayState::Running
|
||||
|| mPlayState == PlayState::Reversing; }
|
||||
bool isFinished() { return mPlayState == PlayState::Finished; }
|
||||
float finalValue() { return mFinalValue; }
|
||||
|
||||
ANDROID_API virtual uint32_t dirtyMask() = 0;
|
||||
|
||||
void forceEndNow(AnimationContext& context);
|
||||
RenderNode* target() { return mTarget; }
|
||||
|
||||
protected:
|
||||
// PlayState is used by mStagingPlayState and mPlayState to track the state initiated from UI
|
||||
// thread and Render Thread animation state, respectively.
|
||||
// From the UI thread, mStagingPlayState transition looks like
|
||||
// NotStarted -> Running -> Finished
|
||||
// ^ |
|
||||
// | |
|
||||
// Restarted <------
|
||||
// NotStarted -> Running/Reversing -> Finished
|
||||
// ^ |
|
||||
// | |
|
||||
// ----------------------
|
||||
// Note: For mStagingState, the Finished state (optional) is only set when the animation is
|
||||
// terminated by user.
|
||||
//
|
||||
// On Render Thread, mPlayState transition:
|
||||
// NotStart -> Running -> Finished
|
||||
// ^ |
|
||||
// | |
|
||||
// -------------
|
||||
// NotStart -> Running/Reversing-> Finished
|
||||
// ^ |
|
||||
// | |
|
||||
// ------------------
|
||||
// Note that if the animation is in Running/Reversing state, calling start or reverse again
|
||||
// would do nothing if the animation has the same play direction as the request; otherwise,
|
||||
// the animation would start from where it is and change direction (i.e. Reversing <-> Running)
|
||||
|
||||
enum class PlayState {
|
||||
NotStarted,
|
||||
Running,
|
||||
Reversing,
|
||||
Finished,
|
||||
Restarted,
|
||||
};
|
||||
|
||||
BaseRenderNodeAnimator(float finalValue);
|
||||
@@ -111,7 +118,6 @@ protected:
|
||||
|
||||
virtual float getValue(RenderNode* target) const = 0;
|
||||
virtual void setValue(RenderNode* target, float value) = 0;
|
||||
RenderNode* target() { return mTarget; }
|
||||
|
||||
void callOnFinishedListener(AnimationContext& context);
|
||||
|
||||
@@ -132,13 +138,28 @@ protected:
|
||||
nsecs_t mDuration;
|
||||
nsecs_t mStartDelay;
|
||||
bool mMayRunAsync;
|
||||
// Play Time tracks the progress of animation, it should always be [0, mDuration], 0 being
|
||||
// the beginning of the animation, will reach mDuration at the end of an animation.
|
||||
nsecs_t mPlayTime;
|
||||
|
||||
sp<AnimationListener> mListener;
|
||||
|
||||
private:
|
||||
enum class Request {
|
||||
Start,
|
||||
Reverse,
|
||||
Reset,
|
||||
Cancel,
|
||||
End
|
||||
};
|
||||
inline void checkMutable();
|
||||
virtual void transitionToRunning(AnimationContext& context);
|
||||
void doSetStartValue(float value);
|
||||
bool updatePlayTime(nsecs_t playTime);
|
||||
void resolveStagingRequest(Request request);
|
||||
|
||||
std::vector<Request> mStagingRequests;
|
||||
|
||||
};
|
||||
|
||||
class RenderPropertyAnimator : public BaseRenderNodeAnimator {
|
||||
|
||||
@@ -27,9 +27,8 @@ namespace uirenderer {
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void unref(BaseRenderNodeAnimator* animator) {
|
||||
static void detach(sp<BaseRenderNodeAnimator>& animator) {
|
||||
animator->detach();
|
||||
animator->decStrong(nullptr);
|
||||
}
|
||||
|
||||
AnimatorManager::AnimatorManager(RenderNode& parent)
|
||||
@@ -38,14 +37,12 @@ AnimatorManager::AnimatorManager(RenderNode& parent)
|
||||
}
|
||||
|
||||
AnimatorManager::~AnimatorManager() {
|
||||
for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
|
||||
for_each(mAnimators.begin(), mAnimators.end(), unref);
|
||||
for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
|
||||
for_each(mAnimators.begin(), mAnimators.end(), detach);
|
||||
}
|
||||
|
||||
void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
||||
animator->incStrong(nullptr);
|
||||
animator->attach(&mParent);
|
||||
mNewAnimators.push_back(animator.get());
|
||||
mNewAnimators.emplace_back(animator.get());
|
||||
}
|
||||
|
||||
void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
|
||||
@@ -56,25 +53,31 @@ void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
|
||||
&mParent, mParent.getName());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void move_all(T& source, T& dest) {
|
||||
dest.reserve(source.size() + dest.size());
|
||||
for (typename T::iterator it = source.begin(); it != source.end(); it++) {
|
||||
dest.push_back(*it);
|
||||
}
|
||||
source.clear();
|
||||
}
|
||||
|
||||
void AnimatorManager::pushStaging() {
|
||||
if (mNewAnimators.size()) {
|
||||
LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
|
||||
"Trying to start new animators on %p (%s) without an animation handle!",
|
||||
&mParent, mParent.getName());
|
||||
// Since this is a straight move, we don't need to inc/dec the ref count
|
||||
move_all(mNewAnimators, mAnimators);
|
||||
// Only add animators that are not already in the on-going animator list.
|
||||
for (auto& animator : mNewAnimators) {
|
||||
RenderNode* targetRenderNode = animator->target();
|
||||
if (targetRenderNode == &mParent) {
|
||||
// Animator already in the animator list: skip adding again
|
||||
continue;
|
||||
}
|
||||
|
||||
if (targetRenderNode){
|
||||
// If the animator is already in another RenderNode's animator list, remove animator from
|
||||
// that list and add animator to current RenderNode's list.
|
||||
targetRenderNode->animators().removeActiveAnimator(animator);
|
||||
}
|
||||
animator->attach(&mParent);
|
||||
mAnimators.push_back(std::move(animator));
|
||||
}
|
||||
mNewAnimators.clear();
|
||||
}
|
||||
for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
|
||||
(*it)->pushStaging(mAnimationHandle->context());
|
||||
for (auto& animator : mAnimators) {
|
||||
animator->pushStaging(mAnimationHandle->context());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,11 +86,11 @@ public:
|
||||
AnimateFunctor(TreeInfo& info, AnimationContext& context)
|
||||
: dirtyMask(0), mInfo(info), mContext(context) {}
|
||||
|
||||
bool operator() (BaseRenderNodeAnimator* animator) {
|
||||
bool operator() (sp<BaseRenderNodeAnimator>& animator) {
|
||||
dirtyMask |= animator->dirtyMask();
|
||||
bool remove = animator->animate(mContext);
|
||||
if (remove) {
|
||||
animator->decStrong(nullptr);
|
||||
animator->detach();
|
||||
} else {
|
||||
if (animator->isRunning()) {
|
||||
mInfo.out.hasAnimations = true;
|
||||
@@ -129,20 +132,18 @@ void AnimatorManager::animateNoDamage(TreeInfo& info) {
|
||||
|
||||
uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
|
||||
AnimateFunctor functor(info, mAnimationHandle->context());
|
||||
std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
|
||||
newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
|
||||
auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
|
||||
mAnimators.erase(newEnd, mAnimators.end());
|
||||
mAnimationHandle->notifyAnimationsRan();
|
||||
mParent.mProperties.updateMatrix();
|
||||
return functor.dirtyMask;
|
||||
}
|
||||
|
||||
static void endStagingAnimator(BaseRenderNodeAnimator* animator) {
|
||||
animator->end();
|
||||
static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
|
||||
animator->cancel();
|
||||
if (animator->listener()) {
|
||||
animator->listener()->onAnimationFinished(animator);
|
||||
animator->listener()->onAnimationFinished(animator.get());
|
||||
}
|
||||
animator->decStrong(nullptr);
|
||||
}
|
||||
|
||||
void AnimatorManager::endAllStagingAnimators() {
|
||||
@@ -153,13 +154,16 @@ void AnimatorManager::endAllStagingAnimators() {
|
||||
mNewAnimators.clear();
|
||||
}
|
||||
|
||||
void AnimatorManager::removeActiveAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
||||
std::remove(mAnimators.begin(), mAnimators.end(), animator);
|
||||
}
|
||||
|
||||
class EndActiveAnimatorsFunctor {
|
||||
public:
|
||||
EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
|
||||
|
||||
void operator() (BaseRenderNodeAnimator* animator) {
|
||||
void operator() (sp<BaseRenderNodeAnimator>& animator) {
|
||||
animator->forceEndNow(mContext);
|
||||
animator->decStrong(nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -62,13 +62,17 @@ public:
|
||||
private:
|
||||
uint32_t animateCommon(TreeInfo& info);
|
||||
|
||||
// This would remove the animator from mAnimators list. It should only be called during
|
||||
// push staging.
|
||||
void removeActiveAnimator(const sp<BaseRenderNodeAnimator>& animator);
|
||||
|
||||
RenderNode& mParent;
|
||||
AnimationHandle* mAnimationHandle;
|
||||
|
||||
// To improve the efficiency of resizing & removing from the vector
|
||||
// use manual ref counting instead of sp<>.
|
||||
std::vector<BaseRenderNodeAnimator*> mNewAnimators;
|
||||
std::vector<BaseRenderNodeAnimator*> mAnimators;
|
||||
std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators;
|
||||
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
|
||||
};
|
||||
|
||||
} /* namespace uirenderer */
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "PropertyValuesAnimatorSet.h"
|
||||
#include "RenderNode.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
@@ -53,16 +55,26 @@ void PropertyValuesAnimatorSet::setValue(RenderNode* target, float value) {
|
||||
}
|
||||
|
||||
void PropertyValuesAnimatorSet::onPlayTimeChanged(nsecs_t playTime) {
|
||||
for (size_t i = 0; i < mAnimators.size(); i++) {
|
||||
mAnimators[i]->setCurrentPlayTime(playTime);
|
||||
if (playTime == 0 && mDuration > 0) {
|
||||
// Reset all the animators
|
||||
for (auto it = mAnimators.rbegin(); it != mAnimators.rend(); it++) {
|
||||
// Note that this set may containing animators modifying the same property, so when we
|
||||
// reset the animators, we need to make sure the animators that end the first will
|
||||
// have the final say on what the property value should be.
|
||||
(*it)->setFraction(0);
|
||||
}
|
||||
} else if (playTime >= mDuration) {
|
||||
// Skip all the animators to end
|
||||
for (auto& anim : mAnimators) {
|
||||
anim->setFraction(1);
|
||||
}
|
||||
} else {
|
||||
for (auto& anim : mAnimators) {
|
||||
anim->setCurrentPlayTime(playTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyValuesAnimatorSet::reset() {
|
||||
// TODO: implement reset through adding a play state because we need to support reset() even
|
||||
// during an animation run.
|
||||
}
|
||||
|
||||
void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
|
||||
init();
|
||||
mOneShotListener = listener;
|
||||
@@ -70,20 +82,23 @@ void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
|
||||
}
|
||||
|
||||
void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
|
||||
// TODO: implement reverse
|
||||
init();
|
||||
mOneShotListener = listener;
|
||||
BaseRenderNodeAnimator::reverse();
|
||||
}
|
||||
|
||||
void PropertyValuesAnimatorSet::init() {
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
nsecs_t maxDuration = 0;
|
||||
for (size_t i = 0; i < mAnimators.size(); i++) {
|
||||
if (maxDuration < mAnimators[i]->getTotalDuration()) {
|
||||
maxDuration = mAnimators[i]->getTotalDuration();
|
||||
}
|
||||
}
|
||||
mDuration = maxDuration;
|
||||
|
||||
// Sort the animators by their total duration. Note that all the animators in the set start at
|
||||
// the same time, so the ones with longer total duration (which includes start delay) will
|
||||
// be the ones that end later.
|
||||
std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) {
|
||||
return a->getTotalDuration() < b->getTotalDuration();
|
||||
});
|
||||
mDuration = mAnimators[mAnimators.size() - 1]->getTotalDuration();
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
@@ -106,18 +121,19 @@ PropertyAnimator::PropertyAnimator(PropertyValuesHolder* holder, Interpolator* i
|
||||
void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) {
|
||||
if (playTime >= mStartDelay && playTime < mTotalDuration) {
|
||||
nsecs_t currentIterationPlayTime = (playTime - mStartDelay) % mDuration;
|
||||
mLatestFraction = currentIterationPlayTime / (float) mDuration;
|
||||
float fraction = currentIterationPlayTime / (float) mDuration;
|
||||
setFraction(fraction);
|
||||
} else if (mLatestFraction < 1.0f && playTime >= mTotalDuration) {
|
||||
mLatestFraction = 1.0f;
|
||||
} else {
|
||||
return;
|
||||
// This makes sure we only set the fraction = 1 once. It is needed because there might
|
||||
// be another animator modifying the same property after this animator finishes, we need
|
||||
// to make sure we don't set conflicting values on the same property within one frame.
|
||||
setFraction(1.0f);
|
||||
}
|
||||
|
||||
setFraction(mLatestFraction);
|
||||
}
|
||||
|
||||
void PropertyAnimator::setFraction(float fraction) {
|
||||
float interpolatedFraction = mInterpolator->interpolate(mLatestFraction);
|
||||
mLatestFraction = fraction;
|
||||
float interpolatedFraction = mInterpolator->interpolate(fraction);
|
||||
mPropertyValuesHolder->setFraction(interpolatedFraction);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ public:
|
||||
|
||||
void start(AnimationListener* listener);
|
||||
void reverse(AnimationListener* listener);
|
||||
void reset();
|
||||
|
||||
void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
|
||||
Interpolator* interpolators, int64_t startDelays,
|
||||
|
||||
Reference in New Issue
Block a user