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