diff options
author | 2016-05-17 16:50:31 -0700 | |
---|---|---|
committer | 2016-06-09 10:27:59 -0700 | |
commit | 718cd3eb70703c43f29ca37907bbf0e153d8cca0 (patch) | |
tree | cf1d4ce2d7c0a2ca19289257d3a8538ecfbaf8cb | |
parent | a2da20d3344010b8f3ca6cc5fea265984662959c (diff) |
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
-rw-r--r-- | core/java/android/view/RenderNode.java | 6 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 8 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 8 | ||||
-rw-r--r-- | core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp | 7 | ||||
-rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 127 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java | 43 | ||||
-rw-r--r-- | graphics/java/android/graphics/drawable/VectorDrawable.java | 7 | ||||
-rw-r--r-- | libs/hwui/AnimationContext.h | 2 | ||||
-rw-r--r-- | libs/hwui/Animator.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Animator.h | 12 | ||||
-rw-r--r-- | libs/hwui/DisplayList.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/DisplayList.h | 21 | ||||
-rw-r--r-- | libs/hwui/DisplayListCanvas.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/PropertyValuesAnimatorSet.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/PropertyValuesAnimatorSet.h | 14 | ||||
-rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/VectorDrawable.h | 19 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 1 |
19 files changed, 262 insertions, 52 deletions
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index ab4cbcf21bed..0164fcd4f016 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -793,12 +793,12 @@ public class RenderNode { return mOwningView != null && mOwningView.mAttachInfo != null; } - public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { + public void registerVectorDrawableAnimator( + AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { if (mOwningView == null || mOwningView.mAttachInfo == null) { throw new IllegalStateException("Cannot start this animator on a detached view!"); } - nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr()); - mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this); + mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet); } public void endAllAnimators() { diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index e650d956915a..fcca7395fe8c 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -23,6 +23,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.drawable.AnimatedVectorDrawable; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -881,6 +882,12 @@ public final class ThreadedRenderer { nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode); } + void registerVectorDrawableAnimator( + AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { + nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode, + animator.getAnimatorNativePtr()); + } + public void serializeDisplayListTree() { nSerializeDisplayListTree(mNativeProxy); } @@ -992,6 +999,7 @@ public final class ThreadedRenderer { private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); private static native void nDestroy(long nativeProxy, long rootRenderNode); private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode); + private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator); private static native void nInvokeFunctor(long functor, boolean waitForCompletion); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 4742818d4be0..06c8e0156249 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -42,6 +42,7 @@ import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; @@ -824,6 +825,13 @@ public final class ViewRootImpl implements ViewParent, } } + public void registerVectorDrawableAnimator( + AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) { + if (mAttachInfo.mHardwareRenderer != null) { + mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator); + } + } + private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { mAttachInfo.mHardwareAccelerated = false; mAttachInfo.mHardwareAccelerationRequested = false; diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp index 4b2a72d8e28e..0ba88e6b066b 100644 --- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp @@ -95,6 +95,12 @@ static jlong createAnimatorSet(JNIEnv*, jobject) { return reinterpret_cast<jlong>(animatorSet); } +static void setVectorDrawableTarget(JNIEnv*, jobject,jlong animatorPtr, jlong vectorDrawablePtr) { + VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(vectorDrawablePtr); + PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr); + set->setVectorDrawable(tree); +} + static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId, jfloat startValue, jfloat endValue) { VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr); @@ -168,6 +174,7 @@ static void reset(JNIEnv*, jobject, jlong animatorSetPtr) { static const JNINativeMethod gMethods[] = { {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet}, + {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget}, {"nAddAnimator", "(JJJJJI)V", (void*)addAnimator}, {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder}, {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder}, diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 5b4bfe96392c..212bf579cfa7 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -32,6 +32,7 @@ #include <utils/Looper.h> #include <utils/RefBase.h> #include <utils/StrongPointer.h> +#include <utils/Timers.h> #include <android_runtime/android_view_Surface.h> #include <system/window.h> @@ -44,6 +45,7 @@ #include <FrameMetricsObserver.h> #include <IContextFactory.h> #include <JankTracker.h> +#include <PropertyValuesAnimatorSet.h> #include <RenderNode.h> #include <renderthread/CanvasContext.h> #include <renderthread/RenderProxy.h> @@ -122,6 +124,31 @@ private: std::vector<OnFinishedEvent> mOnFinishedEvents; }; +class FinishAndInvokeListener : public MessageHandler { +public: + explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim) + : mAnimator(anim) { + mListener = anim->getOneShotListener(); + mRequestId = anim->getRequestId(); + } + + virtual void handleMessage(const Message& message) { + if (mAnimator->getRequestId() == mRequestId) { + // Request Id has not changed, meaning there's no animation lifecyle change since the + // message is posted, so go ahead and call finish to make sure the PlayState is properly + // updated. This is needed because before the next frame comes in from UI thread to + // trigger an animation update, there could be reverse/cancel etc. So we need to update + // the playstate in time to ensure all the subsequent events get chained properly. + mAnimator->end(); + } + mListener->onAnimationFinished(nullptr); + } +private: + sp<PropertyValuesAnimatorSet> mAnimator; + sp<AnimationListener> mListener; + uint32_t mRequestId; +}; + class RenderingException : public MessageHandler { public: RenderingException(JavaVM* vm, const std::string& message) @@ -160,6 +187,15 @@ public: virtual void prepareTree(TreeInfo& info) override { info.errorHandler = this; + + for (auto& anim : mVectorDrawableAnimators) { + // Assume that the property change in VD from the animators will not be consumed. Mark + // otherwise if the VDs are found in the display list tree. For VDs that are not in + // the display list tree, we stop providing animation pulses by 1) removing them from + // the animation list, 2) post a delayed message to end them at end time so their + // listeners can receive the corresponding callbacks. + anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false); + } // TODO: This is hacky info.windowInsetLeft = -stagingProperties().getLeft(); info.windowInsetTop = -stagingProperties().getTop(); @@ -169,16 +205,46 @@ public: info.windowInsetLeft = 0; info.windowInsetTop = 0; info.errorHandler = nullptr; + + for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { + if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) { + // Vector Drawable is not in the display list, we should remove this animator from + // the list and post a delayed message to end the animator. + detachVectorDrawableAnimator(it->get()); + it = mVectorDrawableAnimators.erase(it); + } else { + ++it; + } + } + info.out.hasAnimations |= !mVectorDrawableAnimators.empty(); } void sendMessage(const sp<MessageHandler>& handler) { mLooper->sendMessage(handler, 0); } + void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) { + mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0); + } + void attachAnimatingNode(RenderNode* animatingNode) { mPendingAnimatingRenderNodes.push_back(animatingNode); } + void attachPendingVectorDrawableAnimators() { + mVectorDrawableAnimators.insert(mPendingVectorDrawableAnimators.begin(), + mPendingVectorDrawableAnimators.end()); + mPendingVectorDrawableAnimators.clear(); + } + + void detachAnimators() { + // Remove animators from the list and post a delayed message in future to end the animator + for (auto& anim : mVectorDrawableAnimators) { + detachVectorDrawableAnimator(anim.get()); + } + mVectorDrawableAnimators.clear(); + } + void doAttachAnimatingNodes(AnimationContext* context) { for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) { RenderNode* node = mPendingAnimatingRenderNodes[i].get(); @@ -187,17 +253,57 @@ public: mPendingAnimatingRenderNodes.clear(); } + void runVectorDrawableAnimators(AnimationContext* context) { + for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { + (*it)->pushStaging(*context); + if ((*it)->animate(*context)) { + it = mVectorDrawableAnimators.erase(it); + } else { + ++it; + } + } + } + void destroy() { for (auto& renderNode : mPendingAnimatingRenderNodes) { renderNode->animators().endAllStagingAnimators(); } mPendingAnimatingRenderNodes.clear(); + mPendingVectorDrawableAnimators.clear(); + } + + void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { + mPendingVectorDrawableAnimators.insert(anim); } private: sp<Looper> mLooper; JavaVM* mVm; std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes; + std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators; + std::set< sp<PropertyValuesAnimatorSet> > mVectorDrawableAnimators; + void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { + if (anim->isInfinite() || !anim->isRunning()) { + // Do not need to post anything if the animation is infinite (i.e. no meaningful + // end listener action), or if the animation has already ended. + return; + } + nsecs_t remainingTimeInMs = anim->getRemainingPlayTime(); + // Post a delayed onFinished event that is scheduled to be handled when the animator ends. + if (anim->getOneShotListener()) { + // VectorDrawable's oneshot listener is updated when there are user triggered animation + // lifecycle changes, such as start(), end(), etc. By using checking and clearing + // one shot listener, we ensure the same end listener event gets posted only once. + // Therefore no duplicates. Another benefit of using one shot listener is that no + // removal is necessary: the end time of animation will not change unless triggered by + // user events, in which case the already posted listener's id will become stale, and + // the onFinished callback will then be ignored. + sp<FinishAndInvokeListener> message + = new FinishAndInvokeListener(anim); + sendMessageDelayed(message, remainingTimeInMs); + anim->clearOneShotListener(); + } + } }; class AnimationContextBridge : public AnimationContext { @@ -213,8 +319,16 @@ public: virtual void startFrame(TreeInfo::TraversalMode mode) { if (mode == TreeInfo::MODE_FULL) { mRootNode->doAttachAnimatingNodes(this); + mRootNode->attachPendingVectorDrawableAnimators(); } AnimationContext::startFrame(mode); + // Run VectorDrawable animators in the beginning of the frame instead of during prepareTree, + // because one VD can be in multiple render nodes' display list. So it's more simple to + // run them all at once before prepareTree than running them or checking whether they have + // already ran in each RenderNode. Note that these animators don't damage the RenderNodes. + // The damaging is done in prepareTree as needed after checking whether a VD has been + // modified. + mRootNode->runVectorDrawableAnimators(this); } // Runs any animations still left in mCurrentFrameAnimations @@ -223,6 +337,10 @@ public: postOnFinishedEvents(); } + virtual void detachAnimators() override { + mRootNode->detachAnimators(); + } + virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) { OnFinishedEvent event(animator, listener); mOnFinishedEvents.push_back(event); @@ -230,6 +348,7 @@ public: virtual void destroy() { AnimationContext::destroy(); + detachAnimators(); postOnFinishedEvents(); } @@ -528,6 +647,13 @@ static void android_view_ThreadedRenderer_registerAnimatingRenderNode(JNIEnv* en rootRenderNode->attachAnimatingNode(animatingNode); } +static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz, + jlong rootNodePtr, jlong animatorPtr) { + RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr); + PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr); + rootRenderNode->addVectorDrawableAnimator(animator); +} + static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz, jlong functorPtr, jboolean waitForCompletion) { Functor* functor = reinterpret_cast<Functor*>(functorPtr); @@ -739,6 +865,7 @@ static const JNINativeMethod gMethods[] = { { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy }, { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode }, + { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator }, { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer }, { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer }, diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index 6762bea1ca35..2def8765a49b 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -157,7 +157,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; /** Local, mutable animator set. */ - private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorUI(this); + private VectorDrawableAnimator mAnimatorSet; /** * The resources against which this drawable was created. Used to attempt @@ -182,6 +182,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) { mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res); + mAnimatorSet = new VectorDrawableAnimatorRT(this); mRes = res; } @@ -999,7 +1000,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private WeakReference<RenderNode> mLastSeenTarget = null; private int mLastListenerId = 0; private final IntArray mPendingAnimationActions = new IntArray(); - private final Drawable mDrawable; + private final AnimatedVectorDrawable mDrawable; VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) { mDrawable = drawable; @@ -1018,6 +1019,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation(); parseAnimatorSet(set, 0); + long vectorDrawableTreePtr = mDrawable.mAnimatedVectorState.mVectorDrawable + .getNativeTree(); + nSetVectorDrawableTarget(mSetPtr, vectorDrawableTreePtr); mInitialized = true; mIsInfinite = set.getTotalDuration() == Animator.DURATION_INFINITE; @@ -1254,16 +1258,19 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * to the last seen RenderNode target and start right away. */ protected void recordLastSeenTarget(DisplayListCanvas canvas) { - mLastSeenTarget = new WeakReference<RenderNode>( - RenderNodeAnimatorSetHelper.getTarget(canvas)); - if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) { - if (DBG_ANIMATION_VECTOR_DRAWABLE) { - Log.d(LOGTAG, "Target is set in the next frame"); - } - for (int i = 0; i < mPendingAnimationActions.size(); i++) { - handlePendingAction(mPendingAnimationActions.get(i)); + final RenderNode node = RenderNodeAnimatorSetHelper.getTarget(canvas); + mLastSeenTarget = new WeakReference<RenderNode>(node); + // Add the animator to the list of animators on every draw + if (mInitialized || mPendingAnimationActions.size() > 0) { + if (useTarget(node)) { + if (DBG_ANIMATION_VECTOR_DRAWABLE) { + Log.d(LOGTAG, "Target is set in the next frame"); + } + for (int i = 0; i < mPendingAnimationActions.size(); i++) { + handlePendingAction(mPendingAnimationActions.get(i)); + } + mPendingAnimationActions.clear(); } - mPendingAnimationActions.clear(); } } @@ -1285,10 +1292,15 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private boolean useLastSeenTarget() { if (mLastSeenTarget != null) { final RenderNode target = mLastSeenTarget.get(); - if (target != null && target.isAttached()) { - target.addAnimator(this); - return true; - } + return useTarget(target); + } + return false; + } + + private boolean useTarget(RenderNode target) { + if (target != null && target.isAttached()) { + target.registerVectorDrawableAnimator(this); + return true; } return false; } @@ -1483,6 +1495,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } private static native long nCreateAnimatorSet(); + private static native void nSetVectorDrawableTarget(long animatorPtr, long vectorDrawablePtr); private static native void nAddAnimator(long setPtr, long propertyValuesHolder, long nativeInterpolator, long startDelay, long duration, int repeatCount); diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index f5592fa7e407..283a83dfa23d 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -758,6 +758,13 @@ public class VectorDrawable extends Drawable { return mVectorState.mAutoMirrored; } + /** + * @hide + */ + public long getNativeTree() { + return mVectorState.getNativeRenderer(); + } + static class VectorDrawableState extends ConstantState { // Variables below need to be copied (deep copy if applicable) for mutation. int[] mThemeAttrs; diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h index 909ed36a2127..801fd8719a14 100644 --- a/libs/hwui/AnimationContext.h +++ b/libs/hwui/AnimationContext.h @@ -100,6 +100,8 @@ public: 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 4d65782f684b..dc180188100b 100644 --- a/libs/hwui/Animator.cpp +++ b/libs/hwui/Animator.cpp @@ -274,6 +274,10 @@ bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) { 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 fdae0f32d4e6..9476750afd52 100644 --- a/libs/hwui/Animator.h +++ b/libs/hwui/Animator.h @@ -62,19 +62,23 @@ public: } 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 b572bdaccb86..28be05c52cfc 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -45,7 +45,7 @@ DisplayList::DisplayList() , 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 5b3227b7db97..ccf71c6d360b 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -69,6 +69,11 @@ typedef DisplayListOp BaseOpType; 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 @@ struct ReplayStateStruct : public PlaybackStateStruct { 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 @@ public: 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 @@ private: // 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 ca968cef91b2..bec662959f91 100644 --- a/libs/hwui/DisplayListCanvas.cpp +++ b/libs/hwui/DisplayListCanvas.cpp @@ -417,7 +417,7 @@ void DisplayListCanvas::drawPoints(const float* points, int count, const SkPaint 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 b29f91ff34aa..e416e0c0061d 100644 --- a/libs/hwui/PropertyValuesAnimatorSet.cpp +++ b/libs/hwui/PropertyValuesAnimatorSet.cpp @@ -30,6 +30,11 @@ void PropertyValuesAnimatorSet::addPropertyAnimator(PropertyValuesHolder* proper 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::onPlayTimeChanged(nsecs_t playTime) { 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 c7ae7c0e8ce1..49021bc82825 100644 --- a/libs/hwui/PropertyValuesAnimatorSet.h +++ b/libs/hwui/PropertyValuesAnimatorSet.h @@ -43,6 +43,7 @@ private: 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 @@ public: 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 @@ private: 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 b49f9b529989..b35c92612a42 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -440,8 +440,8 @@ void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) { } 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 6e848fddf48f..0f6c43e9a2c6 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -419,6 +419,14 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) { 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 @@ void RenderNode::syncDisplayList(TreeObserver* observer) { 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 a5d1d4b86673..e67dfdd15703 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -673,21 +673,16 @@ public: 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 @@ private: TreeProperties mProperties = TreeProperties(this); TreeProperties mStagingProperties = TreeProperties(this); - VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this); - SkPaint mPaint; struct Cache { SkBitmap bitmap; @@ -717,6 +710,8 @@ private: 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 e6399d4ec789..597c5c56eec2 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -278,6 +278,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, void CanvasContext::stopDrawing() { mRenderThread.removeFrameCallback(this); + mAnimationContext->detachAnimators(); } void CanvasContext::notifyFramePending() { |