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