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