summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2014-08-14 09:02:01 -0700
committerJohn Reck <jreck@google.com>2014-08-27 17:44:25 -0700
commit119907cd2575c56b1ebf66348b52e67aaf6a88d8 (patch)
tree9990e37a560021560316ac2cfc6cf4c64df9cb92 /libs
parent1698297daf8068bc9e6971d43744d48f1672bab2 (diff)
downloadframeworks_base-119907cd2575c56b1ebf66348b52e67aaf6a88d8.zip
frameworks_base-119907cd2575c56b1ebf66348b52e67aaf6a88d8.tar.gz
frameworks_base-119907cd2575c56b1ebf66348b52e67aaf6a88d8.tar.bz2
Animator stuff
Bug: 17228458 Change-Id: Id884a429a512f9cd2be0ed16dbd0f10e92b4440d
Diffstat (limited to 'libs')
-rw-r--r--libs/hwui/Android.mk1
-rw-r--r--libs/hwui/AnimationContext.cpp126
-rw-r--r--libs/hwui/AnimationContext.h112
-rw-r--r--libs/hwui/Animator.cpp32
-rw-r--r--libs/hwui/Animator.h12
-rw-r--r--libs/hwui/AnimatorManager.cpp86
-rw-r--r--libs/hwui/AnimatorManager.h17
-rw-r--r--libs/hwui/IContextFactory.h39
-rw-r--r--libs/hwui/RenderNode.cpp2
-rw-r--r--libs/hwui/RenderNode.h2
-rw-r--r--libs/hwui/TreeInfo.h15
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp10
-rw-r--r--libs/hwui/renderthread/CanvasContext.h7
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp9
-rw-r--r--libs/hwui/renderthread/RenderProxy.h3
-rw-r--r--libs/hwui/renderthread/TimeLord.cpp2
-rw-r--r--libs/hwui/renderthread/TimeLord.h2
17 files changed, 417 insertions, 60 deletions
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index d9f7941..49560ff 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -12,6 +12,7 @@ ifeq ($(USE_OPENGL_RENDERER),true)
font/CacheTexture.cpp \
font/Font.cpp \
AmbientShadow.cpp \
+ AnimationContext.cpp \
Animator.cpp \
AnimatorManager.cpp \
AssetAtlas.cpp \
diff --git a/libs/hwui/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
new file mode 100644
index 0000000..ec44de3
--- /dev/null
+++ b/libs/hwui/AnimationContext.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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 "TreeInfo.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::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() {
+ LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle,
+ "Missed running animations last frame!");
+ AnimationHandle* head = mNextFrameAnimations.mNextHandle;
+ if (head) {
+ mNextFrameAnimations.mNextHandle = NULL;
+ mCurrentFrameAnimations.mNextHandle = head;
+ head->mPreviousHandle = &mCurrentFrameAnimations;
+ }
+ mFrameTimeMs = mClock.computeFrameTimeMs();
+}
+
+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(NULL)
+ , mNextHandle(NULL) {
+}
+
+AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context)
+ : mRenderNode(&animatingNode)
+ , mContext(context)
+ , mPreviousHandle(NULL)
+ , mNextHandle(NULL) {
+ 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 {
+ mRenderNode->animators().setAnimationHandle(NULL);
+ 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 = NULL;
+ mNextHandle = NULL;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
new file mode 100644
index 0000000..e32c33d
--- /dev/null
+++ b/libs/hwui/AnimationContext.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+#ifndef TREEANIMATIONTRACKER_H_
+#define TREEANIMATIONTRACKER_H_
+
+#include <cutils/compiler.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+#include "renderthread/TimeLord.h"
+#include "utils/Macros.h"
+
+namespace android {
+namespace uirenderer {
+
+class AnimationContext;
+class AnimationListener;
+class BaseRenderNodeAnimator;
+class RenderNode;
+class TreeInfo;
+
+/*
+ * AnimationHandle is several classes merged into one.
+ * 1: It maintains the reference to the AnimationContext required to run animators.
+ * 2: It keeps a strong reference to RenderNodes with animators so that
+ * we don't lose them if they are no longer in the display tree. This is
+ * required so that we can keep animating them, and properly notify listeners
+ * of onAnimationFinished.
+ * 3: It forms a doubly linked list so that we can cheaply move between states.
+ */
+class AnimationHandle {
+ PREVENT_COPY_AND_ASSIGN(AnimationHandle);
+public:
+ AnimationContext& context() { return mContext; }
+
+ void notifyAnimationsRan();
+
+private:
+ friend class AnimationContext;
+ AnimationHandle(AnimationContext& context);
+ AnimationHandle(RenderNode& animatingNode, AnimationContext& context);
+ ~AnimationHandle();
+
+ void insertAfter(AnimationHandle* prev);
+ void removeFromList();
+
+ sp<RenderNode> mRenderNode;
+
+ AnimationContext& mContext;
+
+ AnimationHandle* mPreviousHandle;
+ AnimationHandle* mNextHandle;
+};
+
+class AnimationContext {
+ PREVENT_COPY_AND_ASSIGN(AnimationContext);
+public:
+ ANDROID_API AnimationContext(renderthread::TimeLord& clock);
+ ANDROID_API virtual ~AnimationContext();
+
+ nsecs_t frameTimeMs() { return mFrameTimeMs; }
+ bool hasAnimations() {
+ return mCurrentFrameAnimations.mNextHandle
+ || mNextFrameAnimations.mNextHandle;
+ }
+
+ // Will always add to the next frame list, which is swapped when
+ // startFrame() is called
+ ANDROID_API void addAnimatingRenderNode(RenderNode& node);
+
+ // Marks the start of a frame, which will update the frame time and move all
+ // next frame animations into the current frame
+ ANDROID_API virtual void startFrame();
+
+ // Runs any animations still left in mCurrentFrameAnimations that were not run
+ // as part of the standard RenderNode:prepareTree pass.
+ ANDROID_API virtual void runRemainingAnimations(TreeInfo& info);
+
+ ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener);
+
+private:
+ friend class AnimationHandle;
+ void addAnimationHandle(AnimationHandle* handle);
+
+ renderthread::TimeLord& mClock;
+
+ // Animations left to run this frame, at the end of the frame this should
+ // be null
+ AnimationHandle mCurrentFrameAnimations;
+ // Animations queued for next frame
+ AnimationHandle mNextFrameAnimations;
+
+ nsecs_t mFrameTimeMs;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* TREEANIMATIONTRACKER_H_ */
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 78d569d..1c697d5 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <set>
+#include "AnimationContext.h"
#include "RenderNode.h"
#include "RenderProperties.h"
@@ -85,7 +86,7 @@ void BaseRenderNodeAnimator::attach(RenderNode* target) {
onAttached();
}
-void BaseRenderNodeAnimator::pushStaging(TreeInfo& info) {
+void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
if (!mHasStartValue) {
doSetStartValue(getValue(mTarget));
}
@@ -93,21 +94,22 @@ void BaseRenderNodeAnimator::pushStaging(TreeInfo& info) {
mPlayState = mStagingPlayState;
// Oh boy, we're starting! Man the battle stations!
if (mPlayState == RUNNING) {
- transitionToRunning(info);
+ transitionToRunning(context);
}
}
}
-void BaseRenderNodeAnimator::transitionToRunning(TreeInfo& info) {
- LOG_ALWAYS_FATAL_IF(info.frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", info.frameTimeMs);
+void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
+ nsecs_t frameTimeMs = context.frameTimeMs();
+ LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs);
if (mStartDelay < 0 || mStartDelay > 50000) {
ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay);
}
- mStartTime = info.frameTimeMs + mStartDelay;
+ mStartTime = frameTimeMs + mStartDelay;
if (mStartTime < 0) {
ALOGW("Ended up with a really weird start time of %" PRId64
" with frame time %" PRId64 " and start delay %" PRId64,
- mStartTime, info.frameTimeMs, mStartDelay);
+ mStartTime, frameTimeMs, mStartDelay);
// Set to 0 so that the animate() basically instantly finishes
mStartTime = 0;
}
@@ -120,7 +122,7 @@ void BaseRenderNodeAnimator::transitionToRunning(TreeInfo& info) {
}
}
-bool BaseRenderNodeAnimator::animate(TreeInfo& info) {
+bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
if (mPlayState < RUNNING) {
return false;
}
@@ -132,15 +134,14 @@ bool BaseRenderNodeAnimator::animate(TreeInfo& info) {
// because the staging properties reflect the final value, we always need
// to call setValue even if the animation isn't yet running or is still
// being delayed as we need to override the staging value
- if (mStartTime > info.frameTimeMs) {
- info.out.hasAnimations |= true;
+ if (mStartTime > context.frameTimeMs()) {
setValue(mTarget, mFromValue);
return false;
}
float fraction = 1.0f;
if (mPlayState == RUNNING && mDuration > 0) {
- fraction = (float)(info.frameTimeMs - mStartTime) / mDuration;
+ fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration;
}
if (fraction >= 1.0f) {
fraction = 1.0f;
@@ -151,21 +152,16 @@ bool BaseRenderNodeAnimator::animate(TreeInfo& info) {
setValue(mTarget, mFromValue + (mDeltaValue * fraction));
if (mPlayState == FINISHED) {
- callOnFinishedListener(info);
+ callOnFinishedListener(context);
return true;
}
- info.out.hasAnimations |= true;
return false;
}
-void BaseRenderNodeAnimator::callOnFinishedListener(TreeInfo& info) {
+void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
if (mListener.get()) {
- if (!info.animationHook) {
- mListener->onAnimationFinished(this);
- } else {
- info.animationHook->callOnFinished(this, mListener.get());
- }
+ context.callOnFinished(this, mListener.get());
}
}
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 6dfe7b4..c52a93f 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -28,6 +28,8 @@
namespace android {
namespace uirenderer {
+class AnimationContext;
+class BaseRenderNodeAnimator;
class RenderNode;
class RenderProperties;
@@ -50,15 +52,17 @@ public:
ANDROID_API void setListener(AnimationListener* listener) {
mListener = listener;
}
+ AnimationListener* listener() { return mListener.get(); }
ANDROID_API void start() { mStagingPlayState = RUNNING; onStagingPlayStateChanged(); }
ANDROID_API void end() { mStagingPlayState = FINISHED; onStagingPlayStateChanged(); }
void attach(RenderNode* target);
virtual void onAttached() {}
void detach() { mTarget = 0; }
- void pushStaging(TreeInfo& info);
- bool animate(TreeInfo& info);
+ void pushStaging(AnimationContext& context);
+ bool animate(AnimationContext& context);
+ bool isRunning() { return mPlayState == RUNNING; }
bool isFinished() { return mPlayState == FINISHED; }
float finalValue() { return mFinalValue; }
@@ -72,7 +76,7 @@ protected:
virtual void setValue(RenderNode* target, float value) = 0;
RenderNode* target() { return mTarget; }
- void callOnFinishedListener(TreeInfo& info);
+ void callOnFinishedListener(AnimationContext& context);
virtual void onStagingPlayStateChanged() {}
@@ -100,7 +104,7 @@ protected:
private:
inline void checkMutable();
- virtual void transitionToRunning(TreeInfo& info);
+ virtual void transitionToRunning(AnimationContext& context);
void doSetStartValue(float value);
};
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 7221295a4..3832d42 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -17,6 +17,7 @@
#include <algorithm>
+#include "AnimationContext.h"
#include "RenderNode.h"
namespace android {
@@ -30,7 +31,8 @@ static void unref(BaseRenderNodeAnimator* animator) {
}
AnimatorManager::AnimatorManager(RenderNode& parent)
- : mParent(parent) {
+ : mParent(parent)
+ , mAnimationHandle(NULL) {
}
AnimatorManager::~AnimatorManager() {
@@ -44,6 +46,11 @@ void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mNewAnimators.push_back(animator.get());
}
+void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
+ LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
+ mAnimationHandle = handle;
+}
+
template<typename T>
static void move_all(T& source, T& dest) {
dest.reserve(source.size() + dest.size());
@@ -53,26 +60,30 @@ static void move_all(T& source, T& dest) {
source.clear();
}
-void AnimatorManager::pushStaging(TreeInfo& info) {
+void AnimatorManager::pushStaging() {
if (mNewAnimators.size()) {
// Since this is a straight move, we don't need to inc/dec the ref count
move_all(mNewAnimators, mAnimators);
}
for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
- (*it)->pushStaging(info);
+ (*it)->pushStaging(mAnimationHandle->context());
}
}
class AnimateFunctor {
public:
- AnimateFunctor(RenderNode& target, TreeInfo& info)
- : dirtyMask(0), mTarget(target), mInfo(info) {}
+ AnimateFunctor(TreeInfo& info, AnimationContext& context)
+ : dirtyMask(0), mInfo(info), mContext(context) {}
bool operator() (BaseRenderNodeAnimator* animator) {
dirtyMask |= animator->dirtyMask();
- bool remove = animator->animate(mInfo);
+ bool remove = animator->animate(mContext);
if (remove) {
animator->decStrong(0);
+ } else {
+ if (animator->isRunning()) {
+ mInfo.out.hasAnimations = true;
+ }
}
return remove;
}
@@ -80,8 +91,8 @@ public:
uint32_t dirtyMask;
private:
- RenderNode& mTarget;
TreeInfo& mInfo;
+ AnimationContext& mContext;
};
uint32_t AnimatorManager::animate(TreeInfo& info) {
@@ -93,17 +104,70 @@ uint32_t AnimatorManager::animate(TreeInfo& info) {
mParent.damageSelf(info);
info.damageAccumulator->popTransform();
- AnimateFunctor functor(mParent, info);
- std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
- newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
- mAnimators.erase(newEnd, mAnimators.end());
+ uint32_t dirty = animateCommon(info);
mParent.mProperties.updateMatrix();
info.damageAccumulator->pushTransform(&mParent);
mParent.damageSelf(info);
+ return dirty;
+}
+
+void AnimatorManager::animateNoDamage(TreeInfo& info) {
+ if (!mAnimators.size()) return;
+
+ animateCommon(info);
+}
+
+uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
+ AnimateFunctor functor(info, mAnimationHandle->context());
+ std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
+ newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
+ mAnimators.erase(newEnd, mAnimators.end());
+ mAnimationHandle->notifyAnimationsRan();
return functor.dirtyMask;
}
+class EndAnimatorsFunctor {
+public:
+ EndAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
+
+ void operator() (BaseRenderNodeAnimator* animator) {
+ animator->end();
+ animator->pushStaging(mContext);
+ animator->animate(mContext);
+ animator->decStrong(0);
+ }
+
+private:
+ AnimationContext& mContext;
+};
+
+static void endAnimatorsHard(BaseRenderNodeAnimator* animator) {
+ animator->end();
+ if (animator->listener()) {
+ animator->listener()->onAnimationFinished(animator);
+ }
+ animator->decStrong(0);
+}
+
+void AnimatorManager::endAllAnimators() {
+ if (mNewAnimators.size()) {
+ // Since this is a straight move, we don't need to inc/dec the ref count
+ move_all(mNewAnimators, mAnimators);
+ }
+ // First try gracefully ending them
+ if (mAnimationHandle) {
+ EndAnimatorsFunctor functor(mAnimationHandle->context());
+ for_each(mAnimators.begin(), mAnimators.end(), functor);
+ } else {
+ // We have no context, so bust out the sledgehammer
+ // 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(mAnimators.begin(), mAnimators.end(), endAnimatorsHard);
+ }
+ mAnimators.clear();
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index 0d177c5..d5f56ed 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -27,6 +27,7 @@
namespace android {
namespace uirenderer {
+class AnimationHandle;
class BaseRenderNodeAnimator;
class RenderNode;
@@ -39,12 +40,26 @@ public:
void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
- void pushStaging(TreeInfo& info);
+ void setAnimationHandle(AnimationHandle* handle);
+ bool hasAnimationHandle() { return mAnimationHandle; }
+
+ void pushStaging();
+
// Returns the combined dirty mask of all animators run
uint32_t animate(TreeInfo& info);
+ void animateNoDamage(TreeInfo& info);
+
+ // Hard-ends all animators. Used for cleanup if the root is being destroyed.
+ ANDROID_API void endAllAnimators();
+
+ bool hasAnimators() { return mAnimators.size(); }
+
private:
+ uint32_t animateCommon(TreeInfo& info);
+
RenderNode& mParent;
+ AnimationHandle* mAnimationHandle;
// To improve the efficiency of resizing & removing from the vector
// use manual ref counting instead of sp<>.
diff --git a/libs/hwui/IContextFactory.h b/libs/hwui/IContextFactory.h
new file mode 100644
index 0000000..463b55e
--- /dev/null
+++ b/libs/hwui/IContextFactory.h
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+#ifndef CONTEXTFACTORY_H_
+#define CONTEXTFACTORY_H_
+
+namespace android {
+namespace uirenderer {
+
+namespace renderthread {
+class TimeLord;
+}
+
+class AnimationContext;
+
+class IContextFactory {
+public:
+ virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) = 0;
+
+protected:
+ virtual ~IContextFactory() {}
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* CONTEXTFACTORY_H_ */
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 658265d..a79875e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -235,7 +235,7 @@ void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
if (CC_LIKELY(info.runAnimations)) {
- mAnimatorManager.pushStaging(info);
+ mAnimatorManager.pushStaging();
}
if (mDirtyPropertyFields) {
mDirtyPropertyFields = 0;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 18402b2..27b05e2 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -174,6 +174,8 @@ public:
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
+ AnimatorManager& animators() { return mAnimatorManager; }
+
void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const;
private:
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 74d52a3..e78d8bd 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -26,18 +26,9 @@
namespace android {
namespace uirenderer {
-class BaseRenderNodeAnimator;
-class AnimationListener;
class OpenGLRenderer;
class RenderState;
-class AnimationHook {
-public:
- virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) = 0;
-protected:
- ~AnimationHook() {}
-};
-
class ErrorHandler {
public:
virtual void onError(const std::string& message) = 0;
@@ -62,8 +53,6 @@ public:
explicit TreeInfo(TraversalMode mode, RenderState& renderState)
: mode(mode)
- , frameTimeMs(0)
- , animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
, runAnimations(true)
, damageAccumulator(NULL)
@@ -74,8 +63,6 @@ public:
explicit TreeInfo(TraversalMode mode, const TreeInfo& clone)
: mode(mode)
- , frameTimeMs(clone.frameTimeMs)
- , animationHook(clone.animationHook)
, prepareTextures(mode == MODE_FULL)
, runAnimations(clone.runAnimations)
, damageAccumulator(clone.damageAccumulator)
@@ -85,8 +72,6 @@ public:
{}
const TraversalMode mode;
- nsecs_t frameTimeMs;
- AnimationHook* animationHook;
// TODO: Remove this? Currently this is used to signal to stop preparing
// textures if we run out of cache space.
bool prepareTextures;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4bf5a8a..d9fa0bc 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -21,6 +21,7 @@
#include "EglManager.h"
#include "RenderThread.h"
+#include "../AnimationContext.h"
#include "../Caches.h"
#include "../DeferredLayerUpdater.h"
#include "../RenderState.h"
@@ -35,7 +36,8 @@ namespace android {
namespace uirenderer {
namespace renderthread {
-CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode)
+CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
+ RenderNode* rootRenderNode, IContextFactory* contextFactory)
: mRenderThread(thread)
, mEglManager(thread.eglManager())
, mEglSurface(EGL_NO_SURFACE)
@@ -44,11 +46,13 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode*
, mCanvas(NULL)
, mHaveNewSurface(false)
, mRootRenderNode(rootRenderNode) {
+ mAnimationContext = contextFactory->createAnimationContext(mRenderThread.timeLord());
}
CanvasContext::~CanvasContext() {
destroyCanvasAndSurface();
mRenderThread.removeFrameCallback(this);
+ delete mAnimationContext;
}
void CanvasContext::destroyCanvasAndSurface() {
@@ -136,10 +140,11 @@ void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
void CanvasContext::prepareTree(TreeInfo& info) {
mRenderThread.removeFrameCallback(this);
- info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
info.renderer = mCanvas;
+ mAnimationContext->startFrame();
mRootRenderNode->prepareTree(info);
+ mAnimationContext->runRemainingAnimations(info);
int runningBehind = 0;
// TODO: This query is moderately expensive, investigate adding some sort
@@ -254,7 +259,6 @@ void CanvasContext::buildLayer(RenderNode* node) {
stopDrawing();
TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState());
- info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
info.renderer = mCanvas;
info.runAnimations = false;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0cbed6f..749da1b 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -25,6 +25,7 @@
#include "../DamageAccumulator.h"
#include "../DrawProfiler.h"
+#include "../IContextFactory.h"
#include "../RenderNode.h"
#include "RenderTask.h"
#include "RenderThread.h"
@@ -34,6 +35,7 @@
namespace android {
namespace uirenderer {
+class AnimationContext;
class DeferredLayerUpdater;
class OpenGLRenderer;
class Rect;
@@ -45,9 +47,11 @@ class EglManager;
// This per-renderer class manages the bridge between the global EGL context
// and the render surface.
+// TODO: Rename to Renderer or some other per-window, top-level manager
class CanvasContext : public IFrameCallback {
public:
- CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode);
+ CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory);
virtual ~CanvasContext();
bool initialize(ANativeWindow* window);
@@ -105,6 +109,7 @@ private:
OpenGLRenderer* mCanvas;
bool mHaveNewSurface;
DamageAccumulator mDamageAccumulator;
+ AnimationContext* mAnimationContext;
const sp<RenderNode> mRootRenderNode;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 405ce24..3d04316 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -52,17 +52,20 @@ namespace renderthread {
MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
ARGS(method) *args = (ARGS(method) *) task->payload()
-CREATE_BRIDGE3(createContext, RenderThread* thread, bool translucent, RenderNode* rootRenderNode) {
- return new CanvasContext(*args->thread, args->translucent, args->rootRenderNode);
+CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
+ RenderNode* rootRenderNode, IContextFactory* contextFactory) {
+ return new CanvasContext(*args->thread, args->translucent,
+ args->rootRenderNode, args->contextFactory);
}
-RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode)
+RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
: mRenderThread(RenderThread::getInstance())
, mContext(0) {
SETUP_TASK(createContext);
args->translucent = translucent;
args->rootRenderNode = rootRenderNode;
args->thread = &mRenderThread;
+ args->contextFactory = contextFactory;
mContext = (CanvasContext*) postAndWait(task);
mDrawFrameTask.setContext(&mRenderThread, mContext);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index eea3674..9e6bcf5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -30,6 +30,7 @@
#include <utils/Vector.h>
#include "../Caches.h"
+#include "../IContextFactory.h"
#include "DrawFrameTask.h"
namespace android {
@@ -58,7 +59,7 @@ class RenderProxyBridge;
*/
class ANDROID_API RenderProxy {
public:
- ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode);
+ ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode, IContextFactory* contextFactory);
ANDROID_API virtual ~RenderProxy();
ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos);
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index 758d96e..cf3d039 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -30,7 +30,7 @@ void TimeLord::vsyncReceived(nsecs_t vsync) {
}
}
-nsecs_t TimeLord::frameTimeMs() {
+nsecs_t TimeLord::computeFrameTimeMs() {
// Logic copied from Choreographer.java
nsecs_t now = systemTime(CLOCK_MONOTONIC);
nsecs_t jitterNanos = now - mFrameTimeNanos;
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 52c6d9e..8b0372c 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -30,7 +30,7 @@ class TimeLord {
public:
void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
void vsyncReceived(nsecs_t vsync);
- nsecs_t frameTimeMs();
+ nsecs_t computeFrameTimeMs();
private:
friend class RenderThread;