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