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