diff options
-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() { |