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