1 /*
2 * Copyright (c) 2022-2023 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 "render_service_client/core/animation/rs_interactive_implict_animator.h"
17
18 #include "core/animation/native_curve_helper.h"
19 #include "core/common/container.h"
20 #include "core/components_ng/animation/callback_thread_wrapper.h"
21 #include "core/pipeline_ng/pipeline_context.h"
22 #include "render_service_client/core/ui/rs_ui_director.h"
23
24 namespace OHOS::Ace {
25
26 namespace {
ToAnimationFinishCallbackType(const FinishCallbackType finishCallbackType)27 Rosen::FinishCallbackType ToAnimationFinishCallbackType(const FinishCallbackType finishCallbackType)
28 {
29 if (finishCallbackType == FinishCallbackType::LOGICALLY) {
30 return Rosen::FinishCallbackType::LOGICALLY;
31 } else if (finishCallbackType == FinishCallbackType::REMOVED) {
32 return Rosen::FinishCallbackType::TIME_SENSITIVE;
33 } else {
34 return Rosen::FinishCallbackType::TIME_SENSITIVE;
35 }
36 }
OptionToTimingProtocol(const AnimationOption & option)37 Rosen::RSAnimationTimingProtocol OptionToTimingProtocol(const AnimationOption& option)
38 {
39 Rosen::RSAnimationTimingProtocol timingProtocol;
40 timingProtocol.SetDuration(option.GetDuration());
41 timingProtocol.SetStartDelay(option.GetDelay());
42 timingProtocol.SetSpeed(option.GetTempo());
43 timingProtocol.SetRepeatCount(option.GetIteration());
44 timingProtocol.SetDirection(option.GetAnimationDirection() == AnimationDirection::NORMAL ||
45 option.GetAnimationDirection() == AnimationDirection::ALTERNATE);
46 timingProtocol.SetAutoReverse(option.GetAnimationDirection() == AnimationDirection::ALTERNATE ||
47 option.GetAnimationDirection() == AnimationDirection::ALTERNATE_REVERSE);
48 timingProtocol.SetFillMode(static_cast<Rosen::FillMode>(option.GetFillMode()));
49 timingProtocol.SetFinishCallbackType(ToAnimationFinishCallbackType(option.GetFinishCallbackType()));
50 timingProtocol.SetInterfaceName(option.GetAnimationInterfaceString());
51 auto rateRange = option.GetFrameRateRange();
52 if (rateRange) {
53 timingProtocol.SetFrameRateRange({ rateRange->min_, rateRange->max_, rateRange->preferred_, 0,
54 static_cast<Rosen::ComponentScene>(rateRange->componentScene_) });
55 }
56 return timingProtocol;
57 }
GetWrappedCallback(const std::function<void ()> & callback,bool once,const RefPtr<PipelineBase> & pipeline)58 std::function<void()> GetWrappedCallback(
59 const std::function<void()>& callback, bool once, const RefPtr<PipelineBase>& pipeline)
60 {
61 CHECK_NULL_RETURN(callback, nullptr);
62 auto instanceId = pipeline ? pipeline->GetInstanceId() : Container::CurrentIdSafelyWithCheck();
63 ContainerScope scope(instanceId);
64 auto taskExecutor = Container::CurrentTaskExecutor();
65 CHECK_NULL_RETURN(taskExecutor, callback);
66 NG::CallbackThreadWrapper callbackWrapper { taskExecutor, callback, once };
67 auto wrappedCallback = [callbackWrapper, instanceId]() mutable {
68 ContainerScope scope(instanceId);
69 auto taskExecutor = Container::CurrentTaskExecutor();
70 if (!taskExecutor) {
71 TAG_LOGW(AceLogTag::ACE_ANIMATION, "taskExecutor is nullptr");
72 return;
73 }
74 if (taskExecutor->WillRunOnCurrentThread(TaskExecutor::TaskType::UI)) {
75 callbackWrapper();
76 return;
77 }
78 taskExecutor->PostTask([callbackWrapper] () mutable { callbackWrapper(); }, TaskExecutor::TaskType::UI,
79 "ArkUIAnimationGetWrappedCallback", PriorityType::HIGH);
80 };
81 return wrappedCallback;
82 }
83
GetRSUIContext(const RefPtr<PipelineBase> & context)84 std::shared_ptr<Rosen::RSUIContext> GetRSUIContext(const RefPtr<PipelineBase>& context)
85 {
86 return AnimationUtils::GetCurrentRSUIContext(context);
87 }
88 } // namespace
89
90 class AnimationUtils::Animation {
91 private:
92 std::vector<std::shared_ptr<OHOS::Rosen::RSAnimation>> animations_;
93
94 friend AnimationUtils;
95 };
96
97 class AnimationUtils::InteractiveAnimation {
98 private:
99 std::shared_ptr<Rosen::RSInteractiveImplictAnimator> interactiveAnimation_;
100 friend AnimationUtils;
101 };
102
SetNavGroupNodeTransAnimationCallback()103 void AnimationUtils::SetNavGroupNodeTransAnimationCallback()
104 {
105 auto pipelineContext = NG::PipelineContext::GetCurrentContext();
106 CHECK_NULL_VOID(pipelineContext);
107 auto navigationManger = pipelineContext->GetNavigationManager();
108 CHECK_NULL_VOID(navigationManger);
109 navigationManger->SetNodeAddAnimation(true);
110 }
111
OpenImplicitAnimation(const AnimationOption & option,const RefPtr<Curve> & curve,const std::function<void ()> & finishCallback,const RefPtr<PipelineBase> & context)112 void AnimationUtils::OpenImplicitAnimation(const AnimationOption& option, const RefPtr<Curve>& curve,
113 const std::function<void()>& finishCallback, const RefPtr<PipelineBase>& context)
114 {
115 const auto& timingProtocol = OptionToTimingProtocol(option);
116 auto wrappedOnFinish = GetWrappedCallback(finishCallback, true, context);
117 auto rsUIContext = GetRSUIContext(context);
118 Rosen::RSNode::OpenImplicitAnimation(rsUIContext, timingProtocol,
119 NativeCurveHelper::ToNativeCurve(curve), wrappedOnFinish);
120 }
121
CloseImplicitAnimation(const RefPtr<PipelineBase> & context)122 bool AnimationUtils::CloseImplicitAnimation(const RefPtr<PipelineBase>& context)
123 {
124 auto rsUIContext = GetRSUIContext(context);
125 auto animations = Rosen::RSNode::CloseImplicitAnimation(rsUIContext);
126 auto pipeline = context ? context : PipelineBase::GetCurrentContext();
127 SetNavGroupNodeTransAnimationCallback();
128 if (pipeline && !pipeline->GetOnShow()) {
129 pipeline->FlushMessages();
130 }
131 return !animations.empty();
132 }
133
CloseImplicitCancelAnimation(const RefPtr<PipelineBase> & context)134 bool AnimationUtils::CloseImplicitCancelAnimation(const RefPtr<PipelineBase>& context)
135 {
136 auto rsUIContext = GetRSUIContext(context);
137 return Rosen::RSNode::CloseImplicitCancelAnimation(rsUIContext);
138 }
139
CloseImplicitCancelAnimationReturnStatus(const RefPtr<PipelineBase> & context)140 CancelAnimationStatus AnimationUtils::CloseImplicitCancelAnimationReturnStatus(const RefPtr<PipelineBase>& context)
141 {
142 auto rsUIContext = GetRSUIContext(context);
143 auto status = Rosen::RSNode::CloseImplicitCancelAnimationReturnStatus(rsUIContext);
144 return static_cast<CancelAnimationStatus>(status);
145 }
146
IsImplicitAnimationOpen(const RefPtr<PipelineBase> & context)147 bool AnimationUtils::IsImplicitAnimationOpen(const RefPtr<PipelineBase>& context)
148 {
149 auto rsUIContext = GetRSUIContext(context);
150 return Rosen::RSNode::IsImplicitAnimationOpen(rsUIContext);
151 }
152
Animate(const AnimationOption & option,const PropertyCallback & callback,const FinishCallback & finishCallback,const RepeatCallback & repeatCallback,const RefPtr<PipelineBase> & context)153 void AnimationUtils::Animate(const AnimationOption& option, const PropertyCallback& callback,
154 const FinishCallback& finishCallback, const RepeatCallback& repeatCallback, const RefPtr<PipelineBase>& context)
155 {
156 const auto& timingProtocol = OptionToTimingProtocol(option);
157 auto wrappedOnFinish = GetWrappedCallback(finishCallback, true, context);
158 auto wrappedOnRepeat = GetWrappedCallback(repeatCallback, false, context);
159 auto rsUIContext = GetRSUIContext(context);
160 Rosen::RSNode::Animate(rsUIContext, timingProtocol, NativeCurveHelper::ToNativeCurve(option.GetCurve()), callback,
161 wrappedOnFinish, wrappedOnRepeat);
162 auto pipeline = context ? context : PipelineBase::GetCurrentContext();
163 SetNavGroupNodeTransAnimationCallback();
164 if (pipeline && !pipeline->GetOnShow()) {
165 pipeline->FlushMessages();
166 }
167 }
168
AnimateWithCurrentOptions(const PropertyCallback & callback,const FinishCallback & finishCallback,bool timingSensitive,const RefPtr<PipelineBase> & context)169 void AnimationUtils::AnimateWithCurrentOptions(const PropertyCallback& callback, const FinishCallback& finishCallback,
170 bool timingSensitive, const RefPtr<PipelineBase>& context)
171 {
172 auto wrappedOnFinish = GetWrappedCallback(finishCallback, true, context);
173 auto rsUIContext = GetRSUIContext(context);
174 Rosen::RSNode::AnimateWithCurrentOptions(rsUIContext, callback, wrappedOnFinish, timingSensitive);
175 }
176
AnimateWithCurrentCallback(const AnimationOption & option,const PropertyCallback & callback,const RefPtr<PipelineBase> & context)177 void AnimationUtils::AnimateWithCurrentCallback(const AnimationOption& option, const PropertyCallback& callback,
178 const RefPtr<PipelineBase>& context)
179 {
180 const auto& timingProtocol = OptionToTimingProtocol(option);
181 auto rsUIContext = GetRSUIContext(context);
182 Rosen::RSNode::AnimateWithCurrentCallback(rsUIContext,
183 timingProtocol, NativeCurveHelper::ToNativeCurve(option.GetCurve()), callback);
184 }
185
AddKeyFrame(float fraction,const RefPtr<Curve> & curve,const PropertyCallback & callback,const RefPtr<PipelineBase> & context)186 void AnimationUtils::AddKeyFrame(float fraction, const RefPtr<Curve>& curve, const PropertyCallback& callback,
187 const RefPtr<PipelineBase>& context)
188 {
189 auto rsUIContext = GetRSUIContext(context);
190 Rosen::RSNode::AddKeyFrame(rsUIContext, fraction, NativeCurveHelper::ToNativeCurve(curve), callback);
191 }
192
AddKeyFrame(float fraction,const PropertyCallback & callback,const RefPtr<PipelineBase> & context)193 void AnimationUtils::AddKeyFrame(float fraction, const PropertyCallback& callback,
194 const RefPtr<PipelineBase>& context)
195 {
196 auto rsUIContext = GetRSUIContext(context);
197 Rosen::RSNode::AddKeyFrame(rsUIContext, fraction, callback);
198 }
199
AddDurationKeyFrame(int duration,const RefPtr<Curve> & curve,const PropertyCallback & callback,const RefPtr<PipelineBase> & context)200 void AnimationUtils::AddDurationKeyFrame(int duration, const RefPtr<Curve>& curve, const PropertyCallback& callback,
201 const RefPtr<PipelineBase>& context)
202 {
203 auto rsUIContext = GetRSUIContext(context);
204 Rosen::RSNode::AddDurationKeyFrame(rsUIContext, duration, NativeCurveHelper::ToNativeCurve(curve), callback);
205 }
206
StartAnimation(const AnimationOption & option,const PropertyCallback & callback,const FinishCallback & finishCallback,const RepeatCallback & repeatCallback,const RefPtr<PipelineBase> & context)207 std::shared_ptr<AnimationUtils::Animation> AnimationUtils::StartAnimation(
208 const AnimationOption& option, const PropertyCallback& callback,
209 const FinishCallback& finishCallback, const RepeatCallback& repeatCallback, const RefPtr<PipelineBase>& context)
210 {
211 std::shared_ptr<AnimationUtils::Animation> animation = std::make_shared<AnimationUtils::Animation>();
212 CHECK_NULL_RETURN(animation, nullptr);
213 const auto& timingProtocol = OptionToTimingProtocol(option);
214 auto wrappedOnFinish = GetWrappedCallback(finishCallback, true, context);
215 auto wrappedOnRepeat = GetWrappedCallback(repeatCallback, false, context);
216 auto rsUIContext = GetRSUIContext(context);
217 animation->animations_ = Rosen::RSNode::Animate(rsUIContext, timingProtocol,
218 NativeCurveHelper::ToNativeCurve(option.GetCurve()), callback, wrappedOnFinish, wrappedOnRepeat);
219 auto pipeline = context ? context : PipelineBase::GetCurrentContext();
220 if (pipeline && !pipeline->GetOnShow()) {
221 pipeline->FlushMessages();
222 }
223 if (!animation->animations_.empty()) {
224 return animation;
225 }
226 return nullptr;
227 }
228
StopAnimation(const std::shared_ptr<AnimationUtils::Animation> & animation)229 void AnimationUtils::StopAnimation(const std::shared_ptr<AnimationUtils::Animation>& animation)
230 {
231 CHECK_NULL_VOID(animation);
232 if (!animation->animations_.empty()) {
233 for (auto& ani : animation->animations_) {
234 ani->Finish();
235 }
236 animation->animations_.clear();
237 }
238 }
239
BlendBgColorAnimation(RefPtr<NG::RenderContext> & renderContext,const Color & endColor,int32_t duration,const RefPtr<Curve> & curve)240 void AnimationUtils::BlendBgColorAnimation(
241 RefPtr<NG::RenderContext>& renderContext, const Color& endColor, int32_t duration, const RefPtr<Curve>& curve)
242 {
243 AnimationOption option = AnimationOption();
244 option.SetCurve(curve);
245 option.SetDuration(duration);
246 AnimationUtils::Animate(option, [context = renderContext, color = endColor]() { context->BlendBgColor(color); });
247 }
248
PauseAnimation(const std::shared_ptr<AnimationUtils::Animation> & animation)249 void AnimationUtils::PauseAnimation(const std::shared_ptr<AnimationUtils::Animation>& animation)
250 {
251 CHECK_NULL_VOID(animation);
252 for (auto& ani : animation->animations_) {
253 ani->Pause();
254 }
255 auto pipeline = PipelineBase::GetCurrentContext();
256 if (pipeline && !pipeline->GetOnShow()) {
257 pipeline->FlushMessages();
258 }
259 }
260
ResumeAnimation(const std::shared_ptr<AnimationUtils::Animation> & animation)261 void AnimationUtils::ResumeAnimation(const std::shared_ptr<AnimationUtils::Animation>& animation)
262 {
263 CHECK_NULL_VOID(animation);
264 if (animation->animations_.empty()) {
265 return;
266 }
267 auto pipeline = PipelineBase::GetCurrentContext();
268 if (pipeline) {
269 pipeline->RequestFrame();
270 }
271 for (auto& ani : animation->animations_) {
272 ani->Resume();
273 }
274 }
275
ReverseAnimation(const std::shared_ptr<AnimationUtils::Animation> & animation)276 void AnimationUtils::ReverseAnimation(const std::shared_ptr<AnimationUtils::Animation>& animation)
277 {
278 CHECK_NULL_VOID(animation);
279 if (animation->animations_.empty()) {
280 return;
281 }
282 auto pipeline = PipelineBase::GetCurrentContext();
283 if (pipeline) {
284 pipeline->RequestFrame();
285 }
286 for (auto& ani : animation->animations_) {
287 ani->Reverse();
288 }
289 }
290
ExecuteWithoutAnimation(const PropertyCallback & callback,const RefPtr<PipelineBase> & context)291 void AnimationUtils::ExecuteWithoutAnimation(const PropertyCallback& callback,
292 const RefPtr<PipelineBase>& context)
293 {
294 auto rsUIContext = GetRSUIContext(context);
295 Rosen::RSNode::ExecuteWithoutAnimation(callback, rsUIContext);
296 }
297
CreateInteractiveAnimation(const InteractiveAnimationCallback & addCallback,const FinishCallback & callback)298 std::shared_ptr<AnimationUtils::InteractiveAnimation> AnimationUtils::CreateInteractiveAnimation(
299 const InteractiveAnimationCallback& addCallback, const FinishCallback& callback)
300 {
301 std::shared_ptr<AnimationUtils::InteractiveAnimation> interactiveAnimation =
302 std::make_shared<AnimationUtils::InteractiveAnimation>();
303 CHECK_NULL_RETURN(interactiveAnimation, nullptr);
304 auto wrappedOnFinish = GetWrappedCallback(callback, true, nullptr);
305 Rosen::RSAnimationTimingProtocol timingProtocol;
306 Rosen::RSAnimationTimingCurve curve;
307 interactiveAnimation->interactiveAnimation_ =
308 Rosen::RSInteractiveImplictAnimator::Create(timingProtocol, curve);
309 CHECK_NULL_RETURN(interactiveAnimation->interactiveAnimation_, nullptr);
310 if (addCallback) {
311 interactiveAnimation->interactiveAnimation_->AddAnimation(addCallback);
312 }
313 interactiveAnimation->interactiveAnimation_->SetFinishCallBack(wrappedOnFinish);
314 return interactiveAnimation;
315 }
316
StartInteractiveAnimation(const std::shared_ptr<AnimationUtils::InteractiveAnimation> & interactiveAnimation)317 int32_t AnimationUtils::StartInteractiveAnimation(
318 const std::shared_ptr<AnimationUtils::InteractiveAnimation>& interactiveAnimation)
319 {
320 CHECK_NULL_RETURN(interactiveAnimation, -1);
321 CHECK_NULL_RETURN(interactiveAnimation->interactiveAnimation_, -1);
322 return interactiveAnimation->interactiveAnimation_->StartAnimation();
323 }
324
ContinueInteractiveAnimation(const std::shared_ptr<AnimationUtils::InteractiveAnimation> & interactiveAnimation)325 void AnimationUtils::ContinueInteractiveAnimation(
326 const std::shared_ptr<AnimationUtils::InteractiveAnimation>& interactiveAnimation)
327 {
328 CHECK_NULL_VOID(interactiveAnimation);
329 CHECK_NULL_VOID(interactiveAnimation->interactiveAnimation_);
330 interactiveAnimation->interactiveAnimation_->ContinueAnimation();
331 }
332
ReverseInteractiveAnimation(const std::shared_ptr<AnimationUtils::InteractiveAnimation> & interactiveAnimation)333 void AnimationUtils::ReverseInteractiveAnimation(
334 const std::shared_ptr<AnimationUtils::InteractiveAnimation>& interactiveAnimation)
335 {
336 CHECK_NULL_VOID(interactiveAnimation);
337 CHECK_NULL_VOID(interactiveAnimation->interactiveAnimation_);
338 interactiveAnimation->interactiveAnimation_->ReverseAnimation();
339 }
340
UpdateInteractiveAnimation(const std::shared_ptr<AnimationUtils::InteractiveAnimation> & interactiveAnimation,float progress)341 void AnimationUtils::UpdateInteractiveAnimation(
342 const std::shared_ptr<AnimationUtils::InteractiveAnimation>& interactiveAnimation, float progress)
343 {
344 CHECK_NULL_VOID(interactiveAnimation);
345 CHECK_NULL_VOID(interactiveAnimation->interactiveAnimation_);
346 interactiveAnimation->interactiveAnimation_->PauseAnimation();
347 interactiveAnimation->interactiveAnimation_->SetFraction(progress);
348 }
349
AddInteractiveAnimation(const std::shared_ptr<AnimationUtils::InteractiveAnimation> & interactiveAnimation,const std::function<void ()> & callback)350 void AnimationUtils::AddInteractiveAnimation(
351 const std::shared_ptr<AnimationUtils::InteractiveAnimation>& interactiveAnimation,
352 const std::function<void()>& callback)
353 {
354 CHECK_NULL_VOID(interactiveAnimation);
355 CHECK_NULL_VOID(interactiveAnimation->interactiveAnimation_);
356 interactiveAnimation->interactiveAnimation_->AddAnimation(callback);
357 }
358
GetCurrentRSUIContext(RefPtr<PipelineBase> context)359 std::shared_ptr<Rosen::RSUIContext> AnimationUtils::GetCurrentRSUIContext(RefPtr<PipelineBase> context)
360 {
361 if (!context) {
362 context = PipelineBase::GetCurrentContextSafelyWithCheck();
363 CHECK_NULL_RETURN(context, nullptr);
364 }
365 auto window = context->GetWindow();
366 CHECK_NULL_RETURN(window, nullptr);
367 auto rsUIDirector = window->GetRSUIDirector();
368 CHECK_NULL_RETURN(rsUIDirector, nullptr);
369 return rsUIDirector->GetRSUIContext();
370 }
371 } // namespace OHOS::Ace
372