VectorDrawable native rendering - Step 5 of MANY
This is reverting the revert of what reverts the revert of the original
implementation. Fourth revert is a charm!
This reverts commit df7fdb1e0bdb5c289bbc08047e5c710185503309.
Change-Id: I6fc3a5accfd8b79c3da31bbc101ad9e9b4d6e7dd
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 7bd2b24..372bcb3 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -42,7 +42,8 @@
, mStartTime(0)
, mDuration(300)
, mStartDelay(0)
- , mMayRunAsync(true) {
+ , mMayRunAsync(true)
+ , mPlayTime(0) {
}
BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -85,20 +86,113 @@
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 @@
// 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 ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
+ fraction = mPlayTime / (float) mDuration;
}
- if (fraction >= 1.0f) {
- fraction = 1.0f;
- mPlayState = PlayState::Finished;
- }
+ 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) {