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