• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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