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