| /* | 
 |  * 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 */ |