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         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 
    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
    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 
    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, &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 
    332 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
    333         : BaseRenderNodeAnimator(finalValue)
    334         , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
    335 }
    336 
    337 void RenderPropertyAnimator::onAttached() {
    338     if (!mHasStartValue
    339             && 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(
    389                 CanvasPropertyPrimitive* property, float finalValue)
    390         : BaseRenderNodeAnimator(finalValue)
    391         , mProperty(property) {
    392 }
    393 
    394 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
    395     return mProperty->value;
    396 }
    397 
    398 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
    399     mProperty->value = value;
    400 }
    401 
    402 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
    403     return RenderNode::DISPLAY_LIST;
    404 }
    405 
    406 /************************************************************
    407  *  CanvasPropertySkPaintAnimator
    408  ************************************************************/
    409 
    410 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
    411                 CanvasPropertyPaint* property, PaintField field, float finalValue)
    412         : BaseRenderNodeAnimator(finalValue)
    413         , mProperty(property)
    414         , mField(field) {
    415 }
    416 
    417 float 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 
    428 static 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 
    433 void 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 
    445 uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
    446     return RenderNode::DISPLAY_LIST;
    447 }
    448 
    449 RevealAnimator::RevealAnimator(int centerX, int centerY,
    450         float startValue, float finalValue)
    451         : BaseRenderNodeAnimator(finalValue)
    452         , mCenterX(centerX)
    453         , mCenterY(centerY) {
    454     setStartValue(startValue);
    455 }
    456 
    457 float RevealAnimator::getValue(RenderNode* target) const {
    458     return target->properties().getRevealClip().getRadius();
    459 }
    460 
    461 void RevealAnimator::setValue(RenderNode* target, float value) {
    462     target->animatorProperties().mutableRevealClip().set(true,
    463             mCenterX, mCenterY, value);
    464 }
    465 
    466 uint32_t RevealAnimator::dirtyMask() {
    467     return RenderNode::GENERIC;
    468 }
    469 
    470 } /* namespace uirenderer */
    471 } /* namespace android */
    472