1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "animation/rs_interactive_implict_animator.h"
17
18 #include "platform/common/rs_log.h"
19 #include "sandbox_utils.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 enum class StartAnimationErrorCode : int32_t {
24 SUCCESS = 0,
25 INVALID_STATUS,
26 INVALID_ANIMATIONS,
27 INVALID_PROXY,
28 INVALID_CONTEXT,
29 };
30
31 static bool g_isUniRenderEnabled = false;
32
GenerateId()33 InteractiveImplictAnimatorId RSInteractiveImplictAnimator::GenerateId()
34 {
35 static pid_t pid_ = GetRealPid();
36 static std::atomic<uint32_t> currentId_ = 0;
37
38 auto currentId = currentId_.fetch_add(1, std::memory_order_relaxed);
39 if (currentId == UINT32_MAX) {
40 ROSEN_LOGE("InteractiveImplictAnimatorId Id overflow");
41 }
42
43 // concat two 32-bit numbers to one 64-bit number
44 return ((InteractiveImplictAnimatorId)pid_ << 32) | (currentId);
45 }
46
Create(const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)47 std::shared_ptr<RSInteractiveImplictAnimator> RSInteractiveImplictAnimator::Create(
48 const RSAnimationTimingProtocol& timingProtocol, const RSAnimationTimingCurve& timingCurve)
49 {
50 return std::shared_ptr<RSInteractiveImplictAnimator>(
51 new RSInteractiveImplictAnimator(nullptr, timingProtocol, timingCurve));
52 }
53
Create(const std::shared_ptr<RSUIContext> rsUIContext,const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)54 std::shared_ptr<RSInteractiveImplictAnimator> RSInteractiveImplictAnimator::Create(
55 const std::shared_ptr<RSUIContext> rsUIContext, const RSAnimationTimingProtocol& timingProtocol,
56 const RSAnimationTimingCurve& timingCurve)
57 {
58 return std::shared_ptr<RSInteractiveImplictAnimator>(
59 new RSInteractiveImplictAnimator(rsUIContext, timingProtocol, timingCurve));
60 }
61
RSInteractiveImplictAnimator(const std::shared_ptr<RSUIContext> rsUIContext,const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)62 RSInteractiveImplictAnimator::RSInteractiveImplictAnimator(
63 const std::shared_ptr<RSUIContext> rsUIContext, const RSAnimationTimingProtocol& timingProtocol,
64 const RSAnimationTimingCurve& timingCurve)
65 : id_(GenerateId()), rsUIContext_(rsUIContext), timingProtocol_(timingProtocol), timingCurve_(timingCurve)
66 {
67 InitUniRenderEnabled();
68 }
69
~RSInteractiveImplictAnimator()70 RSInteractiveImplictAnimator::~RSInteractiveImplictAnimator()
71 {
72 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorDestory>(id_);
73 AddCommand(command, IsUniRenderEnabled());
74 if (!IsUniRenderEnabled()) {
75 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorDestory>(id_);
76 AddCommand(commandForRemote, true);
77 }
78 }
79
IsUniRenderEnabled() const80 bool RSInteractiveImplictAnimator::IsUniRenderEnabled() const
81 {
82 return g_isUniRenderEnabled;
83 }
84
InitUniRenderEnabled()85 void RSInteractiveImplictAnimator::InitUniRenderEnabled()
86 {
87 static bool inited = false;
88 if (!inited) {
89 inited = true;
90 g_isUniRenderEnabled = RSSystemProperties::GetUniRenderEnabled();
91 ROSEN_LOGD("RSInteractiveImplictAnimator::InitUniRenderEnabled:%{public}d", g_isUniRenderEnabled);
92 }
93 }
94
GetAnimatorFinishCallback()95 std::shared_ptr<InteractiveAnimatorFinishCallback> RSInteractiveImplictAnimator::GetAnimatorFinishCallback()
96 {
97 auto callback = animatorCallback_.lock();
98 if (callback) {
99 return callback;
100 }
101 auto animatorCallback = std::make_shared<InteractiveAnimatorFinishCallback>([weak = weak_from_this()]() {
102 auto self = weak.lock();
103 if (self) {
104 self->CallFinishCallback();
105 }
106 });
107 animatorCallback_ = animatorCallback;
108 return animatorCallback;
109 }
110
AddImplictAnimation(std::function<void ()> callback)111 size_t RSInteractiveImplictAnimator::AddImplictAnimation(std::function<void()> callback)
112 {
113 if (state_ != RSInteractiveAnimationState::INACTIVE && state_ != RSInteractiveAnimationState::ACTIVE) {
114 ROSEN_LOGE("AddAnimation failed, state_ is error");
115 return 0;
116 }
117 auto rsUIContext = rsUIContext_.lock();
118 auto implicitAnimator = rsUIContext ? rsUIContext->GetRSImplicitAnimator() :
119 RSImplicitAnimatorMap::Instance().GetAnimator(gettid());
120 if (implicitAnimator == nullptr) {
121 ROSEN_LOGE("Failed to open implicit animation, implicit animator is null!");
122 return 0;
123 }
124
125 if (timingProtocol_.GetDuration() <= 0) {
126 return 0;
127 }
128
129 implicitAnimator->OpenInterActiveImplicitAnimation(true, timingProtocol_, timingCurve_, nullptr);
130 callback();
131 auto animations = implicitAnimator->CloseInterActiveImplicitAnimation(true);
132
133 for (auto& [animation, nodeId] : animations) {
134 if (fractionAnimationId_ == 0 && animation->IsSupportInteractiveAnimator()) {
135 fractionAnimationId_ = animation->GetId();
136 fractionNodeId_ = nodeId;
137 }
138 std::weak_ptr<RSAnimation> weakAnimation = animation;
139 animation->SetInteractiveFinishCallback(GetAnimatorFinishCallback());
140 animations_.emplace_back(weakAnimation, nodeId);
141 }
142 state_ = RSInteractiveAnimationState::ACTIVE;
143 return animations.size();
144 }
145
AddAnimation(std::function<void ()> callback)146 size_t RSInteractiveImplictAnimator::AddAnimation(std::function<void()> callback)
147 {
148 if (state_ != RSInteractiveAnimationState::INACTIVE && state_ != RSInteractiveAnimationState::ACTIVE) {
149 ROSEN_LOGE("AddAnimation failed, state_ is error");
150 return 0;
151 }
152 auto rsUIContext = rsUIContext_.lock();
153 auto implicitAnimator = rsUIContext ? rsUIContext->GetRSImplicitAnimator() :
154 RSImplicitAnimatorMap::Instance().GetAnimator(gettid());
155 if (implicitAnimator == nullptr) {
156 ROSEN_LOGE("Failed to open implicit animation, implicit animator is null!");
157 return 0;
158 }
159
160 implicitAnimator->OpenInterActiveImplicitAnimation(false, timingProtocol_, timingCurve_, nullptr);
161 callback();
162 auto animations = implicitAnimator->CloseInterActiveImplicitAnimation(false);
163
164 for (auto& [animation, nodeId] : animations) {
165 if (fractionAnimationId_ == 0 && animation->IsSupportInteractiveAnimator()) {
166 fractionAnimationId_ = animation->GetId();
167 fractionNodeId_ = nodeId;
168 }
169 std::weak_ptr<RSAnimation> weakAnimation = animation;
170 animation->SetInteractiveFinishCallback(GetAnimatorFinishCallback());
171 animations_.emplace_back(weakAnimation, nodeId);
172 }
173 state_ = RSInteractiveAnimationState::ACTIVE;
174 return animations.size();
175 }
176
StartAnimation()177 int32_t RSInteractiveImplictAnimator::StartAnimation()
178 {
179 if (state_ != RSInteractiveAnimationState::ACTIVE) {
180 ROSEN_LOGE("StartAnimation failed, state_ is error");
181 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_STATUS);
182 }
183
184 if (animations_.empty()) {
185 ROSEN_LOGE("StartAnimation failed, animations size is error");
186 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_ANIMATIONS);
187 }
188 auto rsUIContext = rsUIContext_.lock();
189 std::vector<std::pair<NodeId, AnimationId>> renderAnimations;
190 for (auto& [item, nodeId] : animations_) {
191 auto animation = item.lock();
192 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
193 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
194 if (target != nullptr && animation != nullptr) {
195 animation->InteractiveContinue();
196 if (!animation->IsUiAnimation()) {
197 renderAnimations.emplace_back(nodeId, animation->GetId());
198 }
199 }
200 }
201 state_ = RSInteractiveAnimationState::RUNNING;
202
203 auto transactionProxy = RSTransactionProxy::GetInstance();
204 if (transactionProxy == nullptr) {
205 ROSEN_LOGE("Failed to start interactive animation, transaction proxy is null!");
206 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_PROXY);
207 }
208 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorCreate>(id_, renderAnimations, true);
209 AddCommand(command, IsUniRenderEnabled());
210 if (!IsUniRenderEnabled()) {
211 std::unique_ptr<RSCommand> commandForRemote =
212 std::make_unique<RSInteractiveAnimatorCreate>(id_, renderAnimations, true);
213 AddCommand(commandForRemote, true);
214 }
215 return static_cast<int32_t>(StartAnimationErrorCode::SUCCESS);
216 }
217
PauseAnimation()218 void RSInteractiveImplictAnimator::PauseAnimation()
219 {
220 if (state_ != RSInteractiveAnimationState::RUNNING) {
221 ROSEN_LOGE("PauseAnimation failed, state_ is error");
222 return;
223 }
224 state_ = RSInteractiveAnimationState::PAUSED;
225
226 auto rsUIContext = rsUIContext_.lock();
227 for (auto& [item, nodeId] : animations_) {
228 auto animation = item.lock();
229 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
230 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
231 if (target != nullptr && animation != nullptr) {
232 animation->InteractivePause();
233 }
234 }
235 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorPause>(id_);
236 AddCommand(command, IsUniRenderEnabled());
237 if (!IsUniRenderEnabled()) {
238 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorPause>(id_);
239 AddCommand(commandForRemote, true);
240 }
241 }
242
ContinueAnimation()243 void RSInteractiveImplictAnimator::ContinueAnimation()
244 {
245 if (state_ != RSInteractiveAnimationState::PAUSED) {
246 ROSEN_LOGE("ContinueAnimation failed, state_ is error");
247 return;
248 }
249
250 state_ = RSInteractiveAnimationState::RUNNING;
251
252 auto rsUIContext = rsUIContext_.lock();
253 for (auto& [item, nodeId] : animations_) {
254 auto animation = item.lock();
255 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
256 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
257 if (target != nullptr && animation != nullptr) {
258 animation->InteractiveContinue();
259 }
260 }
261
262 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorContinue>(id_);
263 AddCommand(command, IsUniRenderEnabled());
264 if (!IsUniRenderEnabled()) {
265 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorContinue>(id_);
266 AddCommand(commandForRemote, true);
267 }
268 }
269
FinishAnimation(RSInteractiveAnimationPosition position)270 void RSInteractiveImplictAnimator::FinishAnimation(RSInteractiveAnimationPosition position)
271 {
272 if (state_ != RSInteractiveAnimationState::RUNNING && state_ != RSInteractiveAnimationState::PAUSED) {
273 ROSEN_LOGE("FinishAnimation failed, state_ is error");
274 return;
275 }
276 state_ = RSInteractiveAnimationState::INACTIVE;
277
278 auto rsUIContext = rsUIContext_.lock();
279 if (position == RSInteractiveAnimationPosition::START || position == RSInteractiveAnimationPosition::END) {
280 for (auto& [item, nodeId] : animations_) {
281 auto animation = item.lock();
282 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
283 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
284 if (target == nullptr || animation == nullptr) {
285 continue;
286 }
287 animation->InteractiveFinish(position);
288 }
289 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorFinish>(id_, position);
290 AddCommand(command, IsUniRenderEnabled());
291 if (!IsUniRenderEnabled()) {
292 std::unique_ptr<RSCommand> commandForRemote =
293 std::make_unique<RSInteractiveAnimatorFinish>(id_, position);
294 AddCommand(commandForRemote, true);
295 }
296 } else if (position == RSInteractiveAnimationPosition::CURRENT) {
297 FinishOnCurrent();
298 }
299 }
300
FinishOnCurrent()301 void RSInteractiveImplictAnimator::FinishOnCurrent()
302 {
303 auto rsUIContext = rsUIContext_.lock();
304 RSNodeGetShowingPropertiesAndCancelAnimation::PropertiesMap propertiesMap;
305 for (auto& [item, nodeId] : animations_) {
306 auto animation = item.lock();
307 auto node = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
308 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
309 if (node == nullptr || animation == nullptr) {
310 continue;
311 }
312 if (!node->HasPropertyAnimation(animation->GetPropertyId()) || animation->IsUiAnimation()) {
313 continue;
314 }
315 propertiesMap.emplace(std::make_pair<NodeId, PropertyId>(node->GetId(), animation->GetPropertyId()),
316 std::make_pair<std::shared_ptr<RSRenderPropertyBase>, std::vector<AnimationId>>(
317 nullptr, {animation->GetId()}));
318 }
319 if (propertiesMap.size() == 0) {
320 return;
321 }
322 auto task = std::make_shared<RSNodeGetShowingPropertiesAndCancelAnimation>(1e8, std::move(propertiesMap));
323 RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task, IsUniRenderEnabled());
324 if (!task || !task->IsSuccess()) {
325 return;
326 }
327 for (const auto& [key, value] : task->GetProperties()) {
328 const auto& [nodeId, propertyId] = key;
329 auto node = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
330 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
331 if (node == nullptr) {
332 continue;
333 }
334 std::shared_ptr<RSPropertyBase> property = nullptr;
335 if (auto prop = node->GetPropertyById(propertyId)) {
336 property = prop;
337 }
338 if (property == nullptr) {
339 continue;
340 }
341 const auto& [propertyValue, animations] = value;
342 if (propertyValue != nullptr) {
343 property->SetValueFromRender(propertyValue);
344 }
345 }
346 }
347
ReverseAnimation()348 void RSInteractiveImplictAnimator::ReverseAnimation()
349 {
350 if (state_ != RSInteractiveAnimationState::PAUSED) {
351 ROSEN_LOGE("ReverseAnimation failed, state_ is error");
352 return;
353 }
354
355 state_ = RSInteractiveAnimationState::RUNNING;
356
357 auto rsUIContext = rsUIContext_.lock();
358 for (auto& [item, nodeId] : animations_) {
359 auto animation = item.lock();
360 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
361 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
362 if (target != nullptr && animation != nullptr) {
363 animation->InteractiveReverse();
364 }
365 }
366
367 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorReverse>(id_);
368 AddCommand(command, IsUniRenderEnabled());
369 if (!IsUniRenderEnabled()) {
370 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorReverse>(id_);
371 AddCommand(commandForRemote, true);
372 }
373 }
374
SetFraction(float fraction)375 void RSInteractiveImplictAnimator::SetFraction(float fraction)
376 {
377 if (state_ != RSInteractiveAnimationState::PAUSED) {
378 ROSEN_LOGE("SetFraction failed, state_ is error");
379 return;
380 }
381
382 auto rsUIContext = rsUIContext_.lock();
383 for (auto& [item, nodeId] : animations_) {
384 auto animation = item.lock();
385 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
386 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
387 if (target != nullptr && animation != nullptr) {
388 animation->InteractiveSetFraction(fraction);
389 }
390 }
391
392 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorSetFraction>(id_, fraction);
393 AddCommand(command, IsUniRenderEnabled());
394 if (!IsUniRenderEnabled()) {
395 std::unique_ptr<RSCommand> commandForRemote =
396 std::make_unique<RSInteractiveAnimatorSetFraction>(id_, fraction);
397 AddCommand(commandForRemote, true);
398 }
399 }
400
GetFraction()401 float RSInteractiveImplictAnimator::GetFraction()
402 {
403 if (state_ != RSInteractiveAnimationState::PAUSED) {
404 ROSEN_LOGE("GetFraction failed, state_ is error");
405 return 0.0f;
406 }
407 if (fractionAnimationId_ == 0 || fractionNodeId_ == 0) {
408 ROSEN_LOGE("GetFraction failed, id is error");
409 return 0.0f;
410 }
411 auto task = std::make_shared<RSNodeGetAnimationsValueFraction>(1e8, fractionNodeId_, fractionAnimationId_);
412 RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task, IsUniRenderEnabled());
413
414 if (!task || !task->IsSuccess()) {
415 ROSEN_LOGE("RSInteractiveImplictAnimator::ExecuteSyncGetFractionTask failed to execute task.");
416 return 0.0f;
417 }
418 return task->GetFraction();
419 }
420
SetFinishCallBack(const std::function<void ()> & finishCallback)421 void RSInteractiveImplictAnimator::SetFinishCallBack(const std::function<void()>& finishCallback)
422 {
423 finishCallback_ = finishCallback;
424 }
425
CallFinishCallback()426 void RSInteractiveImplictAnimator::CallFinishCallback()
427 {
428 animations_.clear();
429 fractionAnimationId_ = 0;
430 fractionNodeId_ = 0;
431 if (finishCallback_) {
432 finishCallback_();
433 }
434 }
435
AddCommand(std::unique_ptr<RSCommand> & command,bool isRenderServiceCommand,FollowType followType,NodeId nodeId) const436 void RSInteractiveImplictAnimator::AddCommand(
437 std::unique_ptr<RSCommand>& command, bool isRenderServiceCommand, FollowType followType, NodeId nodeId) const
438 {
439 if (rsUIContext_.lock() != nullptr) {
440 auto rsTransaction = rsUIContext_.lock()->GetRSTransaction();
441 if (rsTransaction == nullptr) {
442 RS_LOGE("multi-instance: RSInteractiveImplictAnimator::AddCommand, transaction is nullptr");
443 return;
444 }
445 rsTransaction->AddCommand(command, isRenderServiceCommand, followType, nodeId);
446 } else {
447 auto transactionProxy = RSTransactionProxy::GetInstance();
448 if (transactionProxy == nullptr) {
449 RS_LOGE("RSInteractiveImplictAnimator::AddCommand transactionProxy is nullptr");
450 return;
451 }
452 transactionProxy->AddCommand(command, isRenderServiceCommand, followType, nodeId);
453 }
454 }
455 } // namespace Rosen
456 } // namespace OHOS
457