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