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