AnimatorManager.cpp revision d0cd9db31639b246587fe494ec15d32d9fdb3dc7
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 "RenderNode.h"
22
23namespace android {
24namespace uirenderer {
25
26using namespace std;
27
28static void unref(BaseRenderNodeAnimator* animator) {
29    animator->detach();
30    animator->decStrong(0);
31}
32
33AnimatorManager::AnimatorManager(RenderNode& parent)
34        : mParent(parent)
35        , mAnimationHandle(NULL) {
36}
37
38AnimatorManager::~AnimatorManager() {
39    for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
40    for_each(mAnimators.begin(), mAnimators.end(), unref);
41}
42
43void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
44    animator->incStrong(0);
45    animator->attach(&mParent);
46    mNewAnimators.push_back(animator.get());
47}
48
49void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
50    LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
51    mAnimationHandle = handle;
52}
53
54template<typename T>
55static void move_all(T& source, T& dest) {
56    dest.reserve(source.size() + dest.size());
57    for (typename T::iterator it = source.begin(); it != source.end(); it++) {
58        dest.push_back(*it);
59    }
60    source.clear();
61}
62
63void AnimatorManager::pushStaging() {
64    if (mNewAnimators.size()) {
65        // Since this is a straight move, we don't need to inc/dec the ref count
66        move_all(mNewAnimators, mAnimators);
67    }
68    for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
69        (*it)->pushStaging(mAnimationHandle->context());
70    }
71}
72
73class AnimateFunctor {
74public:
75    AnimateFunctor(TreeInfo& info, AnimationContext& context)
76            : dirtyMask(0), mInfo(info), mContext(context) {}
77
78    bool operator() (BaseRenderNodeAnimator* animator) {
79        dirtyMask |= animator->dirtyMask();
80        bool remove = animator->animate(mContext);
81        if (remove) {
82            animator->decStrong(0);
83        } else {
84            if (animator->isRunning()) {
85                mInfo.out.hasAnimations = true;
86            }
87        }
88        return remove;
89    }
90
91    uint32_t dirtyMask;
92
93private:
94    TreeInfo& mInfo;
95    AnimationContext& mContext;
96};
97
98uint32_t AnimatorManager::animate(TreeInfo& info) {
99    if (!mAnimators.size()) return 0;
100
101    // TODO: Can we target this better? For now treat it like any other staging
102    // property push and just damage self before and after animators are run
103
104    mParent.damageSelf(info);
105    info.damageAccumulator->popTransform();
106
107    uint32_t dirty = animateCommon(info);
108
109    mParent.mProperties.updateMatrix();
110    info.damageAccumulator->pushTransform(&mParent);
111    mParent.damageSelf(info);
112
113    return dirty;
114}
115
116void AnimatorManager::animateNoDamage(TreeInfo& info) {
117    if (!mAnimators.size()) return;
118
119    animateCommon(info);
120}
121
122uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
123    AnimateFunctor functor(info, mAnimationHandle->context());
124    std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
125    newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
126    mAnimators.erase(newEnd, mAnimators.end());
127    mAnimationHandle->notifyAnimationsRan();
128    return functor.dirtyMask;
129}
130
131class EndAnimatorsFunctor {
132public:
133    EndAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
134
135    void operator() (BaseRenderNodeAnimator* animator) {
136        animator->end();
137        animator->pushStaging(mContext);
138        animator->animate(mContext);
139        animator->decStrong(0);
140    }
141
142private:
143    AnimationContext& mContext;
144};
145
146static void endAnimatorsHard(BaseRenderNodeAnimator* animator) {
147    animator->end();
148    if (animator->listener()) {
149        animator->listener()->onAnimationFinished(animator);
150    }
151    animator->decStrong(0);
152}
153
154void AnimatorManager::endAllAnimators() {
155    if (mNewAnimators.size()) {
156        // Since this is a straight move, we don't need to inc/dec the ref count
157        move_all(mNewAnimators, mAnimators);
158    }
159    // First try gracefully ending them
160    if (mAnimationHandle) {
161        EndAnimatorsFunctor functor(mAnimationHandle->context());
162        for_each(mAnimators.begin(), mAnimators.end(), functor);
163        mAnimators.clear();
164        mAnimationHandle->release();
165    } else {
166        // We have no context, so bust out the sledgehammer
167        // This works because this state can only happen on the UI thread,
168        // which means we're already on the right thread to invoke listeners
169        for_each(mAnimators.begin(), mAnimators.end(), endAnimatorsHard);
170        mAnimators.clear();
171    }
172}
173
174} /* namespace uirenderer */
175} /* namespace android */
176