189 lines
6.2 KiB
C++
189 lines
6.2 KiB
C++
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "AnimatorManager.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "AnimationContext.h"
|
|
#include "Animator.h"
|
|
#include "DamageAccumulator.h"
|
|
#include "RenderNode.h"
|
|
|
|
namespace android {
|
|
namespace uirenderer {
|
|
|
|
using namespace std;
|
|
|
|
static void detach(sp<BaseRenderNodeAnimator>& animator) {
|
|
animator->detach();
|
|
}
|
|
|
|
AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
|
|
|
|
AnimatorManager::~AnimatorManager() {
|
|
for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
|
|
for_each(mAnimators.begin(), mAnimators.end(), detach);
|
|
}
|
|
|
|
void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
|
RenderNode* stagingTarget = animator->stagingTarget();
|
|
if (stagingTarget == &mParent) {
|
|
return;
|
|
}
|
|
mNewAnimators.emplace_back(animator.get());
|
|
// If the animator is already attached to other RenderNode, remove it from that RenderNode's
|
|
// new animator list. This ensures one animator only ends up in one newAnimatorList during one
|
|
// frame, even when it's added multiple times to multiple targets.
|
|
if (stagingTarget) {
|
|
stagingTarget->removeAnimator(animator);
|
|
}
|
|
animator->attach(&mParent);
|
|
}
|
|
|
|
void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
|
mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
|
|
mNewAnimators.end());
|
|
}
|
|
|
|
void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
|
|
LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
|
|
mAnimationHandle = handle;
|
|
LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
|
|
"Lost animation handle on %p (%s) with outstanding animators!", &mParent,
|
|
mParent.getName());
|
|
}
|
|
|
|
void AnimatorManager::pushStaging() {
|
|
if (mNewAnimators.size()) {
|
|
if (CC_UNLIKELY(!mAnimationHandle)) {
|
|
ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
|
|
mParent.getName());
|
|
return;
|
|
}
|
|
|
|
// Only add new animators that are not already in the mAnimators list
|
|
for (auto& anim : mNewAnimators) {
|
|
if (anim->target() != &mParent) {
|
|
mAnimators.push_back(std::move(anim));
|
|
}
|
|
}
|
|
mNewAnimators.clear();
|
|
}
|
|
for (auto& animator : mAnimators) {
|
|
animator->pushStaging(mAnimationHandle->context());
|
|
}
|
|
}
|
|
|
|
void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
|
|
LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
|
|
mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
|
|
}
|
|
|
|
class AnimateFunctor {
|
|
public:
|
|
AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
|
|
: mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
|
|
|
|
bool operator()(sp<BaseRenderNodeAnimator>& animator) {
|
|
*mDirtyMask |= animator->dirtyMask();
|
|
bool remove = animator->animate(mContext);
|
|
if (remove) {
|
|
animator->detach();
|
|
} else {
|
|
if (animator->isRunning()) {
|
|
mInfo.out.hasAnimations = true;
|
|
}
|
|
if (CC_UNLIKELY(!animator->mayRunAsync())) {
|
|
mInfo.out.requiresUiRedraw = true;
|
|
}
|
|
}
|
|
return remove;
|
|
}
|
|
|
|
private:
|
|
TreeInfo& mInfo;
|
|
AnimationContext& mContext;
|
|
uint32_t* mDirtyMask;
|
|
};
|
|
|
|
uint32_t AnimatorManager::animate(TreeInfo& info) {
|
|
if (!mAnimators.size()) return 0;
|
|
|
|
// TODO: Can we target this better? For now treat it like any other staging
|
|
// property push and just damage self before and after animators are run
|
|
|
|
mParent.damageSelf(info);
|
|
info.damageAccumulator->popTransform();
|
|
|
|
uint32_t dirty = animateCommon(info);
|
|
|
|
info.damageAccumulator->pushTransform(&mParent);
|
|
mParent.damageSelf(info);
|
|
|
|
return dirty;
|
|
}
|
|
|
|
void AnimatorManager::animateNoDamage(TreeInfo& info) {
|
|
animateCommon(info);
|
|
}
|
|
|
|
uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
|
|
uint32_t dirtyMask = 0;
|
|
AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
|
|
auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
|
|
mAnimators.erase(newEnd, mAnimators.end());
|
|
mAnimationHandle->notifyAnimationsRan();
|
|
mParent.mProperties.updateMatrix();
|
|
return dirtyMask;
|
|
}
|
|
|
|
static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
|
|
animator->cancel();
|
|
if (animator->listener()) {
|
|
animator->listener()->onAnimationFinished(animator.get());
|
|
}
|
|
}
|
|
|
|
void AnimatorManager::endAllStagingAnimators() {
|
|
ALOGD("endAllStagingAnimators on %p (%s)", &mParent, mParent.getName());
|
|
// This works because this state can only happen on the UI thread,
|
|
// which means we're already on the right thread to invoke listeners
|
|
for_each(mNewAnimators.begin(), mNewAnimators.end(), endStagingAnimator);
|
|
mNewAnimators.clear();
|
|
}
|
|
|
|
class EndActiveAnimatorsFunctor {
|
|
public:
|
|
explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
|
|
|
|
void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
|
|
|
|
private:
|
|
AnimationContext& mContext;
|
|
};
|
|
|
|
void AnimatorManager::endAllActiveAnimators() {
|
|
ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
|
|
mAnimationHandle);
|
|
EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
|
|
for_each(mAnimators.begin(), mAnimators.end(), functor);
|
|
mAnimators.clear();
|
|
mAnimationHandle->release();
|
|
}
|
|
|
|
} /* namespace uirenderer */
|
|
} /* namespace android */
|