2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "AnimatorManager.h"
21 #include "AnimationContext.h"
22 #include "DamageAccumulator.h"
23 #include "RenderNode.h"
26 namespace uirenderer {
30 static void unref(BaseRenderNodeAnimator* animator) {
32 animator->decStrong(nullptr);
35 AnimatorManager::AnimatorManager(RenderNode& parent)
37 , mAnimationHandle(nullptr) {
40 AnimatorManager::~AnimatorManager() {
41 for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
42 for_each(mAnimators.begin(), mAnimators.end(), unref);
45 void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
46 animator->incStrong(nullptr);
47 animator->attach(&mParent);
48 mNewAnimators.push_back(animator.get());
51 void 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());
60 static 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++) {
68 void 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);
76 for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
77 (*it)->pushStaging(mAnimationHandle->context());
81 class AnimateFunctor {
83 AnimateFunctor(TreeInfo& info, AnimationContext& context)
84 : dirtyMask(0), mInfo(info), mContext(context) {}
86 bool operator() (BaseRenderNodeAnimator* animator) {
87 dirtyMask |= animator->dirtyMask();
88 bool remove = animator->animate(mContext);
90 animator->decStrong(nullptr);
92 if (animator->isRunning()) {
93 mInfo.out.hasAnimations = true;
95 if (CC_UNLIKELY(!animator->mayRunAsync())) {
96 mInfo.out.requiresUiRedraw = true;
106 AnimationContext& mContext;
109 uint32_t AnimatorManager::animate(TreeInfo& info) {
110 if (!mAnimators.size()) return 0;
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
115 mParent.damageSelf(info);
116 info.damageAccumulator->popTransform();
118 uint32_t dirty = animateCommon(info);
120 mParent.mProperties.updateMatrix();
121 info.damageAccumulator->pushTransform(&mParent);
122 mParent.damageSelf(info);
127 void AnimatorManager::animateNoDamage(TreeInfo& info) {
128 if (!mAnimators.size()) return;
133 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
134 AnimateFunctor functor(info, mAnimationHandle->context());
135 std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
136 newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
137 mAnimators.erase(newEnd, mAnimators.end());
138 mAnimationHandle->notifyAnimationsRan();
139 return functor.dirtyMask;
142 static void endStagingAnimator(BaseRenderNodeAnimator* animator) {
144 if (animator->listener()) {
145 animator->listener()->onAnimationFinished(animator);
147 animator->decStrong(nullptr);
150 void 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();
158 class EndActiveAnimatorsFunctor {
160 EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
162 void operator() (BaseRenderNodeAnimator* animator) {
163 animator->forceEndNow(mContext);
164 animator->decStrong(nullptr);
168 AnimationContext& mContext;
171 void 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);
177 mAnimationHandle->release();
180 } /* namespace uirenderer */
181 } /* namespace android */