2 * Copyright (C) 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include "AnimationContext.h"
23 #include "Interpolator.h"
24 #include "RenderNode.h"
25 #include "RenderProperties.h"
28 namespace uirenderer {
30 /************************************************************
31 * BaseRenderNodeAnimator
32 ************************************************************/
34 BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
36 , mStagingTarget(nullptr)
37 , mFinalValue(finalValue)
40 , mStagingPlayState(PlayState::NotStarted)
41 , mPlayState(PlayState::NotStarted)
42 , mHasStartValue(false)
50 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
53 void BaseRenderNodeAnimator::checkMutable() {
54 // Should be impossible to hit as the Java-side also has guards for this
55 LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
56 "Animator has already been started!");
59 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
61 mInterpolator.reset(interpolator);
64 void BaseRenderNodeAnimator::setStartValue(float value) {
66 doSetStartValue(value);
69 void BaseRenderNodeAnimator::doSetStartValue(float value) {
71 mDeltaValue = (mFinalValue - mFromValue);
72 mHasStartValue = true;
75 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
80 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
82 mStartDelay = startDelay;
85 void BaseRenderNodeAnimator::attach(RenderNode* target) {
86 mStagingTarget = target;
90 void BaseRenderNodeAnimator::start() {
91 mStagingPlayState = PlayState::Running;
92 mStagingRequests.push_back(Request::Start);
93 onStagingPlayStateChanged();
96 void BaseRenderNodeAnimator::cancel() {
97 mStagingPlayState = PlayState::Finished;
98 mStagingRequests.push_back(Request::Cancel);
99 onStagingPlayStateChanged();
102 void BaseRenderNodeAnimator::reset() {
103 mStagingPlayState = PlayState::Finished;
104 mStagingRequests.push_back(Request::Reset);
105 onStagingPlayStateChanged();
108 void BaseRenderNodeAnimator::reverse() {
109 mStagingPlayState = PlayState::Reversing;
110 mStagingRequests.push_back(Request::Reverse);
111 onStagingPlayStateChanged();
114 void BaseRenderNodeAnimator::end() {
115 mStagingPlayState = PlayState::Finished;
116 mStagingRequests.push_back(Request::End);
117 onStagingPlayStateChanged();
120 void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
123 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
125 mPlayState = PlayState::Running;
126 mPendingActionUponFinish = Action::None;
128 case Request::Reverse:
129 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
130 mPlayTime : mDuration;
131 mPlayState = PlayState::Reversing;
132 mPendingActionUponFinish = Action::None;
136 mPlayState = PlayState::Finished;
137 mPendingActionUponFinish = Action::Reset;
139 case Request::Cancel:
140 mPlayState = PlayState::Finished;
141 mPendingActionUponFinish = Action::None;
144 mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
145 mPlayState = PlayState::Finished;
146 mPendingActionUponFinish = Action::End;
149 LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
153 void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
154 if (mStagingTarget) {
155 RenderNode* oldTarget = mTarget;
156 mTarget = mStagingTarget;
157 mStagingTarget = nullptr;
158 if (oldTarget && oldTarget != mTarget) {
159 oldTarget->onAnimatorTargetChanged(this);
163 if (!mHasStartValue) {
164 doSetStartValue(getValue(mTarget));
167 if (!mStagingRequests.empty()) {
168 // No interpolator was set, use the default
169 if (mPlayState == PlayState::NotStarted && !mInterpolator) {
170 mInterpolator.reset(Interpolator::createDefaultInterpolator());
172 // Keep track of the play state and play time before they are changed when
173 // staging requests are resolved.
174 nsecs_t currentPlayTime = mPlayTime;
175 PlayState prevFramePlayState = mPlayState;
177 // Resolve staging requests one by one.
178 for (Request request : mStagingRequests) {
179 resolveStagingRequest(request);
181 mStagingRequests.clear();
183 if (mStagingPlayState == PlayState::Finished) {
184 callOnFinishedListener(context);
185 } else if (mStagingPlayState == PlayState::Running
186 || mStagingPlayState == PlayState::Reversing) {
187 bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
188 if (prevFramePlayState != mStagingPlayState) {
189 transitionToRunning(context);
192 // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
193 // requested from UI thread). It is achieved by modifying mStartTime, such that
194 // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
195 // case of reversing)
196 nsecs_t currentFrameTime = context.frameTimeMs();
197 if (mPlayState == PlayState::Reversing) {
198 // Reverse is not supported for animations with a start delay, so here we
199 // assume no start delay.
200 mStartTime = currentFrameTime - (mDuration - mPlayTime);
202 // Animation should play forward
203 if (mPlayTime == 0) {
204 // If the request is to start from the beginning, include start delay.
205 mStartTime = currentFrameTime + mStartDelay;
207 // If the request is to seek to a non-zero play time, then we skip start
209 mStartTime = currentFrameTime - mPlayTime;
218 void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
219 nsecs_t frameTimeMs = context.frameTimeMs();
220 LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs);
221 if (mStartDelay < 0 || mStartDelay > 50000) {
222 ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay);
224 mStartTime = frameTimeMs + mStartDelay;
225 if (mStartTime < 0) {
226 ALOGW("Ended up with a really weird start time of %" PRId64
227 " with frame time %" PRId64 " and start delay %" PRId64,
228 mStartTime, frameTimeMs, mStartDelay);
229 // Set to 0 so that the animate() basically instantly finishes
233 ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
237 bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
238 if (mPlayState < PlayState::Running) {
241 if (mPlayState == PlayState::Finished) {
242 if (mPendingActionUponFinish == Action::Reset) {
245 } else if (mPendingActionUponFinish == Action::End) {
247 updatePlayTime(mDuration);
249 // Reset pending action.
250 mPendingActionUponFinish = Action ::None;
254 // This should be set before setValue() so animators can query this time when setValue
256 nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
257 bool finished = updatePlayTime(currentPlayTime);
258 if (finished && mPlayState != PlayState::Finished) {
259 mPlayState = PlayState::Finished;
260 callOnFinishedListener(context);
265 bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
266 mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
267 onPlayTimeChanged(mPlayTime);
268 // If BaseRenderNodeAnimator is handling the delay (not typical), then
269 // because the staging properties reflect the final value, we always need
270 // to call setValue even if the animation isn't yet running or is still
271 // being delayed as we need to override the staging value
273 setValue(mTarget, mFromValue);
277 float fraction = 1.0f;
278 if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
279 fraction = mPlayTime / (float) mDuration;
281 fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
283 fraction = mInterpolator->interpolate(fraction);
284 setValue(mTarget, mFromValue + (mDeltaValue * fraction));
286 return playTime >= mDuration;
289 nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
290 return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
293 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
294 if (mPlayState < PlayState::Finished) {
295 mPlayState = PlayState::Finished;
296 callOnFinishedListener(context);
300 void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
301 if (mListener.get()) {
302 context.callOnFinished(this, mListener.get());
306 /************************************************************
307 * RenderPropertyAnimator
308 ************************************************************/
310 struct RenderPropertyAnimator::PropertyAccessors {
311 RenderNode::DirtyPropertyMask dirtyMask;
312 GetFloatProperty getter;
313 SetFloatProperty setter;
316 // Maps RenderProperty enum to accessors
317 const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
318 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
319 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
320 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
321 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
322 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
323 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
324 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
325 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
326 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
327 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
328 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
329 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
332 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
333 : BaseRenderNodeAnimator(finalValue)
334 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
337 void RenderPropertyAnimator::onAttached() {
339 && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
340 setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
344 void RenderPropertyAnimator::onStagingPlayStateChanged() {
345 if (mStagingPlayState == PlayState::Running) {
346 if (mStagingTarget) {
347 (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
349 // In the case of start delay where stagingTarget has been sync'ed over and null'ed
350 // we delay the properties update to push staging.
351 mShouldUpdateStagingProperties = true;
353 } else if (mStagingPlayState == PlayState::Finished) {
354 // We're being canceled, so make sure that whatever values the UI thread
355 // is observing for us is pushed over
356 mShouldSyncPropertyFields = true;
360 void RenderPropertyAnimator::onPushStaging() {
361 if (mShouldUpdateStagingProperties) {
362 (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
363 mShouldUpdateStagingProperties = false;
366 if (mShouldSyncPropertyFields) {
367 mTarget->setPropertyFieldsDirty(dirtyMask());
368 mShouldSyncPropertyFields = false;
372 uint32_t RenderPropertyAnimator::dirtyMask() {
373 return mPropertyAccess->dirtyMask;
376 float RenderPropertyAnimator::getValue(RenderNode* target) const {
377 return (target->properties().*mPropertyAccess->getter)();
380 void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
381 (target->animatorProperties().*mPropertyAccess->setter)(value);
384 /************************************************************
385 * CanvasPropertyPrimitiveAnimator
386 ************************************************************/
388 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
389 CanvasPropertyPrimitive* property, float finalValue)
390 : BaseRenderNodeAnimator(finalValue)
391 , mProperty(property) {
394 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
395 return mProperty->value;
398 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
399 mProperty->value = value;
402 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
403 return RenderNode::DISPLAY_LIST;
406 /************************************************************
407 * CanvasPropertySkPaintAnimator
408 ************************************************************/
410 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
411 CanvasPropertyPaint* property, PaintField field, float finalValue)
412 : BaseRenderNodeAnimator(finalValue)
413 , mProperty(property)
417 float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
420 return mProperty->value.getStrokeWidth();
422 return mProperty->value.getAlpha();
424 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
428 static uint8_t to_uint8(float value) {
429 int c = (int) (value + .5f);
430 return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
433 void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
436 mProperty->value.setStrokeWidth(value);
439 mProperty->value.setAlpha(to_uint8(value));
442 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
445 uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
446 return RenderNode::DISPLAY_LIST;
449 RevealAnimator::RevealAnimator(int centerX, int centerY,
450 float startValue, float finalValue)
451 : BaseRenderNodeAnimator(finalValue)
453 , mCenterY(centerY) {
454 setStartValue(startValue);
457 float RevealAnimator::getValue(RenderNode* target) const {
458 return target->properties().getRevealClip().getRadius();
461 void RevealAnimator::setValue(RenderNode* target, float value) {
462 target->animatorProperties().mutableRevealClip().set(true,
463 mCenterX, mCenterY, value);
466 uint32_t RevealAnimator::dirtyMask() {
467 return RenderNode::GENERIC;
470 } /* namespace uirenderer */
471 } /* namespace android */