1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "RootRenderNode.h"
18 
19 #ifdef __ANDROID__ // Layoutlib does not support Looper (windows)
20 #include <utils/Looper.h>
21 #endif
22 
23 namespace android::uirenderer {
24 
25 #ifdef __ANDROID__ // Layoutlib does not support Looper
26 class FinishAndInvokeListener : public MessageHandler {
27 public:
FinishAndInvokeListener(PropertyValuesAnimatorSet * anim)28     explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim) : mAnimator(anim) {
29         mListener = anim->getOneShotListener();
30         mRequestId = anim->getRequestId();
31     }
32 
handleMessage(const Message & message)33     virtual void handleMessage(const Message& message) {
34         if (mAnimator->getRequestId() == mRequestId) {
35             // Request Id has not changed, meaning there's no animation lifecyle change since the
36             // message is posted, so go ahead and call finish to make sure the PlayState is properly
37             // updated. This is needed because before the next frame comes in from UI thread to
38             // trigger an animation update, there could be reverse/cancel etc. So we need to update
39             // the playstate in time to ensure all the subsequent events get chained properly.
40             mAnimator->end();
41         }
42         mListener->onAnimationFinished(nullptr);
43     }
44 
45 private:
46     sp<PropertyValuesAnimatorSet> mAnimator;
47     sp<AnimationListener> mListener;
48     uint32_t mRequestId;
49 };
50 
prepareTree(TreeInfo & info)51 void RootRenderNode::prepareTree(TreeInfo& info) {
52     info.errorHandler = mErrorHandler.get();
53 
54     for (auto& anim : mRunningVDAnimators) {
55         // Assume that the property change in VD from the animators will not be consumed. Mark
56         // otherwise if the VDs are found in the display list tree. For VDs that are not in
57         // the display list tree, we stop providing animation pulses by 1) removing them from
58         // the animation list, 2) post a delayed message to end them at end time so their
59         // listeners can receive the corresponding callbacks.
60         anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false);
61         // Mark the VD dirty so it will damage itself during prepareTree.
62         anim->getVectorDrawable()->markDirty();
63     }
64     if (info.mode == TreeInfo::MODE_FULL) {
65         for (auto& anim : mPausedVDAnimators) {
66             anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false);
67             anim->getVectorDrawable()->markDirty();
68         }
69     }
70     // TODO: This is hacky
71     info.updateWindowPositions = true;
72     RenderNode::prepareTree(info);
73     info.updateWindowPositions = false;
74     info.errorHandler = nullptr;
75 }
76 
attachAnimatingNode(RenderNode * animatingNode)77 void RootRenderNode::attachAnimatingNode(RenderNode* animatingNode) {
78     mPendingAnimatingRenderNodes.push_back(animatingNode);
79 }
80 
attachPendingVectorDrawableAnimators()81 void RootRenderNode::attachPendingVectorDrawableAnimators() {
82     mRunningVDAnimators.insert(mPendingVectorDrawableAnimators.begin(),
83                                mPendingVectorDrawableAnimators.end());
84     mPendingVectorDrawableAnimators.clear();
85 }
86 
detachAnimators()87 void RootRenderNode::detachAnimators() {
88     // Remove animators from the list and post a delayed message in future to end the animator
89     // For infinite animators, remove the listener so we no longer hold a global ref to the AVD
90     // java object, and therefore the AVD objects in both native and Java can be properly
91     // released.
92     for (auto& anim : mRunningVDAnimators) {
93         detachVectorDrawableAnimator(anim.get());
94         anim->clearOneShotListener();
95     }
96     for (auto& anim : mPausedVDAnimators) {
97         anim->clearOneShotListener();
98     }
99     mRunningVDAnimators.clear();
100     mPausedVDAnimators.clear();
101 }
102 
103 // Move all the animators to the paused list, and send a delayed message to notify the finished
104 // listener.
pauseAnimators()105 void RootRenderNode::pauseAnimators() {
106     mPausedVDAnimators.insert(mRunningVDAnimators.begin(), mRunningVDAnimators.end());
107     for (auto& anim : mRunningVDAnimators) {
108         detachVectorDrawableAnimator(anim.get());
109     }
110     mRunningVDAnimators.clear();
111 }
112 
doAttachAnimatingNodes(AnimationContext * context)113 void RootRenderNode::doAttachAnimatingNodes(AnimationContext* context) {
114     for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
115         RenderNode* node = mPendingAnimatingRenderNodes[i].get();
116         context->addAnimatingRenderNode(*node);
117     }
118     mPendingAnimatingRenderNodes.clear();
119 }
120 
121 // Run VectorDrawable animators after prepareTree.
runVectorDrawableAnimators(AnimationContext * context,TreeInfo & info)122 void RootRenderNode::runVectorDrawableAnimators(AnimationContext* context, TreeInfo& info) {
123     // Push staging.
124     if (info.mode == TreeInfo::MODE_FULL) {
125         pushStagingVectorDrawableAnimators(context);
126     }
127 
128     // Run the animators in the running list.
129     for (auto it = mRunningVDAnimators.begin(); it != mRunningVDAnimators.end();) {
130         if ((*it)->animate(*context)) {
131             it = mRunningVDAnimators.erase(it);
132         } else {
133             it++;
134         }
135     }
136 
137     // Run the animators in paused list during full sync.
138     if (info.mode == TreeInfo::MODE_FULL) {
139         // During full sync we also need to pulse paused animators, in case their targets
140         // have been added back to the display list. All the animators that passed the
141         // scheduled finish time will be removed from the paused list.
142         for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) {
143             if ((*it)->animate(*context)) {
144                 // Animator has finished, remove from the list.
145                 it = mPausedVDAnimators.erase(it);
146             } else {
147                 it++;
148             }
149         }
150     }
151 
152     // Move the animators with a target not in DisplayList to paused list.
153     for (auto it = mRunningVDAnimators.begin(); it != mRunningVDAnimators.end();) {
154         if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) {
155             // Vector Drawable is not in the display list, we should remove this animator from
156             // the list, put it in the paused list, and post a delayed message to end the
157             // animator.
158             detachVectorDrawableAnimator(it->get());
159             mPausedVDAnimators.insert(*it);
160             it = mRunningVDAnimators.erase(it);
161         } else {
162             it++;
163         }
164     }
165 
166     // Move the animators with a target in DisplayList from paused list to running list, and
167     // trim paused list.
168     if (info.mode == TreeInfo::MODE_FULL) {
169         // Check whether any paused animator's target is back in Display List. If so, put the
170         // animator back in the running list.
171         for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) {
172             if ((*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) {
173                 mRunningVDAnimators.insert(*it);
174                 it = mPausedVDAnimators.erase(it);
175             } else {
176                 it++;
177             }
178         }
179         // Trim paused VD animators at full sync, so that when Java loses reference to an
180         // animator, we know we won't be requested to animate it any more, then we remove such
181         // animators from the paused list so they can be properly freed. We also remove the
182         // animators from paused list when the time elapsed since start has exceeded duration.
183         trimPausedVDAnimators(context);
184     }
185 
186     info.out.hasAnimations |= !mRunningVDAnimators.empty();
187 }
188 
trimPausedVDAnimators(AnimationContext * context)189 void RootRenderNode::trimPausedVDAnimators(AnimationContext* context) {
190     // Trim paused vector drawable animator list.
191     for (auto it = mPausedVDAnimators.begin(); it != mPausedVDAnimators.end();) {
192         // Remove paused VD animator if no one else is referencing it. Note that animators that
193         // have passed scheduled finish time are removed from list when they are being pulsed
194         // before prepare tree.
195         // TODO: this is a bit hacky, need to figure out a better way to track when the paused
196         // animators should be freed.
197         if ((*it)->getStrongCount() == 1) {
198             it = mPausedVDAnimators.erase(it);
199         } else {
200             it++;
201         }
202     }
203 }
204 
pushStagingVectorDrawableAnimators(AnimationContext * context)205 void RootRenderNode::pushStagingVectorDrawableAnimators(AnimationContext* context) {
206     for (auto& anim : mRunningVDAnimators) {
207         anim->pushStaging(*context);
208     }
209 }
210 
destroy()211 void RootRenderNode::destroy() {
212     for (auto& renderNode : mPendingAnimatingRenderNodes) {
213         renderNode->animators().endAllStagingAnimators();
214     }
215     mPendingAnimatingRenderNodes.clear();
216     mPendingVectorDrawableAnimators.clear();
217 }
218 
addVectorDrawableAnimator(PropertyValuesAnimatorSet * anim)219 void RootRenderNode::addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
220     mPendingVectorDrawableAnimators.insert(anim);
221 }
222 
detachVectorDrawableAnimator(PropertyValuesAnimatorSet * anim)223 void RootRenderNode::detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
224     if (anim->isInfinite() || !anim->isRunning()) {
225         // Do not need to post anything if the animation is infinite (i.e. no meaningful
226         // end listener action), or if the animation has already ended.
227         return;
228     }
229     nsecs_t remainingTimeInMs = anim->getRemainingPlayTime();
230     // Post a delayed onFinished event that is scheduled to be handled when the animator ends.
231     if (anim->getOneShotListener()) {
232         // VectorDrawable's oneshot listener is updated when there are user triggered animation
233         // lifecycle changes, such as start(), end(), etc. By using checking and clearing
234         // one shot listener, we ensure the same end listener event gets posted only once.
235         // Therefore no duplicates. Another benefit of using one shot listener is that no
236         // removal is necessary: the end time of animation will not change unless triggered by
237         // user events, in which case the already posted listener's id will become stale, and
238         // the onFinished callback will then be ignored.
239         sp<FinishAndInvokeListener> message = new FinishAndInvokeListener(anim);
240         auto looper = Looper::getForThread();
241         LOG_ALWAYS_FATAL_IF(looper == nullptr, "Not on a looper thread?");
242         looper->sendMessageDelayed(ms2ns(remainingTimeInMs), message, 0);
243         anim->clearOneShotListener();
244     }
245 }
246 
247 class AnimationContextBridge : public AnimationContext {
248 public:
AnimationContextBridge(renderthread::TimeLord & clock,RootRenderNode * rootNode)249     AnimationContextBridge(renderthread::TimeLord& clock, RootRenderNode* rootNode)
250             : AnimationContext(clock), mRootNode(rootNode) {}
251 
~AnimationContextBridge()252     virtual ~AnimationContextBridge() {}
253 
254     // Marks the start of a frame, which will update the frame time and move all
255     // next frame animations into the current frame
startFrame(TreeInfo::TraversalMode mode)256     virtual void startFrame(TreeInfo::TraversalMode mode) {
257         if (mode == TreeInfo::MODE_FULL) {
258             mRootNode->doAttachAnimatingNodes(this);
259             mRootNode->attachPendingVectorDrawableAnimators();
260         }
261         AnimationContext::startFrame(mode);
262     }
263 
264     // Runs any animations still left in mCurrentFrameAnimations
runRemainingAnimations(TreeInfo & info)265     virtual void runRemainingAnimations(TreeInfo& info) {
266         AnimationContext::runRemainingAnimations(info);
267         mRootNode->runVectorDrawableAnimators(this, info);
268     }
269 
pauseAnimators()270     virtual void pauseAnimators() override { mRootNode->pauseAnimators(); }
271 
callOnFinished(BaseRenderNodeAnimator * animator,AnimationListener * listener)272     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
273         listener->onAnimationFinished(animator);
274     }
275 
destroy()276     virtual void destroy() {
277         AnimationContext::destroy();
278         mRootNode->detachAnimators();
279     }
280 
281 private:
282     sp<RootRenderNode> mRootNode;
283 };
284 
createAnimationContext(renderthread::TimeLord & clock)285 AnimationContext* ContextFactoryImpl::createAnimationContext(renderthread::TimeLord& clock) {
286     return new AnimationContextBridge(clock, mRootNode);
287 }
288 #else
289 
290 void RootRenderNode::prepareTree(TreeInfo& info) {
291     info.errorHandler = mErrorHandler.get();
292     info.updateWindowPositions = true;
293     RenderNode::prepareTree(info);
294     info.updateWindowPositions = false;
295     info.errorHandler = nullptr;
296 }
297 
298 void RootRenderNode::attachAnimatingNode(RenderNode* animatingNode) { }
299 
300 void RootRenderNode::destroy() { }
301 
302 void RootRenderNode::addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { }
303 
304 #endif
305 
306 }  // namespace android::uirenderer
307