1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include "Animator.h"
18
19 #include <inttypes.h>
20 #include <set>
21
22 #include "AnimationContext.h"
23 #include "Interpolator.h"
24 #include "RenderNode.h"
25 #include "RenderProperties.h"
26
27 namespace android {
28 namespace uirenderer {
29
30 /************************************************************
31 * BaseRenderNodeAnimator
32 ************************************************************/
33
BaseRenderNodeAnimator(float finalValue)34 BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
35 : mTarget(nullptr)
36 , mStagingTarget(nullptr)
37 , mFinalValue(finalValue)
38 , mDeltaValue(0)
39 , mFromValue(0)
40 , mStagingPlayState(PlayState::NotStarted)
41 , mPlayState(PlayState::NotStarted)
42 , mHasStartValue(false)
43 , mStartTime(0)
44 , mDuration(300)
45 , mStartDelay(0)
46 , mMayRunAsync(true)
47 , mPlayTime(0) {}
48
~BaseRenderNodeAnimator()49 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {}
50
checkMutable()51 void BaseRenderNodeAnimator::checkMutable() {
52 // Should be impossible to hit as the Java-side also has guards for this
53 LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
54 "Animator has already been started!");
55 }
56
setInterpolator(Interpolator * interpolator)57 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
58 checkMutable();
59 mInterpolator.reset(interpolator);
60 }
61
setStartValue(float value)62 void BaseRenderNodeAnimator::setStartValue(float value) {
63 checkMutable();
64 doSetStartValue(value);
65 }
66
doSetStartValue(float value)67 void BaseRenderNodeAnimator::doSetStartValue(float value) {
68 mFromValue = value;
69 mDeltaValue = (mFinalValue - mFromValue);
70 mHasStartValue = true;
71 }
72
setDuration(nsecs_t duration)73 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
74 checkMutable();
75 mDuration = duration;
76 }
77
setStartDelay(nsecs_t startDelay)78 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
79 checkMutable();
80 mStartDelay = startDelay;
81 }
82
attach(RenderNode * target)83 void BaseRenderNodeAnimator::attach(RenderNode* target) {
84 mStagingTarget = target;
85 onAttached();
86 }
87
start()88 void BaseRenderNodeAnimator::start() {
89 mStagingPlayState = PlayState::Running;
90 mStagingRequests.push_back(Request::Start);
91 onStagingPlayStateChanged();
92 }
93
cancel()94 void BaseRenderNodeAnimator::cancel() {
95 mStagingPlayState = PlayState::Finished;
96 mStagingRequests.push_back(Request::Cancel);
97 onStagingPlayStateChanged();
98 }
99
reset()100 void BaseRenderNodeAnimator::reset() {
101 mStagingPlayState = PlayState::Finished;
102 mStagingRequests.push_back(Request::Reset);
103 onStagingPlayStateChanged();
104 }
105
reverse()106 void BaseRenderNodeAnimator::reverse() {
107 mStagingPlayState = PlayState::Reversing;
108 mStagingRequests.push_back(Request::Reverse);
109 onStagingPlayStateChanged();
110 }
111
end()112 void BaseRenderNodeAnimator::end() {
113 mStagingPlayState = PlayState::Finished;
114 mStagingRequests.push_back(Request::End);
115 onStagingPlayStateChanged();
116 }
117
resolveStagingRequest(Request request)118 void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
119 switch (request) {
120 case Request::Start:
121 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
122 ? mPlayTime
123 : 0;
124 mPlayState = PlayState::Running;
125 mPendingActionUponFinish = Action::None;
126 break;
127 case Request::Reverse:
128 mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
129 ? mPlayTime
130 : mDuration;
131 mPlayState = PlayState::Reversing;
132 mPendingActionUponFinish = Action::None;
133 break;
134 case Request::Reset:
135 mPlayTime = 0;
136 mPlayState = PlayState::Finished;
137 mPendingActionUponFinish = Action::Reset;
138 break;
139 case Request::Cancel:
140 mPlayState = PlayState::Finished;
141 mPendingActionUponFinish = Action::None;
142 break;
143 case Request::End:
144 mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
145 mPlayState = PlayState::Finished;
146 mPendingActionUponFinish = Action::End;
147 break;
148 default:
149 LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
150 };
151 }
152
pushStaging(AnimationContext & context)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);
160 }
161 }
162
163 if (!mStagingRequests.empty()) {
164 // No interpolator was set, use the default
165 if (mPlayState == PlayState::NotStarted && !mInterpolator) {
166 mInterpolator.reset(Interpolator::createDefaultInterpolator());
167 }
168 // Keep track of the play state and play time before they are changed when
169 // staging requests are resolved.
170 nsecs_t currentPlayTime = mPlayTime;
171 PlayState prevFramePlayState = mPlayState;
172
173 // Resolve staging requests one by one.
174 for (Request request : mStagingRequests) {
175 resolveStagingRequest(request);
176 }
177 mStagingRequests.clear();
178
179 if (mStagingPlayState == PlayState::Finished) {
180 callOnFinishedListener(context);
181 } else if (mStagingPlayState == PlayState::Running ||
182 mStagingPlayState == PlayState::Reversing) {
183 bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
184 if (prevFramePlayState != mStagingPlayState) {
185 transitionToRunning(context);
186 }
187 if (changed) {
188 // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
189 // requested from UI thread). It is achieved by modifying mStartTime, such that
190 // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
191 // case of reversing)
192 nsecs_t currentFrameTime = context.frameTimeMs();
193 if (mPlayState == PlayState::Reversing) {
194 // Reverse is not supported for animations with a start delay, so here we
195 // assume no start delay.
196 mStartTime = currentFrameTime - (mDuration - mPlayTime);
197 } else {
198 // Animation should play forward
199 if (mPlayTime == 0) {
200 // If the request is to start from the beginning, include start delay.
201 mStartTime = currentFrameTime + mStartDelay;
202 } else {
203 // If the request is to seek to a non-zero play time, then we skip start
204 // delay.
205 mStartTime = currentFrameTime - mPlayTime;
206 }
207 }
208 }
209 }
210 }
211 onPushStaging();
212 }
213
transitionToRunning(AnimationContext & context)214 void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
215 nsecs_t frameTimeMs = context.frameTimeMs();
216 LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs);
217 if (mStartDelay < 0 || mStartDelay > 50000) {
218 ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay);
219 }
220 mStartTime = frameTimeMs + mStartDelay;
221 if (mStartTime < 0) {
222 ALOGW("Ended up with a really weird start time of %" PRId64 " with frame time %" PRId64
223 " and start delay %" PRId64,
224 mStartTime, frameTimeMs, mStartDelay);
225 // Set to 0 so that the animate() basically instantly finishes
226 mStartTime = 0;
227 }
228 if (mDuration < 0) {
229 ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
230 }
231 }
232
animate(AnimationContext & context)233 bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
234 if (mPlayState < PlayState::Running) {
235 return false;
236 }
237 if (mPlayState == PlayState::Finished) {
238 if (mPendingActionUponFinish == Action::Reset) {
239 // Skip to start.
240 updatePlayTime(0);
241 } else if (mPendingActionUponFinish == Action::End) {
242 // Skip to end.
243 updatePlayTime(mDuration);
244 }
245 // Reset pending action.
246 mPendingActionUponFinish = Action::None;
247 return true;
248 }
249
250 // This should be set before setValue() so animators can query this time when setValue
251 // is called.
252 nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
253 bool finished = updatePlayTime(currentPlayTime);
254 if (finished && mPlayState != PlayState::Finished) {
255 mPlayState = PlayState::Finished;
256 callOnFinishedListener(context);
257 }
258 return finished;
259 }
260
updatePlayTime(nsecs_t playTime)261 bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
262 mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
263 onPlayTimeChanged(mPlayTime);
264 // If BaseRenderNodeAnimator is handling the delay (not typical), then
265 // because the staging properties reflect the final value, we always need
266 // to call setValue even if the animation isn't yet running or is still
267 // being delayed as we need to override the staging value
268 if (playTime < 0) {
269 return false;
270 }
271 if (!this->mHasStartValue) {
272 doSetStartValue(getValue(mTarget));
273 }
274
275 float fraction = 1.0f;
276 if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
277 fraction = mPlayTime / (float)mDuration;
278 }
279 fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
280
281 fraction = mInterpolator->interpolate(fraction);
282 setValue(mTarget, mFromValue + (mDeltaValue * fraction));
283
284 return playTime >= mDuration;
285 }
286
getRemainingPlayTime()287 nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
288 return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
289 }
290
forceEndNow(AnimationContext & context)291 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
292 if (mPlayState < PlayState::Finished) {
293 mPlayState = PlayState::Finished;
294 callOnFinishedListener(context);
295 }
296 }
297
callOnFinishedListener(AnimationContext & context)298 void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
299 if (mListener.get()) {
300 context.callOnFinished(this, mListener.get());
301 }
302 }
303
304 /************************************************************
305 * RenderPropertyAnimator
306 ************************************************************/
307
308 struct RenderPropertyAnimator::PropertyAccessors {
309 RenderNode::DirtyPropertyMask dirtyMask;
310 GetFloatProperty getter;
311 SetFloatProperty setter;
312 };
313
314 // Maps RenderProperty enum to accessors
315 const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
316 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX,
317 &RenderProperties::setTranslationX},
318 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY,
319 &RenderProperties::setTranslationY},
320 {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ,
321 &RenderProperties::setTranslationZ},
322 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX},
323 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY},
324 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation},
325 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX},
326 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY},
327 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX},
328 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY},
329 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ},
330 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha},
331 };
332
RenderPropertyAnimator(RenderProperty property,float finalValue)333 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
334 : BaseRenderNodeAnimator(finalValue), mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {}
335
onAttached()336 void RenderPropertyAnimator::onAttached() {
337 if (!mHasStartValue && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
338 setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
339 }
340 }
341
onStagingPlayStateChanged()342 void RenderPropertyAnimator::onStagingPlayStateChanged() {
343 if (mStagingPlayState == PlayState::Running) {
344 if (mStagingTarget) {
345 (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
346 } else {
347 // In the case of start delay where stagingTarget has been sync'ed over and null'ed
348 // we delay the properties update to push staging.
349 mShouldUpdateStagingProperties = true;
350 }
351 } else if (mStagingPlayState == PlayState::Finished) {
352 // We're being canceled, so make sure that whatever values the UI thread
353 // is observing for us is pushed over
354 mShouldSyncPropertyFields = true;
355 }
356 }
357
onPushStaging()358 void RenderPropertyAnimator::onPushStaging() {
359 if (mShouldUpdateStagingProperties) {
360 (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
361 mShouldUpdateStagingProperties = false;
362 }
363
364 if (mShouldSyncPropertyFields) {
365 mTarget->setPropertyFieldsDirty(dirtyMask());
366 mShouldSyncPropertyFields = false;
367 }
368 }
369
dirtyMask()370 uint32_t RenderPropertyAnimator::dirtyMask() {
371 return mPropertyAccess->dirtyMask;
372 }
373
getValue(RenderNode * target) const374 float RenderPropertyAnimator::getValue(RenderNode* target) const {
375 return (target->properties().*mPropertyAccess->getter)();
376 }
377
setValue(RenderNode * target,float value)378 void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
379 (target->animatorProperties().*mPropertyAccess->setter)(value);
380 }
381
382 /************************************************************
383 * CanvasPropertyPrimitiveAnimator
384 ************************************************************/
385
CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive * property,float finalValue)386 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
387 float finalValue)
388 : BaseRenderNodeAnimator(finalValue), mProperty(property) {}
389
getValue(RenderNode * target) const390 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
391 return mProperty->value;
392 }
393
setValue(RenderNode * target,float value)394 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
395 mProperty->value = value;
396 }
397
dirtyMask()398 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
399 return RenderNode::DISPLAY_LIST;
400 }
401
402 /************************************************************
403 * CanvasPropertySkPaintAnimator
404 ************************************************************/
405
CanvasPropertyPaintAnimator(CanvasPropertyPaint * property,PaintField field,float finalValue)406 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
407 PaintField field, float finalValue)
408 : BaseRenderNodeAnimator(finalValue), mProperty(property), mField(field) {}
409
getValue(RenderNode * target) const410 float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
411 switch (mField) {
412 case STROKE_WIDTH:
413 return mProperty->value.getStrokeWidth();
414 case ALPHA:
415 return mProperty->value.getAlpha();
416 }
417 LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
418 return -1;
419 }
420
to_uint8(float value)421 static uint8_t to_uint8(float value) {
422 int c = (int)(value + .5f);
423 return static_cast<uint8_t>(c < 0 ? 0 : c > 255 ? 255 : c);
424 }
425
setValue(RenderNode * target,float value)426 void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
427 switch (mField) {
428 case STROKE_WIDTH:
429 mProperty->value.setStrokeWidth(value);
430 return;
431 case ALPHA:
432 mProperty->value.setAlpha(to_uint8(value));
433 return;
434 }
435 LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
436 }
437
dirtyMask()438 uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
439 return RenderNode::DISPLAY_LIST;
440 }
441
RevealAnimator(int centerX,int centerY,float startValue,float finalValue)442 RevealAnimator::RevealAnimator(int centerX, int centerY, float startValue, float finalValue)
443 : BaseRenderNodeAnimator(finalValue), mCenterX(centerX), mCenterY(centerY) {
444 setStartValue(startValue);
445 }
446
getValue(RenderNode * target) const447 float RevealAnimator::getValue(RenderNode* target) const {
448 return target->properties().getRevealClip().getRadius();
449 }
450
setValue(RenderNode * target,float value)451 void RevealAnimator::setValue(RenderNode* target, float value) {
452 target->animatorProperties().mutableRevealClip().set(true, mCenterX, mCenterY, value);
453 }
454
dirtyMask()455 uint32_t RevealAnimator::dirtyMask() {
456 return RenderNode::GENERIC;
457 }
458
459 } /* namespace uirenderer */
460 } /* namespace android */
461