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 };
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(timingProtocol, timingCurve));
52 }
53
RSInteractiveImplictAnimator(const RSAnimationTimingProtocol & timingProtocol,const RSAnimationTimingCurve & timingCurve)54 RSInteractiveImplictAnimator::RSInteractiveImplictAnimator(
55 const RSAnimationTimingProtocol& timingProtocol, const RSAnimationTimingCurve& timingCurve)
56 :id_(GenerateId()), timingProtocol_(timingProtocol), timingCurve_(timingCurve)
57 {
58 InitUniRenderEnabled();
59 }
60
~RSInteractiveImplictAnimator()61 RSInteractiveImplictAnimator::~RSInteractiveImplictAnimator()
62 {
63 auto transactionProxy = RSTransactionProxy::GetInstance();
64 if (transactionProxy == nullptr) {
65 ROSEN_LOGE("RSTransactionProxy is nullptr");
66 return;
67 }
68 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorDestory>(id_);
69 transactionProxy->AddCommand(command, IsUniRenderEnabled());
70 if (!IsUniRenderEnabled()) {
71 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorDestory>(id_);
72 transactionProxy->AddCommand(commandForRemote, true);
73 }
74 }
75
IsUniRenderEnabled() const76 bool RSInteractiveImplictAnimator::IsUniRenderEnabled() const
77 {
78 return g_isUniRenderEnabled;
79 }
80
InitUniRenderEnabled()81 void RSInteractiveImplictAnimator::InitUniRenderEnabled()
82 {
83 static bool inited = false;
84 if (!inited) {
85 inited = true;
86 g_isUniRenderEnabled = RSSystemProperties::GetUniRenderEnabled();
87 ROSEN_LOGD("RSInteractiveImplictAnimator::InitUniRenderEnabled:%{public}d", g_isUniRenderEnabled);
88 }
89 }
90
GetAnimatorFinishCallback()91 std::shared_ptr<InteractiveAnimatorFinishCallback> RSInteractiveImplictAnimator::GetAnimatorFinishCallback()
92 {
93 auto callback = animatorCallback_.lock();
94 if (callback) {
95 return callback;
96 }
97 auto animatorCallback = std::make_shared<InteractiveAnimatorFinishCallback>([weak = weak_from_this()]() {
98 auto self = weak.lock();
99 if (self) {
100 self->CallFinishCallback();
101 }
102 });
103 animatorCallback_ = animatorCallback;
104 return animatorCallback;
105 }
106
AddImplictAnimation(std::function<void ()> callback)107 size_t RSInteractiveImplictAnimator::AddImplictAnimation(std::function<void()> callback)
108 {
109 if (state_ != RSInteractiveAnimationState::INACTIVE && state_ != RSInteractiveAnimationState::ACTIVE) {
110 ROSEN_LOGE("AddAnimation failed, state_ is error");
111 return 0;
112 }
113
114 auto implicitAnimator = RSImplicitAnimatorMap::Instance().GetAnimator(gettid());
115 if (implicitAnimator == nullptr) {
116 ROSEN_LOGE("Failed to open implicit animation, implicit animator is null!");
117 return 0;
118 }
119
120 if (timingProtocol_.GetDuration() <= 0) {
121 return 0;
122 }
123
124 implicitAnimator->OpenInterActiveImplicitAnimation(true, timingProtocol_, timingCurve_, nullptr);
125 callback();
126 auto animations = implicitAnimator->CloseInterActiveImplicitAnimation(true);
127
128 for (auto& [animation, nodeId] : animations) {
129 if (fractionAnimationId_ == 0 && animation->IsSupportInteractiveAnimator()) {
130 fractionAnimationId_ = animation->GetId();
131 fractionNodeId_ = nodeId;
132 }
133 std::weak_ptr<RSAnimation> weakAnimation = animation;
134 animation->SetInteractiveFinishCallback(GetAnimatorFinishCallback());
135 animations_.emplace_back(weakAnimation, nodeId);
136 }
137 state_ = RSInteractiveAnimationState::ACTIVE;
138 return animations.size();
139 }
140
AddAnimation(std::function<void ()> callback)141 size_t RSInteractiveImplictAnimator::AddAnimation(std::function<void()> callback)
142 {
143 if (state_ != RSInteractiveAnimationState::INACTIVE && state_ != RSInteractiveAnimationState::ACTIVE) {
144 ROSEN_LOGE("AddAnimation failed, state_ is error");
145 return 0;
146 }
147
148 auto implicitAnimator = RSImplicitAnimatorMap::Instance().GetAnimator(gettid());
149 if (implicitAnimator == nullptr) {
150 ROSEN_LOGE("Failed to open implicit animation, implicit animator is null!");
151 return 0;
152 }
153
154 implicitAnimator->OpenInterActiveImplicitAnimation(false, timingProtocol_, timingCurve_, nullptr);
155 callback();
156 auto animations = implicitAnimator->CloseInterActiveImplicitAnimation(false);
157
158 for (auto& [animation, nodeId] : animations) {
159 if (fractionAnimationId_ == 0 && animation->IsSupportInteractiveAnimator()) {
160 fractionAnimationId_ = animation->GetId();
161 fractionNodeId_ = nodeId;
162 }
163 std::weak_ptr<RSAnimation> weakAnimation = animation;
164 animation->SetInteractiveFinishCallback(GetAnimatorFinishCallback());
165 animations_.emplace_back(weakAnimation, nodeId);
166 }
167 state_ = RSInteractiveAnimationState::ACTIVE;
168 return animations.size();
169 }
170
StartAnimation()171 int32_t RSInteractiveImplictAnimator::StartAnimation()
172 {
173 if (state_ != RSInteractiveAnimationState::ACTIVE) {
174 ROSEN_LOGE("StartAnimation failed, state_ is error");
175 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_STATUS);
176 }
177
178 if (animations_.empty()) {
179 ROSEN_LOGE("StartAnimation failed, animations size is error");
180 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_ANIMATIONS);
181 }
182 std::vector<std::pair<NodeId, AnimationId>> renderAnimations;
183 for (auto& [item, nodeId] : animations_) {
184 auto animation = item.lock();
185 auto target = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
186 if (target != nullptr && animation != nullptr) {
187 animation->InteractiveContinue();
188 if (!animation->IsUiAnimation()) {
189 renderAnimations.emplace_back(nodeId, animation->GetId());
190 }
191 }
192 }
193 state_ = RSInteractiveAnimationState::RUNNING;
194
195 auto transactionProxy = RSTransactionProxy::GetInstance();
196 if (transactionProxy == nullptr) {
197 ROSEN_LOGE("Failed to start interactive animation, transaction proxy is null!");
198 return static_cast<int32_t>(StartAnimationErrorCode::INVALID_PROXY);
199 }
200 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorCreate>(id_, renderAnimations, true);
201 transactionProxy->AddCommand(command, IsUniRenderEnabled());
202 if (!IsUniRenderEnabled()) {
203 std::unique_ptr<RSCommand> commandForRemote =
204 std::make_unique<RSInteractiveAnimatorCreate>(id_, renderAnimations, true);
205 transactionProxy->AddCommand(commandForRemote, true);
206 }
207 return static_cast<int32_t>(StartAnimationErrorCode::SUCCESS);
208 }
209
PauseAnimation()210 void RSInteractiveImplictAnimator::PauseAnimation()
211 {
212 if (state_ != RSInteractiveAnimationState::RUNNING) {
213 ROSEN_LOGE("PauseAnimation failed, state_ is error");
214 return;
215 }
216 state_ = RSInteractiveAnimationState::PAUSED;
217
218 for (auto& [item, nodeId] : animations_) {
219 auto animation = item.lock();
220 auto target = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
221 if (target != nullptr && animation != nullptr) {
222 animation->InteractivePause();
223 }
224 }
225 auto transactionProxy = RSTransactionProxy::GetInstance();
226 if (transactionProxy == nullptr) {
227 ROSEN_LOGE("RSTransactionProxy is nullptr");
228 return;
229 }
230 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorPause>(id_);
231 transactionProxy->AddCommand(command, IsUniRenderEnabled());
232 if (!IsUniRenderEnabled()) {
233 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorPause>(id_);
234 transactionProxy->AddCommand(commandForRemote, true);
235 }
236 }
237
ContinueAnimation()238 void RSInteractiveImplictAnimator::ContinueAnimation()
239 {
240 if (state_ != RSInteractiveAnimationState::PAUSED) {
241 ROSEN_LOGE("ContinueAnimation failed, state_ is error");
242 return;
243 }
244
245 state_ = RSInteractiveAnimationState::RUNNING;
246
247 for (auto& [item, nodeId] : animations_) {
248 auto animation = item.lock();
249 auto target = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
250 if (target != nullptr && animation != nullptr) {
251 animation->InteractiveContinue();
252 }
253 }
254
255 auto transactionProxy = RSTransactionProxy::GetInstance();
256 if (transactionProxy == nullptr) {
257 ROSEN_LOGE("RSTransactionProxy is nullptr");
258 return;
259 }
260 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorContinue>(id_);
261 transactionProxy->AddCommand(command, IsUniRenderEnabled());
262 if (!IsUniRenderEnabled()) {
263 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorContinue>(id_);
264 transactionProxy->AddCommand(commandForRemote, true);
265 }
266 }
267
FinishAnimation(RSInteractiveAnimationPosition position)268 void RSInteractiveImplictAnimator::FinishAnimation(RSInteractiveAnimationPosition position)
269 {
270 if (state_ != RSInteractiveAnimationState::RUNNING && state_ != RSInteractiveAnimationState::PAUSED) {
271 ROSEN_LOGE("FinishAnimation failed, state_ is error");
272 return;
273 }
274 state_ = RSInteractiveAnimationState::INACTIVE;
275 if (position == RSInteractiveAnimationPosition::START || position == RSInteractiveAnimationPosition::END) {
276 for (auto& [item, nodeId] : animations_) {
277 auto animation = item.lock();
278 auto target = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
279 if (target == nullptr || animation == nullptr) {
280 continue;
281 }
282 animation->InteractiveFinish(position);
283 }
284 auto transactionProxy = RSTransactionProxy::GetInstance();
285 if (transactionProxy == nullptr) {
286 ROSEN_LOGE("RSTransactionProxy is nullptr");
287 return;
288 }
289 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorFinish>(id_, position);
290 transactionProxy->AddCommand(command, IsUniRenderEnabled());
291 if (!IsUniRenderEnabled()) {
292 std::unique_ptr<RSCommand> commandForRemote =
293 std::make_unique<RSInteractiveAnimatorFinish>(id_, position);
294 transactionProxy->AddCommand(commandForRemote, true);
295 }
296 } else if (position == RSInteractiveAnimationPosition::CURRENT) {
297 FinishOnCurrent();
298 }
299 }
300
FinishOnCurrent()301 void RSInteractiveImplictAnimator::FinishOnCurrent()
302 {
303 RSNodeGetShowingPropertiesAndCancelAnimation::PropertiesMap propertiesMap;
304 for (auto& [item, nodeId] : animations_) {
305 auto animation = item.lock();
306 auto node = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
307 if (node == nullptr || animation == nullptr) {
308 continue;
309 }
310 if (!node->HasPropertyAnimation(animation->GetPropertyId()) || animation->IsUiAnimation()) {
311 continue;
312 }
313 propertiesMap.emplace(std::make_pair<NodeId, PropertyId>(node->GetId(), animation->GetPropertyId()),
314 std::make_pair<std::shared_ptr<RSRenderPropertyBase>, std::vector<AnimationId>>(
315 nullptr, {animation->GetId()}));
316 }
317 if (propertiesMap.size() == 0) {
318 return;
319 }
320 auto task = std::make_shared<RSNodeGetShowingPropertiesAndCancelAnimation>(1e8, std::move(propertiesMap));
321 RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task, IsUniRenderEnabled());
322 if (!task || !task->IsSuccess()) {
323 return;
324 }
325 for (const auto& [key, value] : task->GetProperties()) {
326 const auto& [nodeId, propertyId] = key;
327 auto node = RSNodeMap::Instance().GetNode(nodeId);
328 if (node == nullptr) {
329 continue;
330 }
331 auto modifier = node->GetModifier(propertyId);
332 if (modifier == nullptr) {
333 continue;
334 }
335 auto property = modifier->GetProperty();
336 if (property == nullptr) {
337 continue;
338 }
339 const auto& [propertyValue, animations] = value;
340 if (propertyValue != nullptr) {
341 property->SetValueFromRender(propertyValue);
342 }
343 }
344 }
345
ReverseAnimation()346 void RSInteractiveImplictAnimator::ReverseAnimation()
347 {
348 if (state_ != RSInteractiveAnimationState::PAUSED) {
349 ROSEN_LOGE("ReverseAnimation failed, state_ is error");
350 return;
351 }
352
353 state_ = RSInteractiveAnimationState::RUNNING;
354
355 for (auto& [item, nodeId] : animations_) {
356 auto animation = item.lock();
357 auto target = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
358 if (target != nullptr && animation != nullptr) {
359 animation->InteractiveReverse();
360 }
361 }
362
363 auto transactionProxy = RSTransactionProxy::GetInstance();
364 if (transactionProxy == nullptr) {
365 ROSEN_LOGE("RSTransactionProxy is nullptr");
366 return;
367 }
368 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorReverse>(id_);
369 transactionProxy->AddCommand(command, IsUniRenderEnabled());
370 if (!IsUniRenderEnabled()) {
371 std::unique_ptr<RSCommand> commandForRemote = std::make_unique<RSInteractiveAnimatorReverse>(id_);
372 transactionProxy->AddCommand(commandForRemote, true);
373 }
374 }
375
SetFraction(float fraction)376 void RSInteractiveImplictAnimator::SetFraction(float fraction)
377 {
378 if (state_ != RSInteractiveAnimationState::PAUSED) {
379 ROSEN_LOGE("SetFraction failed, state_ is error");
380 return;
381 }
382
383 for (auto& [item, nodeId] : animations_) {
384 auto animation = item.lock();
385 auto target = RSNodeMap::Instance().GetNode<RSNode>(nodeId);
386 if (target != nullptr && animation != nullptr) {
387 animation->InteractiveSetFraction(fraction);
388 }
389 }
390
391 auto transactionProxy = RSTransactionProxy::GetInstance();
392 if (transactionProxy == nullptr) {
393 ROSEN_LOGE("RSTransactionProxy is nullptr");
394 return;
395 }
396 std::unique_ptr<RSCommand> command = std::make_unique<RSInteractiveAnimatorSetFraction>(id_, fraction);
397 transactionProxy->AddCommand(command, IsUniRenderEnabled());
398 if (!IsUniRenderEnabled()) {
399 std::unique_ptr<RSCommand> commandForRemote =
400 std::make_unique<RSInteractiveAnimatorSetFraction>(id_, fraction);
401 transactionProxy->AddCommand(commandForRemote, true);
402 }
403 }
404
GetFraction()405 float RSInteractiveImplictAnimator::GetFraction()
406 {
407 if (state_ != RSInteractiveAnimationState::PAUSED) {
408 ROSEN_LOGE("GetFraction failed, state_ is error");
409 return 0.0f;
410 }
411 if (fractionAnimationId_ == 0 || fractionNodeId_ == 0) {
412 ROSEN_LOGE("GetFraction failed, id is error");
413 return 0.0f;
414 }
415 auto task = std::make_shared<RSNodeGetAnimationsValueFraction>(1e8, fractionNodeId_, fractionAnimationId_);
416 RSTransactionProxy::GetInstance()->ExecuteSynchronousTask(task, IsUniRenderEnabled());
417
418 if (!task || !task->IsSuccess()) {
419 ROSEN_LOGE("RSInteractiveImplictAnimator::ExecuteSyncGetFractionTask failed to execute task.");
420 return 0.0f;
421 }
422 return task->GetFraction();
423 }
424
SetFinishCallBack(const std::function<void ()> & finishCallback)425 void RSInteractiveImplictAnimator::SetFinishCallBack(const std::function<void()>& finishCallback)
426 {
427 finishCallback_ = finishCallback;
428 }
429
CallFinishCallback()430 void RSInteractiveImplictAnimator::CallFinishCallback()
431 {
432 animations_.clear();
433 fractionAnimationId_ = 0;
434 fractionNodeId_ = 0;
435 if (finishCallback_) {
436 finishCallback_();
437 }
438 }
439 } // namespace Rosen
440 } // namespace OHOS
441