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