Handle hidden RT VectorDrawable animators
This CL changes the target of VD specific animators to VectorDrawable,
instead of RenderNode. The benefit of doing so is that animators can
now detect whether the animation is meaningful by checking whether
their VD target is in the display list. If not, that means the VD is
not drawing for the current frame, in which case we can be smarter
and more power efficient by removing the animator from the list and
posting a delayed onFinished listener callback.
By setting VD as the animation target, when an ImageView decides to
update its drawable from one AVD to something else, we'll be able
to detect that the previous AVD is no longer in the display list,
and stop providing animation pulse to the stale AVD, which is
something we couldn't do previously. This change also
handles the case where one AVD instance could be drawn in two
different views.
Bug: 27441375
Change-Id: Iaad1ed09cfd526276b95db0dd695275c28e074e8
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 909ed36..801fd87 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -100,6 +100,8 @@
ANDROID_API virtual void destroy();
+ ANDROID_API virtual void detachAnimators() {}
+
private:
friend class AnimationHandle;
void addAnimationHandle(AnimationHandle* handle);
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 4d65782..dc18018 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -274,6 +274,10 @@
return playTime >= mDuration;
}
+nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
+ return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
+}
+
void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
if (mPlayState < PlayState::Finished) {
mPlayState = PlayState::Finished;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fdae0f3..9476750 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -62,19 +62,23 @@
}
bool mayRunAsync() { return mMayRunAsync; }
ANDROID_API void start();
- ANDROID_API void reset();
+ ANDROID_API virtual void reset();
ANDROID_API void reverse();
// Terminates the animation at its current progress.
ANDROID_API void cancel();
// Terminates the animation and skip to the end of the animation.
- ANDROID_API void end();
+ ANDROID_API virtual void end();
void attach(RenderNode* target);
virtual void onAttached() {}
void detach() { mTarget = nullptr; }
- void pushStaging(AnimationContext& context);
- bool animate(AnimationContext& context);
+ ANDROID_API void pushStaging(AnimationContext& context);
+ ANDROID_API bool animate(AnimationContext& context);
+
+ // Returns the remaining time in ms for the animation. Note this should only be called during
+ // an animation on RenderThread.
+ ANDROID_API nsecs_t getRemainingPlayTime();
bool isRunning() { return mPlayState == PlayState::Running
|| mPlayState == PlayState::Reversing; }
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index b572bda..28be05c 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,7 +45,7 @@
, regions(stdAllocator)
, referenceHolders(stdAllocator)
, functors(stdAllocator)
- , pushStagingFunctors(stdAllocator)
+ , vectorDrawables(stdAllocator)
, hasDrawOps(false) {
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5b3227b..ccf71c6 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -69,6 +69,11 @@
typedef DrawRenderNodeOp NodeOpType;
#endif
+namespace VectorDrawable {
+class Tree;
+};
+typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
+
/**
* Holds data used in the playback a tree of DisplayLists.
*/
@@ -110,16 +115,6 @@
LinearAllocator mReplayAllocator;
};
-/**
- * Functor that can be used for objects with data in both UI thread and RT to keep the data
- * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
- */
-struct PushStagingFunctor {
- PushStagingFunctor() {}
- virtual ~PushStagingFunctor() {}
- virtual void operator ()() {}
-};
-
struct FunctorContainer {
Functor* functor;
GlFunctorLifecycleListener* listener;
@@ -161,7 +156,7 @@
const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
const LsaVector<FunctorContainer>& getFunctors() const { return functors; }
- const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
+ const LsaVector<VectorDrawableRoot*>& getVectorDrawables() { return vectorDrawables; }
size_t addChild(NodeOpType* childOp);
@@ -203,10 +198,10 @@
// List of functors
LsaVector<FunctorContainer> functors;
- // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+ // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
// but a callback during sync DisplayList, unlike the list of functors defined above, which
// gets special treatment exclusive for webview.
- LsaVector<PushStagingFunctor*> pushStagingFunctors;
+ LsaVector<VectorDrawableRoot*> vectorDrawables;
bool hasDrawOps; // only used if !HWUI_NEW_OPS
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index ca968ce..bec66295 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -417,7 +417,7 @@
void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
- mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+ mDisplayList->vectorDrawables.push_back(tree);
addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
}
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index b29f91f..e416e0c 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -30,6 +30,11 @@
interpolator, startDelay, duration, repeatCount);
mAnimators.emplace_back(animator);
setListener(new PropertyAnimatorSetListener(this));
+
+ // Check whether any child animator is infinite after adding it them to the set.
+ if (repeatCount == -1) {
+ mIsInfinite = true;
+ }
}
PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
@@ -78,15 +83,27 @@
void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
init();
mOneShotListener = listener;
+ mRequestId++;
BaseRenderNodeAnimator::start();
}
void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
init();
mOneShotListener = listener;
+ mRequestId++;
BaseRenderNodeAnimator::reverse();
}
+void PropertyValuesAnimatorSet::reset() {
+ mRequestId++;
+ BaseRenderNodeAnimator::reset();
+}
+
+void PropertyValuesAnimatorSet::end() {
+ mRequestId++;
+ BaseRenderNodeAnimator::end();
+}
+
void PropertyValuesAnimatorSet::init() {
if (mInitialized) {
return;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index c7ae7c0..49021bc 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -43,6 +43,7 @@
float mLatestFraction = 0.0f;
};
+// TODO: This class should really be named VectorDrawableAnimator
class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator {
public:
friend class PropertyAnimatorSetListener;
@@ -50,11 +51,19 @@
void start(AnimationListener* listener);
void reverse(AnimationListener* listener);
+ virtual void reset() override;
+ virtual void end() override;
void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
Interpolator* interpolators, int64_t startDelays,
nsecs_t durations, int repeatCount);
virtual uint32_t dirtyMask();
+ bool isInfinite() { return mIsInfinite; }
+ void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
+ VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable; }
+ AnimationListener* getOneShotListener() { return mOneShotListener.get(); }
+ void clearOneShotListener() { mOneShotListener = nullptr; }
+ uint32_t getRequestId() const { return mRequestId; }
protected:
virtual float getValue(RenderNode* target) const override;
@@ -69,6 +78,11 @@
std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
float mLastFraction = 0.0f;
bool mInitialized = false;
+ VectorDrawableRoot* mVectorDrawable = nullptr;
+ bool mIsInfinite = false;
+ // This request id gets incremented (on UI thread only) when a new request to modfiy the
+ // lifecycle of an animation happens, namely when start/end/reset/reverse is called.
+ uint32_t mRequestId = 0;
};
class PropertyAnimatorSetListener : public AnimationListener {
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b49f9b5..b35c926 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -440,8 +440,8 @@
}
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
- mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
mDisplayList->ref(tree);
+ mDisplayList->vectorDrawables.push_back(tree);
addOp(alloc().create_trivial<VectorDrawableOp>(
tree,
Rect(tree->stagingProperties()->getBounds()),
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6e848fd..0f6c43e 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -419,6 +419,14 @@
prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
pushLayerUpdate(info);
+ for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+ // If any vector drawable in the display list needs update, damage the node.
+ if (vectorDrawable->isDirty()) {
+ damageSelf(info);
+ }
+ vectorDrawable->setPropertyChangeWillBeConsumed(true);
+ }
+
info.damageAccumulator->popTransform();
}
@@ -477,8 +485,8 @@
for (auto& iter : mDisplayList->getFunctors()) {
(*iter.functor)(DrawGlInfo::kModeSync, nullptr);
}
- for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
- (*mDisplayList->getPushStagingFunctors()[i])();
+ for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+ vectorDrawable->syncProperties();
}
}
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index a5d1d4b..e67dfdd 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -673,21 +673,16 @@
void onPropertyChanged(TreeProperties* prop);
TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
const TreeProperties* stagingProperties() const { return &mStagingProperties; }
- PushStagingFunctor* getFunctor() { return &mFunctor;}
// This should only be called from animations on RT
TreeProperties* mutateProperties() { return &mProperties; }
+ // This should always be called from RT.
+ bool isDirty() const { return mCache.dirty; }
+ bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
+ void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
+
private:
- class VectorDrawableFunctor : public PushStagingFunctor {
- public:
- VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
- virtual void operator ()() {
- mTree->syncProperties();
- }
- private:
- Tree* mTree;
- };
SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
@@ -704,8 +699,6 @@
TreeProperties mProperties = TreeProperties(this);
TreeProperties mStagingProperties = TreeProperties(this);
- VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
-
SkPaint mPaint;
struct Cache {
SkBitmap bitmap;
@@ -717,6 +710,8 @@
PropertyChangedListener mPropertyChangedListener
= PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+
+ mutable bool mWillBeConsumed = false;
};
} // namespace VectorDrawable
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e6399d4..597c5c5 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -278,6 +278,7 @@
void CanvasContext::stopDrawing() {
mRenderThread.removeFrameCallback(this);
+ mAnimationContext->detachAnimators();
}
void CanvasContext::notifyFramePending() {