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