/* * 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 "AnimationContext.h" #include "Animator.h" #include "RenderNode.h" #include "renderthread/TimeLord.h" namespace android { namespace uirenderer { AnimationContext::AnimationContext(renderthread::TimeLord& clock) : mClock(clock) , mCurrentFrameAnimations(*this) , mNextFrameAnimations(*this) , mFrameTimeMs(0) { } AnimationContext::~AnimationContext() { } void AnimationContext::destroy() { startFrame(TreeInfo::MODE_RT_ONLY); while (mCurrentFrameAnimations.mNextHandle) { AnimationHandle* current = mCurrentFrameAnimations.mNextHandle; AnimatorManager& animators = current->mRenderNode->animators(); animators.endAllActiveAnimators(); LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current, "endAllAnimators failed to remove from current frame list!"); } } void AnimationContext::addAnimatingRenderNode(RenderNode& node) { if (!node.animators().hasAnimationHandle()) { AnimationHandle* handle = new AnimationHandle(node, *this); addAnimationHandle(handle); } } void AnimationContext::addAnimationHandle(AnimationHandle* handle) { handle->insertAfter(&mNextFrameAnimations); } void AnimationContext::startFrame(TreeInfo::TraversalMode mode) { LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle, "Missed running animations last frame!"); AnimationHandle* head = mNextFrameAnimations.mNextHandle; if (head) { mNextFrameAnimations.mNextHandle = nullptr; mCurrentFrameAnimations.mNextHandle = head; head->mPreviousHandle = &mCurrentFrameAnimations; } mFrameTimeMs = ns2ms(mClock.latestVsync()); } void AnimationContext::runRemainingAnimations(TreeInfo& info) { while (mCurrentFrameAnimations.mNextHandle) { AnimationHandle* current = mCurrentFrameAnimations.mNextHandle; AnimatorManager& animators = current->mRenderNode->animators(); animators.pushStaging(); animators.animateNoDamage(info); LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current, "Animate failed to remove from current frame list!"); } } void AnimationContext::callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) { listener->onAnimationFinished(animator); } AnimationHandle::AnimationHandle(AnimationContext& context) : mContext(context) , mPreviousHandle(nullptr) , mNextHandle(nullptr) { } AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context) : mRenderNode(&animatingNode) , mContext(context) , mPreviousHandle(nullptr) , mNextHandle(nullptr) { mRenderNode->animators().setAnimationHandle(this); } AnimationHandle::~AnimationHandle() { LOG_ALWAYS_FATAL_IF(mPreviousHandle || mNextHandle, "AnimationHandle destroyed while still animating!"); } void AnimationHandle::notifyAnimationsRan() { removeFromList(); if (mRenderNode->animators().hasAnimators()) { mContext.addAnimationHandle(this); } else { release(); } } void AnimationHandle::release() { LOG_ALWAYS_FATAL_IF(mRenderNode->animators().hasAnimators(), "Releasing the handle for an RenderNode with outstanding animators!"); removeFromList(); mRenderNode->animators().setAnimationHandle(nullptr); delete this; } void AnimationHandle::insertAfter(AnimationHandle* prev) { removeFromList(); mNextHandle = prev->mNextHandle; if (mNextHandle) { mNextHandle->mPreviousHandle = this; } prev->mNextHandle = this; mPreviousHandle = prev; } void AnimationHandle::removeFromList() { if (mPreviousHandle) { mPreviousHandle->mNextHandle = mNextHandle; } if (mNextHandle) { mNextHandle->mPreviousHandle = mPreviousHandle; } mPreviousHandle = nullptr; mNextHandle = nullptr; } } /* namespace uirenderer */ } /* namespace android */