diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 595d5c61b8e8d..037ca73325def 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -188,7 +188,7 @@ public: virtual void prepareTree(TreeInfo& info) override { info.errorHandler = this; - for (auto& anim : mVectorDrawableAnimators) { + for (auto& anim : mRunningVDAnimators) { // 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 @@ -196,6 +196,11 @@ public: // listeners can receive the corresponding callbacks. anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false); } + if (info.mode == TreeInfo::MODE_FULL) { + for (auto &anim : mPausedVDAnimators) { + anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false); + } + } // TODO: This is hacky info.windowInsetLeft = -stagingProperties().getLeft(); info.windowInsetTop = -stagingProperties().getTop(); @@ -206,17 +211,33 @@ public: info.windowInsetTop = 0; info.errorHandler = nullptr; - for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { + for (auto it = mRunningVDAnimators.begin(); it != mRunningVDAnimators.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. + // the list, put it in the paused list, and post a delayed message to end the + // animator. detachVectorDrawableAnimator(it->get()); - it = mVectorDrawableAnimators.erase(it); + mPausedVDAnimators.insert(*it); + it = mRunningVDAnimators.erase(it); } else { - ++it; + it++; } } - info.out.hasAnimations |= !mVectorDrawableAnimators.empty(); + + if (info.mode == TreeInfo::MODE_FULL) { + // Check whether any paused animator's target is back in Display List. If so, put the + // animator back in the running list. + for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) { + if ((*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) { + mRunningVDAnimators.insert(*it); + it = mPausedVDAnimators.erase(it); + } else { + it++; + } + } + } + info.out.hasAnimations |= !mRunningVDAnimators.empty(); + } void sendMessage(const sp& handler) { @@ -232,17 +253,18 @@ public: } void attachPendingVectorDrawableAnimators() { - mVectorDrawableAnimators.insert(mPendingVectorDrawableAnimators.begin(), + mRunningVDAnimators.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) { + for (auto& anim : mRunningVDAnimators) { detachVectorDrawableAnimator(anim.get()); } - mVectorDrawableAnimators.clear(); + mRunningVDAnimators.clear(); + mPausedVDAnimators.clear(); } void doAttachAnimatingNodes(AnimationContext* context) { @@ -253,18 +275,48 @@ public: mPendingAnimatingRenderNodes.clear(); } - void runVectorDrawableAnimators(AnimationContext* context) { - for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) { + void runVectorDrawableAnimators(AnimationContext* context, TreeInfo::TraversalMode mode) { + for (auto it = mRunningVDAnimators.begin(); it != mRunningVDAnimators.end();) { if ((*it)->animate(*context)) { - it = mVectorDrawableAnimators.erase(it); + it = mRunningVDAnimators.erase(it); } else { - ++it; + it++; + } + } + + if (mode == TreeInfo::MODE_FULL) { + // During full sync we also need to pulse paused animators, in case their targets + // have been added back to the display list. All the animators that passed the + // scheduled finish time will be removed from the paused list. + for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) { + if ((*it)->animate(*context)) { + // Animator has finished, remove from the list. + it = mPausedVDAnimators.erase(it); + } else { + it++; + } + } + } + } + + void trimPausedVDAnimators(AnimationContext* context) { + // Trim paused vector drawable animator list. + for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) { + // Remove paused VD animator if no one else is referencing it. Note that animators that + // have passed scheduled finish time are removed from list when they are being pulsed + // before prepare tree. + // TODO: this is a bit hacky, need to figure out a better way to track when the paused + // animators should be freed. + if ((*it)->getStrongCount() == 1) { + it = mPausedVDAnimators.erase(it); + } else { + it++; } } } void pushStagingVectorDrawableAnimators(AnimationContext* context) { - for (auto& anim : mVectorDrawableAnimators) { + for (auto& anim : mRunningVDAnimators) { anim->pushStaging(*context); } } @@ -286,7 +338,15 @@ private: JavaVM* mVm; std::vector< sp > mPendingAnimatingRenderNodes; std::set< sp > mPendingVectorDrawableAnimators; - std::set< sp > mVectorDrawableAnimators; + std::set< sp > mRunningVDAnimators; + // mPausedVDAnimators stores a list of animators that have not yet passed the finish time, but + // their VectorDrawable targets are no longer in the DisplayList. We skip these animators when + // render thread runs animators independent of UI thread (i.e. RT_ONLY mode). These animators + // need to be re-activated once their VD target is added back into DisplayList. Since that could + // only happen when we do a full sync, we need to make sure to pulse these paused animators at + // full sync. If any animator's VD target is found in DisplayList during a full sync, we move + // the animator back to the running list. + std::set< sp > mPausedVDAnimators; void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { if (anim->isInfinite() || !anim->isRunning()) { // Do not need to post anything if the animation is infinite (i.e. no meaningful @@ -336,13 +396,20 @@ public: if (mode == TreeInfo::MODE_FULL) { mRootNode->pushStagingVectorDrawableAnimators(this); } - mRootNode->runVectorDrawableAnimators(this); + mRootNode->runVectorDrawableAnimators(this, mode); } // Runs any animations still left in mCurrentFrameAnimations virtual void runRemainingAnimations(TreeInfo& info) { AnimationContext::runRemainingAnimations(info); postOnFinishedEvents(); + if (info.mode == TreeInfo::MODE_FULL) { + // Trim paused VD animators at full sync, so that when Java loses reference to an + // animator, we know we won't be requested to animate it any more, then we remove such + // animators from the paused list so they can be properly freed. We also remove the + // animators from paused list when the time elapsed since start has exceeded duration. + mRootNode->trimPausedVDAnimators(this); + } } virtual void detachAnimators() override {