xref: /aosp_15_r20/frameworks/base/libs/hwui/AnimatorManager.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker #include "AnimatorManager.h"
17*d57664e9SAndroid Build Coastguard Worker 
18*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
19*d57664e9SAndroid Build Coastguard Worker 
20*d57664e9SAndroid Build Coastguard Worker #include "AnimationContext.h"
21*d57664e9SAndroid Build Coastguard Worker #include "Animator.h"
22*d57664e9SAndroid Build Coastguard Worker #include "DamageAccumulator.h"
23*d57664e9SAndroid Build Coastguard Worker #include "RenderNode.h"
24*d57664e9SAndroid Build Coastguard Worker 
25*d57664e9SAndroid Build Coastguard Worker namespace android {
26*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
27*d57664e9SAndroid Build Coastguard Worker 
28*d57664e9SAndroid Build Coastguard Worker using namespace std;
29*d57664e9SAndroid Build Coastguard Worker 
detach(sp<BaseRenderNodeAnimator> & animator)30*d57664e9SAndroid Build Coastguard Worker static void detach(sp<BaseRenderNodeAnimator>& animator) {
31*d57664e9SAndroid Build Coastguard Worker     animator->detach();
32*d57664e9SAndroid Build Coastguard Worker }
33*d57664e9SAndroid Build Coastguard Worker 
AnimatorManager(RenderNode & parent)34*d57664e9SAndroid Build Coastguard Worker AnimatorManager::AnimatorManager(RenderNode& parent)
35*d57664e9SAndroid Build Coastguard Worker         : mParent(parent), mAnimationHandle(nullptr), mCancelAllAnimators(false) {}
36*d57664e9SAndroid Build Coastguard Worker 
~AnimatorManager()37*d57664e9SAndroid Build Coastguard Worker AnimatorManager::~AnimatorManager() {
38*d57664e9SAndroid Build Coastguard Worker     for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
39*d57664e9SAndroid Build Coastguard Worker     for_each(mAnimators.begin(), mAnimators.end(), detach);
40*d57664e9SAndroid Build Coastguard Worker }
41*d57664e9SAndroid Build Coastguard Worker 
addAnimator(const sp<BaseRenderNodeAnimator> & animator)42*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
43*d57664e9SAndroid Build Coastguard Worker     RenderNode* stagingTarget = animator->stagingTarget();
44*d57664e9SAndroid Build Coastguard Worker     if (stagingTarget == &mParent) {
45*d57664e9SAndroid Build Coastguard Worker         return;
46*d57664e9SAndroid Build Coastguard Worker     }
47*d57664e9SAndroid Build Coastguard Worker     mNewAnimators.emplace_back(animator.get());
48*d57664e9SAndroid Build Coastguard Worker     // If the animator is already attached to other RenderNode, remove it from that RenderNode's
49*d57664e9SAndroid Build Coastguard Worker     // new animator list. This ensures one animator only ends up in one newAnimatorList during one
50*d57664e9SAndroid Build Coastguard Worker     // frame, even when it's added multiple times to multiple targets.
51*d57664e9SAndroid Build Coastguard Worker     if (stagingTarget) {
52*d57664e9SAndroid Build Coastguard Worker         stagingTarget->removeAnimator(animator);
53*d57664e9SAndroid Build Coastguard Worker     }
54*d57664e9SAndroid Build Coastguard Worker     animator->attach(&mParent);
55*d57664e9SAndroid Build Coastguard Worker }
56*d57664e9SAndroid Build Coastguard Worker 
removeAnimator(const sp<BaseRenderNodeAnimator> & animator)57*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
58*d57664e9SAndroid Build Coastguard Worker     mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
59*d57664e9SAndroid Build Coastguard Worker                         mNewAnimators.end());
60*d57664e9SAndroid Build Coastguard Worker }
61*d57664e9SAndroid Build Coastguard Worker 
setAnimationHandle(AnimationHandle * handle)62*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
63*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
64*d57664e9SAndroid Build Coastguard Worker     mAnimationHandle = handle;
65*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
66*d57664e9SAndroid Build Coastguard Worker                         "Lost animation handle on %p (%s) with outstanding animators!", &mParent,
67*d57664e9SAndroid Build Coastguard Worker                         mParent.getName());
68*d57664e9SAndroid Build Coastguard Worker }
69*d57664e9SAndroid Build Coastguard Worker 
pushStaging()70*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::pushStaging() {
71*d57664e9SAndroid Build Coastguard Worker     if (mNewAnimators.size()) {
72*d57664e9SAndroid Build Coastguard Worker         if (CC_UNLIKELY(!mAnimationHandle)) {
73*d57664e9SAndroid Build Coastguard Worker             ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
74*d57664e9SAndroid Build Coastguard Worker                   mParent.getName());
75*d57664e9SAndroid Build Coastguard Worker             return;
76*d57664e9SAndroid Build Coastguard Worker         }
77*d57664e9SAndroid Build Coastguard Worker 
78*d57664e9SAndroid Build Coastguard Worker         // Only add new animators that are not already in the mAnimators list
79*d57664e9SAndroid Build Coastguard Worker         for (auto& anim : mNewAnimators) {
80*d57664e9SAndroid Build Coastguard Worker             if (anim->target() != &mParent) {
81*d57664e9SAndroid Build Coastguard Worker                 mAnimators.push_back(std::move(anim));
82*d57664e9SAndroid Build Coastguard Worker             }
83*d57664e9SAndroid Build Coastguard Worker         }
84*d57664e9SAndroid Build Coastguard Worker         mNewAnimators.clear();
85*d57664e9SAndroid Build Coastguard Worker     }
86*d57664e9SAndroid Build Coastguard Worker 
87*d57664e9SAndroid Build Coastguard Worker     if (mCancelAllAnimators) {
88*d57664e9SAndroid Build Coastguard Worker         for (auto& animator : mAnimators) {
89*d57664e9SAndroid Build Coastguard Worker             animator->forceEndNow(mAnimationHandle->context());
90*d57664e9SAndroid Build Coastguard Worker         }
91*d57664e9SAndroid Build Coastguard Worker         mCancelAllAnimators = false;
92*d57664e9SAndroid Build Coastguard Worker     } else {
93*d57664e9SAndroid Build Coastguard Worker         // create a copy of mAnimators as onAnimatorTargetChanged can erase mAnimators.
94*d57664e9SAndroid Build Coastguard Worker         FatVector<sp<BaseRenderNodeAnimator>> animators;
95*d57664e9SAndroid Build Coastguard Worker         animators.reserve(mAnimators.size());
96*d57664e9SAndroid Build Coastguard Worker         for (const auto& animator : mAnimators) {
97*d57664e9SAndroid Build Coastguard Worker             animators.push_back(animator);
98*d57664e9SAndroid Build Coastguard Worker         }
99*d57664e9SAndroid Build Coastguard Worker         for (auto& animator : animators) {
100*d57664e9SAndroid Build Coastguard Worker             animator->pushStaging(mAnimationHandle->context());
101*d57664e9SAndroid Build Coastguard Worker         }
102*d57664e9SAndroid Build Coastguard Worker     }
103*d57664e9SAndroid Build Coastguard Worker }
104*d57664e9SAndroid Build Coastguard Worker 
onAnimatorTargetChanged(BaseRenderNodeAnimator * animator)105*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
106*d57664e9SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
107*d57664e9SAndroid Build Coastguard Worker     mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
108*d57664e9SAndroid Build Coastguard Worker }
109*d57664e9SAndroid Build Coastguard Worker 
110*d57664e9SAndroid Build Coastguard Worker class AnimateFunctor {
111*d57664e9SAndroid Build Coastguard Worker public:
AnimateFunctor(TreeInfo & info,AnimationContext & context,uint32_t * outDirtyMask)112*d57664e9SAndroid Build Coastguard Worker     AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
113*d57664e9SAndroid Build Coastguard Worker             : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
114*d57664e9SAndroid Build Coastguard Worker 
operator ()(sp<BaseRenderNodeAnimator> & animator)115*d57664e9SAndroid Build Coastguard Worker     bool operator()(sp<BaseRenderNodeAnimator>& animator) {
116*d57664e9SAndroid Build Coastguard Worker         *mDirtyMask |= animator->dirtyMask();
117*d57664e9SAndroid Build Coastguard Worker         bool remove = animator->animate(mContext);
118*d57664e9SAndroid Build Coastguard Worker         if (remove) {
119*d57664e9SAndroid Build Coastguard Worker             animator->detach();
120*d57664e9SAndroid Build Coastguard Worker         } else {
121*d57664e9SAndroid Build Coastguard Worker             if (animator->isRunning()) {
122*d57664e9SAndroid Build Coastguard Worker                 mInfo.out.hasAnimations = true;
123*d57664e9SAndroid Build Coastguard Worker             }
124*d57664e9SAndroid Build Coastguard Worker             if (CC_UNLIKELY(!animator->mayRunAsync())) {
125*d57664e9SAndroid Build Coastguard Worker                 mInfo.out.requiresUiRedraw = true;
126*d57664e9SAndroid Build Coastguard Worker             }
127*d57664e9SAndroid Build Coastguard Worker         }
128*d57664e9SAndroid Build Coastguard Worker         return remove;
129*d57664e9SAndroid Build Coastguard Worker     }
130*d57664e9SAndroid Build Coastguard Worker 
131*d57664e9SAndroid Build Coastguard Worker private:
132*d57664e9SAndroid Build Coastguard Worker     TreeInfo& mInfo;
133*d57664e9SAndroid Build Coastguard Worker     AnimationContext& mContext;
134*d57664e9SAndroid Build Coastguard Worker     uint32_t* mDirtyMask;
135*d57664e9SAndroid Build Coastguard Worker };
136*d57664e9SAndroid Build Coastguard Worker 
animate(TreeInfo & info)137*d57664e9SAndroid Build Coastguard Worker uint32_t AnimatorManager::animate(TreeInfo& info) {
138*d57664e9SAndroid Build Coastguard Worker     if (!mAnimators.size()) return 0;
139*d57664e9SAndroid Build Coastguard Worker 
140*d57664e9SAndroid Build Coastguard Worker     // TODO: Can we target this better? For now treat it like any other staging
141*d57664e9SAndroid Build Coastguard Worker     // property push and just damage self before and after animators are run
142*d57664e9SAndroid Build Coastguard Worker 
143*d57664e9SAndroid Build Coastguard Worker     mParent.damageSelf(info);
144*d57664e9SAndroid Build Coastguard Worker     info.damageAccumulator->popTransform();
145*d57664e9SAndroid Build Coastguard Worker 
146*d57664e9SAndroid Build Coastguard Worker     uint32_t dirty = animateCommon(info);
147*d57664e9SAndroid Build Coastguard Worker 
148*d57664e9SAndroid Build Coastguard Worker     info.damageAccumulator->pushTransform(&mParent);
149*d57664e9SAndroid Build Coastguard Worker     mParent.damageSelf(info);
150*d57664e9SAndroid Build Coastguard Worker 
151*d57664e9SAndroid Build Coastguard Worker     return dirty;
152*d57664e9SAndroid Build Coastguard Worker }
153*d57664e9SAndroid Build Coastguard Worker 
animateNoDamage(TreeInfo & info)154*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::animateNoDamage(TreeInfo& info) {
155*d57664e9SAndroid Build Coastguard Worker     animateCommon(info);
156*d57664e9SAndroid Build Coastguard Worker }
157*d57664e9SAndroid Build Coastguard Worker 
animateCommon(TreeInfo & info)158*d57664e9SAndroid Build Coastguard Worker uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
159*d57664e9SAndroid Build Coastguard Worker     uint32_t dirtyMask = 0;
160*d57664e9SAndroid Build Coastguard Worker     AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
161*d57664e9SAndroid Build Coastguard Worker     auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
162*d57664e9SAndroid Build Coastguard Worker     mAnimators.erase(newEnd, mAnimators.end());
163*d57664e9SAndroid Build Coastguard Worker     mAnimationHandle->notifyAnimationsRan();
164*d57664e9SAndroid Build Coastguard Worker     mParent.mProperties.updateMatrix();
165*d57664e9SAndroid Build Coastguard Worker     return dirtyMask;
166*d57664e9SAndroid Build Coastguard Worker }
167*d57664e9SAndroid Build Coastguard Worker 
endStagingAnimator(sp<BaseRenderNodeAnimator> & animator)168*d57664e9SAndroid Build Coastguard Worker static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
169*d57664e9SAndroid Build Coastguard Worker     animator->cancel();
170*d57664e9SAndroid Build Coastguard Worker     if (animator->listener()) {
171*d57664e9SAndroid Build Coastguard Worker         animator->listener()->onAnimationFinished(animator.get());
172*d57664e9SAndroid Build Coastguard Worker     }
173*d57664e9SAndroid Build Coastguard Worker }
174*d57664e9SAndroid Build Coastguard Worker 
endAllStagingAnimators()175*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::endAllStagingAnimators() {
176*d57664e9SAndroid Build Coastguard Worker     ALOGD("endAllStagingAnimators on %p (%s)", &mParent, mParent.getName());
177*d57664e9SAndroid Build Coastguard Worker     // This works because this state can only happen on the UI thread,
178*d57664e9SAndroid Build Coastguard Worker     // which means we're already on the right thread to invoke listeners
179*d57664e9SAndroid Build Coastguard Worker     for_each(mNewAnimators.begin(), mNewAnimators.end(), endStagingAnimator);
180*d57664e9SAndroid Build Coastguard Worker     mNewAnimators.clear();
181*d57664e9SAndroid Build Coastguard Worker }
182*d57664e9SAndroid Build Coastguard Worker 
183*d57664e9SAndroid Build Coastguard Worker class EndActiveAnimatorsFunctor {
184*d57664e9SAndroid Build Coastguard Worker public:
EndActiveAnimatorsFunctor(AnimationContext & context)185*d57664e9SAndroid Build Coastguard Worker     explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
186*d57664e9SAndroid Build Coastguard Worker 
operator ()(sp<BaseRenderNodeAnimator> & animator)187*d57664e9SAndroid Build Coastguard Worker     void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
188*d57664e9SAndroid Build Coastguard Worker 
189*d57664e9SAndroid Build Coastguard Worker private:
190*d57664e9SAndroid Build Coastguard Worker     AnimationContext& mContext;
191*d57664e9SAndroid Build Coastguard Worker };
192*d57664e9SAndroid Build Coastguard Worker 
endAllActiveAnimators()193*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::endAllActiveAnimators() {
194*d57664e9SAndroid Build Coastguard Worker     ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
195*d57664e9SAndroid Build Coastguard Worker           mAnimationHandle);
196*d57664e9SAndroid Build Coastguard Worker     EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
197*d57664e9SAndroid Build Coastguard Worker     for_each(mAnimators.begin(), mAnimators.end(), functor);
198*d57664e9SAndroid Build Coastguard Worker     mAnimators.clear();
199*d57664e9SAndroid Build Coastguard Worker     mAnimationHandle->release();
200*d57664e9SAndroid Build Coastguard Worker }
201*d57664e9SAndroid Build Coastguard Worker 
forceEndAnimators()202*d57664e9SAndroid Build Coastguard Worker void AnimatorManager::forceEndAnimators() {
203*d57664e9SAndroid Build Coastguard Worker     mCancelAllAnimators = true;
204*d57664e9SAndroid Build Coastguard Worker }
205*d57664e9SAndroid Build Coastguard Worker 
206*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
207*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
208