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 LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(), 53 "Lost animation handle on %p (%s) with outstanding animators!", 54 &mParent, mParent.getName()); 55} 56 57template<typename T> 58static 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 66void 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 79class AnimateFunctor { 80public: 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 102private: 103 TreeInfo& mInfo; 104 AnimationContext& mContext; 105}; 106 107uint32_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 125void AnimatorManager::animateNoDamage(TreeInfo& info) { 126 if (!mAnimators.size()) return; 127 128 animateCommon(info); 129} 130 131uint32_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 140static void endStagingAnimator(BaseRenderNodeAnimator* animator) { 141 animator->end(); 142 if (animator->listener()) { 143 animator->listener()->onAnimationFinished(animator); 144 } 145 animator->decStrong(0); 146} 147 148void 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 156class EndActiveAnimatorsFunctor { 157public: 158 EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {} 159 160 void operator() (BaseRenderNodeAnimator* animator) { 161 animator->forceEndNow(mContext); 162 animator->decStrong(0); 163 } 164 165private: 166 AnimationContext& mContext; 167}; 168 169void 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