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 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {}
     50 
     51 void BaseRenderNodeAnimator::checkMutable() {
     52     // Should be impossible to hit as the Java-side also has guards for this
     53     LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
     54                         "Animator has already been started!");
     55 }
     56 
     57 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
     58     checkMutable();
     59     mInterpolator.reset(interpolator);
     60 }
     61 
     62 void BaseRenderNodeAnimator::setStartValue(float value) {
     63     checkMutable();
     64     doSetStartValue(value);
     65 }
     66 
     67 void BaseRenderNodeAnimator::doSetStartValue(float value) {
     68     mFromValue = value;
     69     mDeltaValue = (mFinalValue - mFromValue);
     70     mHasStartValue = true;
     71 }
     72 
     73 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
     74     checkMutable();
     75     mDuration = duration;
     76 }
     77 
     78 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
     79     checkMutable();
     80     mStartDelay = startDelay;
     81 }
     82 
     83 void BaseRenderNodeAnimator::attach(RenderNode* target) {
     84     mStagingTarget = target;
     85     onAttached();
     86 }
     87 
     88 void BaseRenderNodeAnimator::start() {
     89     mStagingPlayState = PlayState::Running;
     90     mStagingRequests.push_back(Request::Start);
     91     onStagingPlayStateChanged();
     92 }
     93 
     94 void BaseRenderNodeAnimator::cancel() {
     95     mStagingPlayState = PlayState::Finished;
     96     mStagingRequests.push_back(Request::Cancel);
     97     onStagingPlayStateChanged();
     98 }
     99 
    100 void BaseRenderNodeAnimator::reset() {
    101     mStagingPlayState = PlayState::Finished;
    102     mStagingRequests.push_back(Request::Reset);
    103     onStagingPlayStateChanged();
    104 }
    105 
    106 void BaseRenderNodeAnimator::reverse() {
    107     mStagingPlayState = PlayState::Reversing;
    108     mStagingRequests.push_back(Request::Reverse);
    109     onStagingPlayStateChanged();
    110 }
    111 
    112 void BaseRenderNodeAnimator::end() {
    113     mStagingPlayState = PlayState::Finished;
    114     mStagingRequests.push_back(Request::End);
    115     onStagingPlayStateChanged();
    116 }
    117 
    118 void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
    119     switch (request) {
    120         case Request::Start:
    121             mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
    122                                 ? mPlayTime
    123                                 : 0;
    124             mPlayState = PlayState::Running;
    125             mPendingActionUponFinish = Action::None;
    126             break;
    127         case Request::Reverse:
    128             mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
    129                                 ? mPlayTime
    130                                 : 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 
    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 
    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 " with frame time %" PRId64
    227               " 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 
    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 
    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 
    289 nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
    290     return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
    291 }
    292 
    293 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
    294     if (mPlayState < PlayState::Finished) {
    295         mPlayState = PlayState::Finished;
    296         callOnFinishedListener(context);
    297     }
    298 }
    299 
    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,
    319          &RenderProperties::setTranslationX},
    320         {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY,
    321          &RenderProperties::setTranslationY},
    322         {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ,
    323          &RenderProperties::setTranslationZ},
    324         {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX},
    325         {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY},
    326         {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation},
    327         {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX},
    328         {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY},
    329         {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX},
    330         {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY},
    331         {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ},
    332         {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha},
    333 };
    334 
    335 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
    336         : BaseRenderNodeAnimator(finalValue), mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {}
    337 
    338 void RenderPropertyAnimator::onAttached() {
    339     if (!mHasStartValue && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
    340         setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
    341     }
    342 }
    343 
    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 
    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 
    372 uint32_t RenderPropertyAnimator::dirtyMask() {
    373     return mPropertyAccess->dirtyMask;
    374 }
    375 
    376 float RenderPropertyAnimator::getValue(RenderNode* target) const {
    377     return (target->properties().*mPropertyAccess->getter)();
    378 }
    379 
    380 void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
    381     (target->animatorProperties().*mPropertyAccess->setter)(value);
    382 }
    383 
    384 /************************************************************
    385  *  CanvasPropertyPrimitiveAnimator
    386  ************************************************************/
    387 
    388 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
    389                                                                  float finalValue)
    390         : BaseRenderNodeAnimator(finalValue), mProperty(property) {}
    391 
    392 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
    393     return mProperty->value;
    394 }
    395 
    396 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
    397     mProperty->value = value;
    398 }
    399 
    400 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
    401     return RenderNode::DISPLAY_LIST;
    402 }
    403 
    404 /************************************************************
    405  *  CanvasPropertySkPaintAnimator
    406  ************************************************************/
    407 
    408 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
    409                                                          PaintField field, float finalValue)
    410         : BaseRenderNodeAnimator(finalValue), mProperty(property), mField(field) {}
    411 
    412 float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
    413     switch (mField) {
    414         case STROKE_WIDTH:
    415             return mProperty->value.getStrokeWidth();
    416         case ALPHA:
    417             return mProperty->value.getAlpha();
    418     }
    419     LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
    420     return -1;
    421 }
    422 
    423 static uint8_t to_uint8(float value) {
    424     int c = (int)(value + .5f);
    425     return static_cast<uint8_t>(c < 0 ? 0 : c > 255 ? 255 : c);
    426 }
    427 
    428 void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
    429     switch (mField) {
    430         case STROKE_WIDTH:
    431             mProperty->value.setStrokeWidth(value);
    432             return;
    433         case ALPHA:
    434             mProperty->value.setAlpha(to_uint8(value));
    435             return;
    436     }
    437     LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
    438 }
    439 
    440 uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
    441     return RenderNode::DISPLAY_LIST;
    442 }
    443 
    444 RevealAnimator::RevealAnimator(int centerX, int centerY, float startValue, float finalValue)
    445         : BaseRenderNodeAnimator(finalValue), mCenterX(centerX), mCenterY(centerY) {
    446     setStartValue(startValue);
    447 }
    448 
    449 float RevealAnimator::getValue(RenderNode* target) const {
    450     return target->properties().getRevealClip().getRadius();
    451 }
    452 
    453 void RevealAnimator::setValue(RenderNode* target, float value) {
    454     target->animatorProperties().mutableRevealClip().set(true, mCenterX, mCenterY, value);
    455 }
    456 
    457 uint32_t RevealAnimator::dirtyMask() {
    458     return RenderNode::GENERIC;
    459 }
    460 
    461 } /* namespace uirenderer */
    462 } /* namespace android */
    463