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 "modifier/rs_extended_modifier.h"
19 #include "platform/common/rs_log.h"
20 #include "sandbox_utils.h"
21
22 namespace OHOS {
23 namespace Rosen {
24 enum class StartAnimationErrorCode : int32_t {
25 SUCCESS = 0,
26 INVALID_STATUS,
27 INVALID_ANIMATIONS,
28 INVALID_PROXY,
29 INVALID_CONTEXT,
30 };
31
32 static bool g_isUniRenderEnabled = false;
33
GenerateId()34 InteractiveImplictAnimatorId RSInteractiveImplictAnimator::GenerateId()
35 {
36 static pid_t pid_ = GetRealPid();
37 static std::atomic<uint32_t> currentId_ = 0;
38
39 auto currentId = currentId_.fetch_add(1, std::memory_order_relaxed);
40 if (currentId == UINT32_MAX) {
41 ROSEN_LOGE("InteractiveImplictAnimatorId Id overflow");
42 }
43
44 // concat two 32-bit numbers to one 64-bit number
45 return ((InteractiveImplictAnimatorId)pid_ << 32) | (currentId);
46 }
47
Create(const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)48 std::shared_ptr<RSInteractiveImplictAnimator> RSInteractiveImplictAnimator::Create(
49 const RSAnimationTimingProtocol& timingProtocol, const RSAnimationTimingCurve& timingCurve)
50 {
51 return std::shared_ptr<RSInteractiveImplictAnimator>(
52 new RSInteractiveImplictAnimator(nullptr, timingProtocol, timingCurve));
53 }
54
Create(const std::shared_ptr<RSUIContext> rsUIContext,const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)55 std::shared_ptr<RSInteractiveImplictAnimator> RSInteractiveImplictAnimator::Create(
56 const std::shared_ptr<RSUIContext> rsUIContext, const RSAnimationTimingProtocol& timingProtocol,
57 const RSAnimationTimingCurve& timingCurve)
58 {
59 return std::shared_ptr<RSInteractiveImplictAnimator>(
60 new RSInteractiveImplictAnimator(rsUIContext, timingProtocol, timingCurve));
61 }
62
RSInteractiveImplictAnimator(const std::shared_ptr<RSUIContext> rsUIContext,const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)63 RSInteractiveImplictAnimator::RSInteractiveImplictAnimator(const std::shared_ptr<RSUIContext> rsUIContext,
64 const RSAnimationTimingProtocol& timingProtocol, 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
118 auto rsUIContext = rsUIContext_.lock();
119 auto implicitAnimator = rsUIContext ? rsUIContext->GetRSImplicitAnimator() :
120 RSImplicitAnimatorMap::Instance().GetAnimator(gettid());
121 if (implicitAnimator == nullptr) {
122 ROSEN_LOGE("Failed to open implicit animation, implicit animator is null!");
123 return 0;
124 }
125
126 if (timingProtocol_.GetDuration() <= 0) {
127 return 0;
128 }
129
130 implicitAnimator->OpenInterActiveImplicitAnimation(true, timingProtocol_, timingCurve_, nullptr);
131 callback();
132 auto animations = implicitAnimator->CloseInterActiveImplicitAnimation(true);
133
134 for (auto& [animation, nodeId] : animations) {
135 if (fractionAnimationId_ == 0 && animation->IsSupportInteractiveAnimator()) {
136 fractionAnimationId_ = animation->GetId();
137 fractionNodeId_ = nodeId;
138 }
139 std::weak_ptr<RSAnimation> weakAnimation = animation;
140 animation->SetInteractiveFinishCallback(GetAnimatorFinishCallback());
141 animations_.emplace_back(weakAnimation, nodeId);
142 }
143 state_ = RSInteractiveAnimationState::ACTIVE;
144 return animations.size();
145 }
146
AddAnimation(std::function<void ()> callback)147 size_t RSInteractiveImplictAnimator::AddAnimation(std::function<void()> callback)
148 {
149 if (state_ != RSInteractiveAnimationState::INACTIVE && state_ != RSInteractiveAnimationState::ACTIVE) {
150 ROSEN_LOGE("AddAnimation failed, state_ is error");
151 return 0;
152 }
153 auto rsUIContext = rsUIContext_.lock();
154 auto implicitAnimator = rsUIContext ? rsUIContext->GetRSImplicitAnimator() :
155 RSImplicitAnimatorMap::Instance().GetAnimator(gettid());
156 if (implicitAnimator == nullptr) {
157 ROSEN_LOGE("Failed to open implicit animation, implicit animator is null!");
158 return 0;
159 }
160
161 implicitAnimator->OpenInterActiveImplicitAnimation(false, timingProtocol_, timingCurve_, nullptr);
162 callback();
163 auto animations = implicitAnimator->CloseInterActiveImplicitAnimation(false);
164
165 for (auto& [animation, nodeId] : animations) {
166 if (fractionAnimationId_ == 0 && animation->IsSupportInteractiveAnimator()) {
167 fractionAnimationId_ = animation->GetId();
168 fractionNodeId_ = nodeId;
169 }
170 std::weak_ptr<RSAnimation> weakAnimation = animation;
171 animation->SetInteractiveFinishCallback(GetAnimatorFinishCallback());
172 animations_.emplace_back(weakAnimation, nodeId);
173 }
174 state_ = RSInteractiveAnimationState::ACTIVE;
175 return animations.size();
176 }
177
StartAnimation()178 int32_t RSInteractiveImplictAnimator::StartAnimation()
179 {
180 if (state_ != RSInteractiveAnimationState::ACTIVE) {
181 ROSEN_LOGE("StartAnimation failed, state_ is error");
182 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_STATUS);
183 }
184
185 if (animations_.empty()) {
186 ROSEN_LOGE("StartAnimation failed, animations size is error");
187 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_ANIMATIONS);
188 }
189 auto rsUIContext = rsUIContext_.lock();
190 std::vector<std::pair<NodeId, AnimationId>> renderAnimations;
191 for (auto& [item, nodeId] : animations_) {
192 auto animation = item.lock();
193 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
194 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
195 if (target != nullptr && animation != nullptr) {
196 animation->InteractiveContinue();
197 if (!animation->IsUiAnimation()) {
198 renderAnimations.emplace_back(nodeId, animation->GetId());
199 }
200 }
201 }
202 state_ = RSInteractiveAnimationState::RUNNING;
203
204 auto transactionProxy = RSTransactionProxy::GetInstance();
205 if (transactionProxy == nullptr) {
206 ROSEN_LOGE("Failed to start interactive animation, transaction proxy is null!");
207 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_PROXY);
208 }
209 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorCreate>(id_, renderAnimations, true);
210 AddCommand(command, IsUniRenderEnabled());
211 if (!IsUniRenderEnabled()) {
212 std::unique_ptr<RSCommand> commandForRemote =
213 std::make_unique<RSInteractiveAnimatorCreate>(id_, renderAnimations, true);
214 AddCommand(commandForRemote, true);
215 }
216 return static_cast<int32_t>(StartAnimationErrorCode::SUCCESS);
217 }
218
PauseAnimation()219 void RSInteractiveImplictAnimator::PauseAnimation()
220 {
221 if (state_ != RSInteractiveAnimationState::RUNNING) {
222 ROSEN_LOGE("PauseAnimation failed, state_ is error");
223 return;
224 }
225 state_ = RSInteractiveAnimationState::PAUSED;
226
227 auto rsUIContext = rsUIContext_.lock();
228 for (auto& [item, nodeId] : animations_) {
229 auto animation = item.lock();
230 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
231 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
232 if (target != nullptr && animation != nullptr) {
233 animation->InteractivePause();
234 }
235 }
236 auto transactionProxy = RSTransactionProxy::GetInstance();
237 if (transactionProxy == nullptr) {
238 ROSEN_LOGE("RSTransactionProxy is nullptr");
239 return;
240 }
241 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorPause>(id_);
242 AddCommand(command, IsUniRenderEnabled());
243 if (!IsUniRenderEnabled()) {
244 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorPause>(id_);
245 AddCommand(commandForRemote, true);
246 }
247 }
248
ContinueAnimation()249 void RSInteractiveImplictAnimator::ContinueAnimation()
250 {
251 if (state_ != RSInteractiveAnimationState::PAUSED) {
252 ROSEN_LOGE("ContinueAnimation failed, state_ is error");
253 return;
254 }
255
256 state_ = RSInteractiveAnimationState::RUNNING;
257
258 auto rsUIContext = rsUIContext_.lock();
259 for (auto& [item, nodeId] : animations_) {
260 auto animation = item.lock();
261 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
262 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
263 if (target != nullptr && animation != nullptr) {
264 animation->InteractiveContinue();
265 }
266 }
267
268 auto transactionProxy = RSTransactionProxy::GetInstance();
269 if (transactionProxy == nullptr) {
270 ROSEN_LOGE("RSTransactionProxy is nullptr");
271 return;
272 }
273 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorContinue>(id_);
274 AddCommand(command, IsUniRenderEnabled());
275 if (!IsUniRenderEnabled()) {
276 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorContinue>(id_);
277 AddCommand(commandForRemote, true);
278 }
279 }
280
FinishAnimation(RSInteractiveAnimationPosition position)281 void RSInteractiveImplictAnimator::FinishAnimation(RSInteractiveAnimationPosition position)
282 {
283 if (state_ != RSInteractiveAnimationState::RUNNING && state_ != RSInteractiveAnimationState::PAUSED) {
284 ROSEN_LOGE("FinishAnimation failed, state_ is error");
285 return;
286 }
287 state_ = RSInteractiveAnimationState::INACTIVE;
288
289 auto rsUIContext = rsUIContext_.lock();
290 if (position == RSInteractiveAnimationPosition::START || position == RSInteractiveAnimationPosition::END) {
291 for (auto& [item, nodeId] : animations_) {
292 auto animation = item.lock();
293 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
294 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
295 if (target == nullptr || animation == nullptr) {
296 continue;
297 }
298 animation->InteractiveFinish(position);
299 }
300 auto transactionProxy = RSTransactionProxy::GetInstance();
301 if (transactionProxy == nullptr) {
302 ROSEN_LOGE("RSTransactionProxy is nullptr");
303 return;
304 }
305 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorFinish>(id_, position);
306 AddCommand(command, IsUniRenderEnabled());
307 if (!IsUniRenderEnabled()) {
308 std::unique_ptr<RSCommand> commandForRemote =
309 std::make_unique<RSInteractiveAnimatorFinish>(id_, position);
310 AddCommand(commandForRemote, true);
311 }
312 } else if (position == RSInteractiveAnimationPosition::CURRENT) {
313 FinishOnCurrent();
314 }
315 }
316
FinishOnCurrent()317 void RSInteractiveImplictAnimator::FinishOnCurrent()
318 {
319 auto rsUIContext = rsUIContext_.lock();
320 RSNodeGetShowingPropertiesAndCancelAnimation::PropertiesMap propertiesMap;
321 for (auto& [item, nodeId] : animations_) {
322 auto animation = item.lock();
323 auto node = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
324 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
325 if (node == nullptr || animation == nullptr) {
326 continue;
327 }
328 if (!node->HasPropertyAnimation(animation->GetPropertyId()) || animation->IsUiAnimation()) {
329 continue;
330 }
331 propertiesMap.emplace(std::make_pair<NodeId, PropertyId>(node->GetId(), animation->GetPropertyId()),
332 std::make_pair<std::shared_ptr<RSRenderPropertyBase>, std::vector<AnimationId>>(
333 nullptr, {animation->GetId()}));
334 }
335 if (propertiesMap.size() == 0) {
336 return;
337 }
338 auto task = std::make_shared<RSNodeGetShowingPropertiesAndCancelAnimation>(1e8, std::move(propertiesMap));
339 RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task, IsUniRenderEnabled());
340 if (!task || !task->IsSuccess()) {
341 return;
342 }
343 for (const auto& [key, value] : task->GetProperties()) {
344 const auto& [nodeId, propertyId] = key;
345 auto node = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
346 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
347 if (node == nullptr) {
348 continue;
349 }
350 auto modifier = node->GetModifier(propertyId);
351 if (modifier == nullptr) {
352 continue;
353 }
354 auto property = modifier->GetProperty();
355 if (property == nullptr) {
356 continue;
357 }
358 const auto& [propertyValue, animations] = value;
359 if (propertyValue != nullptr) {
360 property->SetValueFromRender(propertyValue);
361 }
362 }
363 }
364
ReverseAnimation()365 void RSInteractiveImplictAnimator::ReverseAnimation()
366 {
367 if (state_ != RSInteractiveAnimationState::PAUSED) {
368 ROSEN_LOGE("ReverseAnimation failed, state_ is error");
369 return;
370 }
371
372 state_ = RSInteractiveAnimationState::RUNNING;
373
374 auto rsUIContext = rsUIContext_.lock();
375 for (auto& [item, nodeId] : animations_) {
376 auto animation = item.lock();
377 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
378 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
379 if (target != nullptr && animation != nullptr) {
380 animation->InteractiveReverse();
381 }
382 }
383
384 auto transactionProxy = RSTransactionProxy::GetInstance();
385 if (transactionProxy == nullptr) {
386 ROSEN_LOGE("RSTransactionProxy is nullptr");
387 return;
388 }
389 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorReverse>(id_);
390 AddCommand(command, IsUniRenderEnabled());
391 if (!IsUniRenderEnabled()) {
392 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorReverse>(id_);
393 AddCommand(commandForRemote, true);
394 }
395 }
396
SetFraction(float fraction)397 void RSInteractiveImplictAnimator::SetFraction(float fraction)
398 {
399 if (state_ != RSInteractiveAnimationState::PAUSED) {
400 ROSEN_LOGE("SetFraction failed, state_ is error");
401 return;
402 }
403
404 auto rsUIContext = rsUIContext_.lock();
405 for (auto& [item, nodeId] : animations_) {
406 auto animation = item.lock();
407 auto target = rsUIContext ? rsUIContext->GetNodeMap().GetNode<RSNode>(nodeId) :
408 RSNodeMap::Instance().GetNode<RSNode>(nodeId);
409 if (target != nullptr && animation != nullptr) {
410 animation->InteractiveSetFraction(fraction);
411 }
412 }
413
414 auto transactionProxy = RSTransactionProxy::GetInstance();
415 if (transactionProxy == nullptr) {
416 ROSEN_LOGE("RSTransactionProxy is nullptr");
417 return;
418 }
419 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorSetFraction>(id_, fraction);
420 AddCommand(command, IsUniRenderEnabled());
421 if (!IsUniRenderEnabled()) {
422 std::unique_ptr<RSCommand> commandForRemote =
423 std::make_unique<RSInteractiveAnimatorSetFraction>(id_, fraction);
424 AddCommand(commandForRemote, true);
425 }
426 }
427
GetFraction()428 float RSInteractiveImplictAnimator::GetFraction()
429 {
430 if (state_ != RSInteractiveAnimationState::PAUSED) {
431 ROSEN_LOGE("GetFraction failed, state_ is error");
432 return 0.0f;
433 }
434 if (fractionAnimationId_ == 0 || fractionNodeId_ == 0) {
435 ROSEN_LOGE("GetFraction failed, id is error");
436 return 0.0f;
437 }
438 auto task = std::make_shared<RSNodeGetAnimationsValueFraction>(1e8, fractionNodeId_, fractionAnimationId_);
439 RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task, IsUniRenderEnabled());
440
441 if (!task || !task->IsSuccess()) {
442 ROSEN_LOGE("RSInteractiveImplictAnimator::ExecuteSyncGetFractionTask failed to execute task.");
443 return 0.0f;
444 }
445 return task->GetFraction();
446 }
447
SetFinishCallBack(const std::function<void ()> & finishCallback)448 void RSInteractiveImplictAnimator::SetFinishCallBack(const std::function<void()>& finishCallback)
449 {
450 finishCallback_ = finishCallback;
451 }
452
CallFinishCallback()453 void RSInteractiveImplictAnimator::CallFinishCallback()
454 {
455 animations_.clear();
456 fractionAnimationId_ = 0;
457 fractionNodeId_ = 0;
458 if (finishCallback_) {
459 finishCallback_();
460 }
461 }
462
AddCommand(std::unique_ptr<RSCommand> & command,bool isRenderServiceCommand,FollowType followType,NodeId nodeId) const463 void RSInteractiveImplictAnimator::AddCommand(
464 std::unique_ptr<RSCommand>& command, bool isRenderServiceCommand, FollowType followType, NodeId nodeId) const
465 {
466 if (rsUIContext_.lock() != nullptr) {
467 auto rsTransaction = rsUIContext_.lock()->GetRSTransaction();
468 if (rsTransaction == nullptr) {
469 RS_LOGE("multi-instance: RSInteractiveImplictAnimator::AddCommand, transaction is nullptr");
470 return;
471 }
472 rsTransaction->AddCommand(command, isRenderServiceCommand, followType, nodeId);
473 } else {
474 auto transactionProxy = RSTransactionProxy::GetInstance();
475 if (transactionProxy == nullptr) {
476 RS_LOGE("RSInteractiveImplictAnimator::AddCommand transactionProxy is nullptr");
477 return;
478 }
479 transactionProxy->AddCommand(command, isRenderServiceCommand, followType, nodeId);
480 }
481 }
482 } // namespace Rosen
483 } // namespace OHOS
484