AnimatorManager.cpp revision 6725d581eb3c13591a4ff276413dbfa0fc13e739
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
25namespace android {
26namespace uirenderer {
27
28using namespace std;
29
30static void detach(sp<BaseRenderNodeAnimator>& animator) {
31    animator->detach();
32}
33
34AnimatorManager::AnimatorManager(RenderNode& parent)
35        : mParent(parent)
36        , mAnimationHandle(nullptr) {
37}
38
39AnimatorManager::~AnimatorManager() {
40    for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
41    for_each(mAnimators.begin(), mAnimators.end(), detach);
42}
43
44void 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
59void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
60    mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
61            mNewAnimators.end());
62}
63
64void 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
72void AnimatorManager::pushStaging() {
73    if (mNewAnimators.size()) {
74        LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
75                "Trying to start new animators on %p (%s) without an animation handle!",
76                &mParent, mParent.getName());
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    for (auto& animator : mAnimators) {
87        animator->pushStaging(mAnimationHandle->context());
88    }
89}
90
91void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
92    LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
93    mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
94}
95
96class AnimateFunctor {
97public:
98    AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
99            : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
100
101    bool operator() (sp<BaseRenderNodeAnimator>& animator) {
102        *mDirtyMask |= animator->dirtyMask();
103        bool remove = animator->animate(mContext);
104        if (remove) {
105            animator->detach();
106        } else {
107            if (animator->isRunning()) {
108                mInfo.out.hasAnimations = true;
109            }
110            if (CC_UNLIKELY(!animator->mayRunAsync())) {
111                mInfo.out.requiresUiRedraw = true;
112            }
113        }
114        return remove;
115    }
116
117private:
118    TreeInfo& mInfo;
119    AnimationContext& mContext;
120    uint32_t* mDirtyMask;
121};
122
123uint32_t AnimatorManager::animate(TreeInfo& info) {
124    if (!mAnimators.size()) return 0;
125
126    // TODO: Can we target this better? For now treat it like any other staging
127    // property push and just damage self before and after animators are run
128
129    mParent.damageSelf(info);
130    info.damageAccumulator->popTransform();
131
132    uint32_t dirty = animateCommon(info);
133
134    info.damageAccumulator->pushTransform(&mParent);
135    mParent.damageSelf(info);
136
137    return dirty;
138}
139
140void AnimatorManager::animateNoDamage(TreeInfo& info) {
141    animateCommon(info);
142}
143
144uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
145    uint32_t dirtyMask;
146    AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
147    auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
148    mAnimators.erase(newEnd, mAnimators.end());
149    mAnimationHandle->notifyAnimationsRan();
150    mParent.mProperties.updateMatrix();
151    return dirtyMask;
152}
153
154static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
155    animator->cancel();
156    if (animator->listener()) {
157        animator->listener()->onAnimationFinished(animator.get());
158    }
159}
160
161void AnimatorManager::endAllStagingAnimators() {
162    ALOGD("endAllStagingAnimators on %p (%s)", &mParent, mParent.getName());
163    // This works because this state can only happen on the UI thread,
164    // which means we're already on the right thread to invoke listeners
165    for_each(mNewAnimators.begin(), mNewAnimators.end(), endStagingAnimator);
166    mNewAnimators.clear();
167}
168
169class EndActiveAnimatorsFunctor {
170public:
171    EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
172
173    void operator() (sp<BaseRenderNodeAnimator>& animator) {
174        animator->forceEndNow(mContext);
175    }
176
177private:
178    AnimationContext& mContext;
179};
180
181void AnimatorManager::endAllActiveAnimators() {
182    ALOGD("endAllActiveAnimators on %p (%s) with handle %p",
183            &mParent, mParent.getName(), mAnimationHandle);
184    EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
185    for_each(mAnimators.begin(), mAnimators.end(), functor);
186    mAnimators.clear();
187    mAnimationHandle->release();
188}
189
190} /* namespace uirenderer */
191} /* namespace android */
192