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        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
153void 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
218void 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
237bool 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
265bool 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
289nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
290    return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
291}
292
293void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
294    if (mPlayState < PlayState::Finished) {
295        mPlayState = PlayState::Finished;
296        callOnFinishedListener(context);
297    }
298}
299
300void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
301    if (mListener.get()) {
302        context.callOnFinished(this, mListener.get());
303    }
304}
305
306/************************************************************
307 *  RenderPropertyAnimator
308 ************************************************************/
309
310struct RenderPropertyAnimator::PropertyAccessors {
311   RenderNode::DirtyPropertyMask dirtyMask;
312   GetFloatProperty getter;
313   SetFloatProperty setter;
314};
315
316// Maps RenderProperty enum to accessors
317const 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
332RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
333        : BaseRenderNodeAnimator(finalValue)
334        , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
335}
336
337void RenderPropertyAnimator::onAttached() {
338    if (!mHasStartValue
339            && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
340        setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
341    }
342}
343
344void 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
360void 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
372uint32_t RenderPropertyAnimator::dirtyMask() {
373    return mPropertyAccess->dirtyMask;
374}
375
376float RenderPropertyAnimator::getValue(RenderNode* target) const {
377    return (target->properties().*mPropertyAccess->getter)();
378}
379
380void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
381    (target->animatorProperties().*mPropertyAccess->setter)(value);
382}
383
384/************************************************************
385 *  CanvasPropertyPrimitiveAnimator
386 ************************************************************/
387
388CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
389                CanvasPropertyPrimitive* property, float finalValue)
390        : BaseRenderNodeAnimator(finalValue)
391        , mProperty(property) {
392}
393
394float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
395    return mProperty->value;
396}
397
398void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
399    mProperty->value = value;
400}
401
402uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
403    return RenderNode::DISPLAY_LIST;
404}
405
406/************************************************************
407 *  CanvasPropertySkPaintAnimator
408 ************************************************************/
409
410CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
411                CanvasPropertyPaint* property, PaintField field, float finalValue)
412        : BaseRenderNodeAnimator(finalValue)
413        , mProperty(property)
414        , mField(field) {
415}
416
417float 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
428static 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
433void 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
445uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
446    return RenderNode::DISPLAY_LIST;
447}
448
449RevealAnimator::RevealAnimator(int centerX, int centerY,
450        float startValue, float finalValue)
451        : BaseRenderNodeAnimator(finalValue)
452        , mCenterX(centerX)
453        , mCenterY(centerY) {
454    setStartValue(startValue);
455}
456
457float RevealAnimator::getValue(RenderNode* target) const {
458    return target->properties().getRevealClip().getRadius();
459}
460
461void RevealAnimator::setValue(RenderNode* target, float value) {
462    target->animatorProperties().mutableRevealClip().set(true,
463            mCenterX, mCenterY, value);
464}
465
466uint32_t RevealAnimator::dirtyMask() {
467    return RenderNode::GENERIC;
468}
469
470} /* namespace uirenderer */
471} /* namespace android */
472