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 #include "AnimatorManager.h"
     17 
     18 #include <algorithm>
     19 
     20 #include "AnimationContext.h"
     21 #include "Animator.h"
     22 #include "DamageAccumulator.h"
     23 #include "RenderNode.h"
     24 
     25 namespace android {
     26 namespace uirenderer {
     27 
     28 using namespace std;
     29 
     30 static void detach(sp<BaseRenderNodeAnimator>& animator) {
     31     animator->detach();
     32 }
     33 
     34 AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
     35 
     36 AnimatorManager::~AnimatorManager() {
     37     for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
     38     for_each(mAnimators.begin(), mAnimators.end(), detach);
     39 }
     40 
     41 void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
     42     RenderNode* stagingTarget = animator->stagingTarget();
     43     if (stagingTarget == &mParent) {
     44         return;
     45     }
     46     mNewAnimators.emplace_back(animator.get());
     47     // If the animator is already attached to other RenderNode, remove it from that RenderNode's
     48     // new animator list. This ensures one animator only ends up in one newAnimatorList during one
     49     // frame, even when it's added multiple times to multiple targets.
     50     if (stagingTarget) {
     51         stagingTarget->removeAnimator(animator);
     52     }
     53     animator->attach(&mParent);
     54 }
     55 
     56 void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
     57     mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
     58                         mNewAnimators.end());
     59 }
     60 
     61 void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
     62     LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
     63     mAnimationHandle = handle;
     64     LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
     65                         "Lost animation handle on %p (%s) with outstanding animators!", &mParent,
     66                         mParent.getName());
     67 }
     68 
     69 void AnimatorManager::pushStaging() {
     70     if (mNewAnimators.size()) {
     71         if (CC_UNLIKELY(!mAnimationHandle)) {
     72             ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
     73                   mParent.getName());
     74             return;
     75         }
     76 
     77         // Only add new animators that are not already in the mAnimators list
     78         for (auto& anim : mNewAnimators) {
     79             if (anim->target() != &mParent) {
     80                 mAnimators.push_back(std::move(anim));
     81             }
     82         }
     83         mNewAnimators.clear();
     84     }
     85     for (auto& animator : mAnimators) {
     86         animator->pushStaging(mAnimationHandle->context());
     87     }
     88 }
     89 
     90 void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
     91     LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
     92     mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
     93 }
     94 
     95 class AnimateFunctor {
     96 public:
     97     AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
     98             : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
     99 
    100     bool operator()(sp<BaseRenderNodeAnimator>& animator) {
    101         *mDirtyMask |= animator->dirtyMask();
    102         bool remove = animator->animate(mContext);
    103         if (remove) {
    104             animator->detach();
    105         } else {
    106             if (animator->isRunning()) {
    107                 mInfo.out.hasAnimations = true;
    108             }
    109             if (CC_UNLIKELY(!animator->mayRunAsync())) {
    110                 mInfo.out.requiresUiRedraw = true;
    111             }
    112         }
    113         return remove;
    114     }
    115 
    116 private:
    117     TreeInfo& mInfo;
    118     AnimationContext& mContext;
    119     uint32_t* mDirtyMask;
    120 };
    121 
    122 uint32_t AnimatorManager::animate(TreeInfo& info) {
    123     if (!mAnimators.size()) return 0;
    124 
    125     // TODO: Can we target this better? For now treat it like any other staging
    126     // property push and just damage self before and after animators are run
    127 
    128     mParent.damageSelf(info);
    129     info.damageAccumulator->popTransform();
    130 
    131     uint32_t dirty = animateCommon(info);
    132 
    133     info.damageAccumulator->pushTransform(&mParent);
    134     mParent.damageSelf(info);
    135 
    136     return dirty;
    137 }
    138 
    139 void AnimatorManager::animateNoDamage(TreeInfo& info) {
    140     animateCommon(info);
    141 }
    142 
    143 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
    144     uint32_t dirtyMask = 0;
    145     AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
    146     auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
    147     mAnimators.erase(newEnd, mAnimators.end());
    148     mAnimationHandle->notifyAnimationsRan();
    149     mParent.mProperties.updateMatrix();
    150     return dirtyMask;
    151 }
    152 
    153 static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
    154     animator->cancel();
    155     if (animator->listener()) {
    156         animator->listener()->onAnimationFinished(animator.get());
    157     }
    158 }
    159 
    160 void AnimatorManager::endAllStagingAnimators() {
    161     ALOGD("endAllStagingAnimators on %p (%s)", &mParent, mParent.getName());
    162     // This works because this state can only happen on the UI thread,
    163     // which means we're already on the right thread to invoke listeners
    164     for_each(mNewAnimators.begin(), mNewAnimators.end(), endStagingAnimator);
    165     mNewAnimators.clear();
    166 }
    167 
    168 class EndActiveAnimatorsFunctor {
    169 public:
    170     explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
    171 
    172     void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
    173 
    174 private:
    175     AnimationContext& mContext;
    176 };
    177 
    178 void AnimatorManager::endAllActiveAnimators() {
    179     ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
    180           mAnimationHandle);
    181     EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
    182     for_each(mAnimators.begin(), mAnimators.end(), functor);
    183     mAnimators.clear();
    184     mAnimationHandle->release();
    185 }
    186 
    187 } /* namespace uirenderer */
    188 } /* namespace android */
    189