• 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 }
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         mPendingActionUponFinish = Action::None;
127         break;
128     case Request::Reverse:
129         mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
130                         mPlayTime : 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 (!mHasStartValue) {
164         doSetStartValue(getValue(mTarget));
165     }
166 
167     if (!mStagingRequests.empty()) {
168         // No interpolator was set, use the default
169         if (mPlayState == PlayState::NotStarted && !mInterpolator) {
170             mInterpolator.reset(Interpolator::createDefaultInterpolator());
171         }
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;
176 
177         // Resolve staging requests one by one.
178         for (Request request : mStagingRequests) {
179             resolveStagingRequest(request);
180         }
181         mStagingRequests.clear();
182 
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);
190             }
191             if (changed) {
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);
201                 } else {
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;
206                     } else {
207                         // If the request is to seek to a non-zero play time, then we skip start
208                         // delay.
209                         mStartTime = currentFrameTime - mPlayTime;
210                     }
211                 }
212             }
213         }
214     }
215     onPushStaging();
216 }
217 
transitionToRunning(AnimationContext & context)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);
223     }
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
230         mStartTime = 0;
231     }
232     if (mDuration < 0) {
233         ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
234     }
235 }
236 
animate(AnimationContext & context)237 bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
238     if (mPlayState < PlayState::Running) {
239         return false;
240     }
241     if (mPlayState == PlayState::Finished) {
242         if (mPendingActionUponFinish == Action::Reset) {
243             // Skip to start.
244             updatePlayTime(0);
245         } else if (mPendingActionUponFinish == Action::End) {
246             // Skip to end.
247             updatePlayTime(mDuration);
248         }
249         // Reset pending action.
250         mPendingActionUponFinish = Action ::None;
251         return true;
252     }
253 
254     // This should be set before setValue() so animators can query this time when setValue
255     // is called.
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);
261     }
262     return finished;
263 }
264 
updatePlayTime(nsecs_t playTime)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
272     if (playTime < 0) {
273         setValue(mTarget, mFromValue);
274         return false;
275     }
276 
277     float fraction = 1.0f;
278     if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
279         fraction = mPlayTime / (float) mDuration;
280     }
281     fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
282 
283     fraction = mInterpolator->interpolate(fraction);
284     setValue(mTarget, mFromValue + (mDeltaValue * fraction));
285 
286     return playTime >= mDuration;
287 }
288 
getRemainingPlayTime()289 nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
290     return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
291 }
292 
forceEndNow(AnimationContext & context)293 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
294     if (mPlayState < PlayState::Finished) {
295         mPlayState = PlayState::Finished;
296         callOnFinishedListener(context);
297     }
298 }
299 
callOnFinishedListener(AnimationContext & context)300 void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
301     if (mListener.get()) {
302         context.callOnFinished(this, mListener.get());
303     }
304 }
305 
306 /************************************************************
307  *  RenderPropertyAnimator
308  ************************************************************/
309 
310 struct RenderPropertyAnimator::PropertyAccessors {
311    RenderNode::DirtyPropertyMask dirtyMask;
312    GetFloatProperty getter;
313    SetFloatProperty setter;
314 };
315 
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_Z, &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 },
330 };
331 
RenderPropertyAnimator(RenderProperty property,float finalValue)332 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
333         : BaseRenderNodeAnimator(finalValue)
334         , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
335 }
336 
onAttached()337 void RenderPropertyAnimator::onAttached() {
338     if (!mHasStartValue
339             && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
340         setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
341     }
342 }
343 
onStagingPlayStateChanged()344 void RenderPropertyAnimator::onStagingPlayStateChanged() {
345     if (mStagingPlayState == PlayState::Running) {
346         if (mStagingTarget) {
347             (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
348         } else {
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;
352         }
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;
357     }
358 }
359 
onPushStaging()360 void RenderPropertyAnimator::onPushStaging() {
361     if (mShouldUpdateStagingProperties) {
362         (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
363         mShouldUpdateStagingProperties = false;
364     }
365 
366     if (mShouldSyncPropertyFields) {
367         mTarget->setPropertyFieldsDirty(dirtyMask());
368         mShouldSyncPropertyFields = false;
369     }
370 }
371 
dirtyMask()372 uint32_t RenderPropertyAnimator::dirtyMask() {
373     return mPropertyAccess->dirtyMask;
374 }
375 
getValue(RenderNode * target) const376 float RenderPropertyAnimator::getValue(RenderNode* target) const {
377     return (target->properties().*mPropertyAccess->getter)();
378 }
379 
setValue(RenderNode * target,float value)380 void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
381     (target->animatorProperties().*mPropertyAccess->setter)(value);
382 }
383 
384 /************************************************************
385  *  CanvasPropertyPrimitiveAnimator
386  ************************************************************/
387 
CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive * property,float finalValue)388 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
389                 CanvasPropertyPrimitive* property, float finalValue)
390         : BaseRenderNodeAnimator(finalValue)
391         , mProperty(property) {
392 }
393 
getValue(RenderNode * target) const394 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
395     return mProperty->value;
396 }
397 
setValue(RenderNode * target,float value)398 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
399     mProperty->value = value;
400 }
401 
dirtyMask()402 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
403     return RenderNode::DISPLAY_LIST;
404 }
405 
406 /************************************************************
407  *  CanvasPropertySkPaintAnimator
408  ************************************************************/
409 
CanvasPropertyPaintAnimator(CanvasPropertyPaint * property,PaintField field,float finalValue)410 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
411                 CanvasPropertyPaint* property, PaintField field, float finalValue)
412         : BaseRenderNodeAnimator(finalValue)
413         , mProperty(property)
414         , mField(field) {
415 }
416 
getValue(RenderNode * target) const417 float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
418     switch (mField) {
419     case STROKE_WIDTH:
420         return mProperty->value.getStrokeWidth();
421     case ALPHA:
422         return mProperty->value.getAlpha();
423     }
424     LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
425     return -1;
426 }
427 
to_uint8(float value)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 );
431 }
432 
setValue(RenderNode * target,float value)433 void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
434     switch (mField) {
435     case STROKE_WIDTH:
436         mProperty->value.setStrokeWidth(value);
437         return;
438     case ALPHA:
439         mProperty->value.setAlpha(to_uint8(value));
440         return;
441     }
442     LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
443 }
444 
dirtyMask()445 uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
446     return RenderNode::DISPLAY_LIST;
447 }
448 
RevealAnimator(int centerX,int centerY,float startValue,float finalValue)449 RevealAnimator::RevealAnimator(int centerX, int centerY,
450         float startValue, float finalValue)
451         : BaseRenderNodeAnimator(finalValue)
452         , mCenterX(centerX)
453         , mCenterY(centerY) {
454     setStartValue(startValue);
455 }
456 
getValue(RenderNode * target) const457 float RevealAnimator::getValue(RenderNode* target) const {
458     return target->properties().getRevealClip().getRadius();
459 }
460 
setValue(RenderNode * target,float value)461 void RevealAnimator::setValue(RenderNode* target, float value) {
462     target->animatorProperties().mutableRevealClip().set(true,
463             mCenterX, mCenterY, value);
464 }
465 
dirtyMask()466 uint32_t RevealAnimator::dirtyMask() {
467     return RenderNode::GENERIC;
468 }
469 
470 } /* namespace uirenderer */
471 } /* namespace android */
472