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