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 "Animator.h"
22 #include "DamageAccumulator.h"
23 #include "RenderNode.h"
24
25 namespace android {
26 namespace uirenderer {
27
28 using namespace std;
29
detach(sp<BaseRenderNodeAnimator> & animator)30 static void detach(sp<BaseRenderNodeAnimator>& animator) {
31 animator->detach();
32 }
33
AnimatorManager(RenderNode & parent)34 AnimatorManager::AnimatorManager(RenderNode& parent)
35 : mParent(parent), mAnimationHandle(nullptr), mCancelAllAnimators(false) {}
36
~AnimatorManager()37 AnimatorManager::~AnimatorManager() {
38 for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
39 for_each(mAnimators.begin(), mAnimators.end(), detach);
40 }
41
addAnimator(const sp<BaseRenderNodeAnimator> & animator)42 void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
43 RenderNode* stagingTarget = animator->stagingTarget();
44 if (stagingTarget == &mParent) {
45 return;
46 }
47 mNewAnimators.emplace_back(animator.get());
48 // If the animator is already attached to other RenderNode, remove it from that RenderNode's
49 // new animator list. This ensures one animator only ends up in one newAnimatorList during one
50 // frame, even when it's added multiple times to multiple targets.
51 if (stagingTarget) {
52 stagingTarget->removeAnimator(animator);
53 }
54 animator->attach(&mParent);
55 }
56
removeAnimator(const sp<BaseRenderNodeAnimator> & animator)57 void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
58 mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
59 mNewAnimators.end());
60 }
61
setAnimationHandle(AnimationHandle * handle)62 void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
63 LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
64 mAnimationHandle = handle;
65 LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
66 "Lost animation handle on %p (%s) with outstanding animators!", &mParent,
67 mParent.getName());
68 }
69
pushStaging()70 void AnimatorManager::pushStaging() {
71 if (mNewAnimators.size()) {
72 if (CC_UNLIKELY(!mAnimationHandle)) {
73 ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
74 mParent.getName());
75 return;
76 }
77
78 // Only add new animators that are not already in the mAnimators list
79 for (auto& anim : mNewAnimators) {
80 if (anim->target() != &mParent) {
81 mAnimators.push_back(std::move(anim));
82 }
83 }
84 mNewAnimators.clear();
85 }
86
87 if (mCancelAllAnimators) {
88 for (auto& animator : mAnimators) {
89 animator->forceEndNow(mAnimationHandle->context());
90 }
91 mCancelAllAnimators = false;
92 } else {
93 for (auto& animator : mAnimators) {
94 animator->pushStaging(mAnimationHandle->context());
95 }
96 }
97 }
98
onAnimatorTargetChanged(BaseRenderNodeAnimator * animator)99 void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
100 LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
101 mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
102 }
103
104 class AnimateFunctor {
105 public:
AnimateFunctor(TreeInfo & info,AnimationContext & context,uint32_t * outDirtyMask)106 AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
107 : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
108
operator ()(sp<BaseRenderNodeAnimator> & animator)109 bool operator()(sp<BaseRenderNodeAnimator>& animator) {
110 *mDirtyMask |= animator->dirtyMask();
111 bool remove = animator->animate(mContext);
112 if (remove) {
113 animator->detach();
114 } else {
115 if (animator->isRunning()) {
116 mInfo.out.hasAnimations = true;
117 }
118 if (CC_UNLIKELY(!animator->mayRunAsync())) {
119 mInfo.out.requiresUiRedraw = true;
120 }
121 }
122 return remove;
123 }
124
125 private:
126 TreeInfo& mInfo;
127 AnimationContext& mContext;
128 uint32_t* mDirtyMask;
129 };
130
animate(TreeInfo & info)131 uint32_t AnimatorManager::animate(TreeInfo& info) {
132 if (!mAnimators.size()) return 0;
133
134 // TODO: Can we target this better? For now treat it like any other staging
135 // property push and just damage self before and after animators are run
136
137 mParent.damageSelf(info);
138 info.damageAccumulator->popTransform();
139
140 uint32_t dirty = animateCommon(info);
141
142 info.damageAccumulator->pushTransform(&mParent);
143 mParent.damageSelf(info);
144
145 return dirty;
146 }
147
animateNoDamage(TreeInfo & info)148 void AnimatorManager::animateNoDamage(TreeInfo& info) {
149 animateCommon(info);
150 }
151
animateCommon(TreeInfo & info)152 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
153 uint32_t dirtyMask = 0;
154 AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
155 auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
156 mAnimators.erase(newEnd, mAnimators.end());
157 mAnimationHandle->notifyAnimationsRan();
158 mParent.mProperties.updateMatrix();
159 return dirtyMask;
160 }
161
endStagingAnimator(sp<BaseRenderNodeAnimator> & animator)162 static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
163 animator->cancel();
164 if (animator->listener()) {
165 animator->listener()->onAnimationFinished(animator.get());
166 }
167 }
168
endAllStagingAnimators()169 void AnimatorManager::endAllStagingAnimators() {
170 ALOGD("endAllStagingAnimators on %p (%s)", &mParent, mParent.getName());
171 // This works because this state can only happen on the UI thread,
172 // which means we're already on the right thread to invoke listeners
173 for_each(mNewAnimators.begin(), mNewAnimators.end(), endStagingAnimator);
174 mNewAnimators.clear();
175 }
176
177 class EndActiveAnimatorsFunctor {
178 public:
EndActiveAnimatorsFunctor(AnimationContext & context)179 explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
180
operator ()(sp<BaseRenderNodeAnimator> & animator)181 void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
182
183 private:
184 AnimationContext& mContext;
185 };
186
endAllActiveAnimators()187 void AnimatorManager::endAllActiveAnimators() {
188 ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
189 mAnimationHandle);
190 EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
191 for_each(mAnimators.begin(), mAnimators.end(), functor);
192 mAnimators.clear();
193 mAnimationHandle->release();
194 }
195
forceEndAnimators()196 void AnimatorManager::forceEndAnimators() {
197 mCancelAllAnimators = true;
198 }
199
200 } /* namespace uirenderer */
201 } /* namespace android */
202