Animator.cpp revision 718cd3eb70703c43f29ca37907bbf0e153d8cca0
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
27namespace android {
28namespace uirenderer {
29
30/************************************************************
31 *  BaseRenderNodeAnimator
32 ************************************************************/
33
34BaseRenderNodeAnimator::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
50BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
51}
52
53void 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
59void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
60    checkMutable();
61    mInterpolator.reset(interpolator);
62}
63
64void BaseRenderNodeAnimator::setStartValue(float value) {
65    checkMutable();
66    doSetStartValue(value);
67}
68
69void BaseRenderNodeAnimator::doSetStartValue(float value) {
70    mFromValue = value;
71    mDeltaValue = (mFinalValue - mFromValue);
72    mHasStartValue = true;
73}
74
75void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
76    checkMutable();
77    mDuration = duration;
78}
79
80void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
81    checkMutable();
82    mStartDelay = startDelay;
83}
84
85void BaseRenderNodeAnimator::attach(RenderNode* target) {
86    mStagingTarget = target;
87    onAttached();
88}
89
90void BaseRenderNodeAnimator::start() {
91    mStagingPlayState = PlayState::Running;
92    mStagingRequests.push_back(Request::Start);
93    onStagingPlayStateChanged();
94}
95
96void BaseRenderNodeAnimator::cancel() {
97    mStagingPlayState = PlayState::Finished;
98    mStagingRequests.push_back(Request::Cancel);
99    onStagingPlayStateChanged();
100}
101
102void BaseRenderNodeAnimator::reset() {
103    mStagingPlayState = PlayState::Finished;
104    mStagingRequests.push_back(Request::Reset);
105    onStagingPlayStateChanged();
106}
107
108void BaseRenderNodeAnimator::reverse() {
109    mStagingPlayState = PlayState::Reversing;
110    mStagingRequests.push_back(Request::Reverse);
111    onStagingPlayStateChanged();
112}
113
114void BaseRenderNodeAnimator::end() {
115    mStagingPlayState = PlayState::Finished;
116    mStagingRequests.push_back(Request::End);
117    onStagingPlayStateChanged();
118}
119
120void 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
148void 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
215void 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
234bool 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
253bool 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
277nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
278    return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
279}
280
281void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
282    if (mPlayState < PlayState::Finished) {
283        mPlayState = PlayState::Finished;
284        callOnFinishedListener(context);
285    }
286}
287
288void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
289    if (mListener.get()) {
290        context.callOnFinished(this, mListener.get());
291    }
292}
293
294/************************************************************
295 *  RenderPropertyAnimator
296 ************************************************************/
297
298struct RenderPropertyAnimator::PropertyAccessors {
299   RenderNode::DirtyPropertyMask dirtyMask;
300   GetFloatProperty getter;
301   SetFloatProperty setter;
302};
303
304// Maps RenderProperty enum to accessors
305const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
306    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
307    {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
308    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
309    {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
310    {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
311    {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
312    {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
313    {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
314    {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
315    {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
316    {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
317    {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
318};
319
320RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
321        : BaseRenderNodeAnimator(finalValue)
322        , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
323}
324
325void RenderPropertyAnimator::onAttached() {
326    if (!mHasStartValue
327            && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
328        setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
329    }
330}
331
332void RenderPropertyAnimator::onStagingPlayStateChanged() {
333    if (mStagingPlayState == PlayState::Running) {
334        if (mStagingTarget) {
335            (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
336        } else {
337            // In the case of start delay where stagingTarget has been sync'ed over and null'ed
338            // we delay the properties update to push staging.
339            mShouldUpdateStagingProperties = true;
340        }
341    } else if (mStagingPlayState == PlayState::Finished) {
342        // We're being canceled, so make sure that whatever values the UI thread
343        // is observing for us is pushed over
344        mShouldSyncPropertyFields = true;
345    }
346}
347
348void RenderPropertyAnimator::onPushStaging() {
349    if (mShouldUpdateStagingProperties) {
350        (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
351        mShouldUpdateStagingProperties = false;
352    }
353
354    if (mShouldSyncPropertyFields) {
355        mTarget->setPropertyFieldsDirty(dirtyMask());
356        mShouldSyncPropertyFields = false;
357    }
358}
359
360uint32_t RenderPropertyAnimator::dirtyMask() {
361    return mPropertyAccess->dirtyMask;
362}
363
364float RenderPropertyAnimator::getValue(RenderNode* target) const {
365    return (target->properties().*mPropertyAccess->getter)();
366}
367
368void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
369    (target->animatorProperties().*mPropertyAccess->setter)(value);
370}
371
372/************************************************************
373 *  CanvasPropertyPrimitiveAnimator
374 ************************************************************/
375
376CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
377                CanvasPropertyPrimitive* property, float finalValue)
378        : BaseRenderNodeAnimator(finalValue)
379        , mProperty(property) {
380}
381
382float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
383    return mProperty->value;
384}
385
386void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
387    mProperty->value = value;
388}
389
390uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
391    return RenderNode::DISPLAY_LIST;
392}
393
394/************************************************************
395 *  CanvasPropertySkPaintAnimator
396 ************************************************************/
397
398CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
399                CanvasPropertyPaint* property, PaintField field, float finalValue)
400        : BaseRenderNodeAnimator(finalValue)
401        , mProperty(property)
402        , mField(field) {
403}
404
405float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
406    switch (mField) {
407    case STROKE_WIDTH:
408        return mProperty->value.getStrokeWidth();
409    case ALPHA:
410        return mProperty->value.getAlpha();
411    }
412    LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
413    return -1;
414}
415
416static uint8_t to_uint8(float value) {
417    int c = (int) (value + .5f);
418    return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
419}
420
421void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
422    switch (mField) {
423    case STROKE_WIDTH:
424        mProperty->value.setStrokeWidth(value);
425        return;
426    case ALPHA:
427        mProperty->value.setAlpha(to_uint8(value));
428        return;
429    }
430    LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
431}
432
433uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
434    return RenderNode::DISPLAY_LIST;
435}
436
437RevealAnimator::RevealAnimator(int centerX, int centerY,
438        float startValue, float finalValue)
439        : BaseRenderNodeAnimator(finalValue)
440        , mCenterX(centerX)
441        , mCenterY(centerY) {
442    setStartValue(startValue);
443}
444
445float RevealAnimator::getValue(RenderNode* target) const {
446    return target->properties().getRevealClip().getRadius();
447}
448
449void RevealAnimator::setValue(RenderNode* target, float value) {
450    target->animatorProperties().mutableRevealClip().set(true,
451            mCenterX, mCenterY, value);
452}
453
454uint32_t RevealAnimator::dirtyMask() {
455    return RenderNode::GENERIC;
456}
457
458} /* namespace uirenderer */
459} /* namespace android */
460