1 /*
2 * Copyright (c) 2021-2022 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 "core/animation/animator.h"
17
18 #include "base/utils/system_properties.h"
19 #include "base/utils/utils.h"
20 #include "core/animation/scheduler.h"
21 #include "core/common/container.h"
22 #include "core/common/container_scope.h"
23 #include "core/common/thread_checker.h"
24 #include "core/pipeline/pipeline_base.h"
25
26 namespace OHOS::Ace {
27 namespace {
28
29 int32_t g_controllerId = 0;
AllocControllerId()30 int32_t AllocControllerId()
31 {
32 return ++g_controllerId;
33 }
34
35 } // namespace
36
37 // Static Functions.
38 float Animator::scale_ = 1.0f;
39
SetDurationScale(float scale)40 void Animator::SetDurationScale(float scale)
41 {
42 if (scale < 0.0f) {
43 LOGE("Invalid scale value: %{public}f", scale);
44 return;
45 }
46 scale_ = scale;
47 }
48
GetAnimationScale() const49 float Animator::GetAnimationScale() const
50 {
51 #ifdef OHOS_STANDARD_SYSTEM
52 // if rosen is enabled, animationScale should be set on Rosen.
53 return allowRunningAsynchronously_ ? 1.0 : SystemProperties::GetAnimationScale();
54 #else
55 return scale_;
56 #endif
57 }
58
59 // Public Functions.
Animator(const char * name)60 Animator::Animator(const char* name)
61 {
62 controllerId_ = AllocControllerId();
63 if (name != nullptr) {
64 animatorName_ = name;
65 }
66 }
67
Animator(const WeakPtr<PipelineBase> & context,const char * name)68 Animator::Animator(const WeakPtr<PipelineBase>& context, const char* name)
69 {
70 controllerId_ = AllocControllerId();
71 AttachScheduler(context);
72 if (name != nullptr) {
73 animatorName_ = name;
74 }
75 }
76
~Animator()77 Animator::~Animator()
78 {
79 CHECK_RUN_ON(UI);
80 LOGD("Animator destructor. id:%{public}d", controllerId_);
81 // Clear all listeners first to make its destruction silently.
82 ClearAllListeners();
83 ClearInterpolators();
84 if (!IsStopped()) {
85 Stop();
86 }
87 }
88
AttachScheduler(const WeakPtr<PipelineBase> & context)89 void Animator::AttachScheduler(const WeakPtr<PipelineBase>& context)
90 {
91 auto&& callback = [weak = AceType::WeakClaim(this)](uint64_t duration) {
92 auto controller = weak.Upgrade();
93 if (!controller) {
94 LOGE("controller is nullptr, skip frame callback.");
95 return;
96 }
97 controller->OnFrame(duration);
98 };
99 scheduler_ = SchedulerBuilder::Build(callback, context);
100 }
101
AttachSchedulerOnContainer()102 void Animator::AttachSchedulerOnContainer()
103 {
104 auto pipeline = PipelineBase::GetCurrentContext();
105 CHECK_NULL_VOID(pipeline);
106 AttachScheduler(pipeline);
107 }
108
HasScheduler() const109 bool Animator::HasScheduler() const
110 {
111 return scheduler_ != nullptr;
112 }
113
AddInterpolator(const RefPtr<Interpolator> & animation)114 void Animator::AddInterpolator(const RefPtr<Interpolator>& animation)
115 {
116 CHECK_RUN_ON(UI);
117 if (animation) {
118 interpolators_.emplace_back(animation);
119 }
120 }
121
RemoveInterpolator(const RefPtr<Interpolator> & animation)122 void Animator::RemoveInterpolator(const RefPtr<Interpolator>& animation)
123 {
124 CHECK_RUN_ON(UI);
125 interpolators_.remove(animation);
126 }
127
ClearInterpolators()128 void Animator::ClearInterpolators()
129 {
130 CHECK_RUN_ON(UI);
131 interpolators_.clear();
132 }
133
AddProxyController(const RefPtr<Animator> & proxy)134 void Animator::AddProxyController(const RefPtr<Animator>& proxy)
135 {
136 CHECK_RUN_ON(UI);
137 if (!proxy) {
138 LOGE("Add Proxy Controller failed. controller is null.");
139 return;
140 }
141 if (RawPtr(proxy) != this) {
142 proxyControllers_.emplace_back(proxy);
143 proxy->Copy(Claim(this));
144 proxy->scheduler_.Reset();
145 }
146 }
147
RemoveProxyController(const RefPtr<Animator> & proxy)148 void Animator::RemoveProxyController(const RefPtr<Animator>& proxy)
149 {
150 CHECK_RUN_ON(UI);
151 proxyControllers_.remove(proxy);
152 }
153
ClearProxyControllers()154 void Animator::ClearProxyControllers()
155 {
156 CHECK_RUN_ON(UI);
157 proxyControllers_.clear();
158 }
159
GetStatus() const160 Animator::Status Animator::GetStatus() const
161 {
162 return status_;
163 }
164
IsStopped() const165 bool Animator::IsStopped() const
166 {
167 return status_ == Status::STOPPED;
168 }
169
IsRunning() const170 bool Animator::IsRunning() const
171 {
172 return status_ == Status::RUNNING;
173 }
174
175 // When the animation is in the delayed start phase.
IsPending() const176 bool Animator::IsPending() const
177 {
178 if ((status_ == Status::RUNNING) || (status_ == Status::PAUSED)) {
179 return elapsedTime_ < startDelay_;
180 } else {
181 return false;
182 }
183 }
184
GetDuration() const185 int32_t Animator::GetDuration() const
186 {
187 return duration_;
188 }
189
SetDuration(int32_t duration)190 void Animator::SetDuration(int32_t duration)
191 {
192 CHECK_RUN_ON(UI);
193 if (duration < 0) {
194 LOGE("invalid duration time, keep the old. id: %{public}d", controllerId_);
195 return;
196 }
197 LOGD("set duration: %{public}d. id: %{public}d", duration, controllerId_);
198 if ((status_ == Status::RUNNING || status_ == Status::PAUSED) && duration != 0) {
199 // Need to update elapsedTime when animation running or paused.
200 elapsedTime_ = (duration_ / duration) * elapsedTime_;
201 }
202 duration_ = duration;
203 for (auto& controller : proxyControllers_) {
204 controller->SetDuration(duration);
205 }
206 }
207
SetIteration(int32_t iteration)208 bool Animator::SetIteration(int32_t iteration)
209 {
210 CHECK_RUN_ON(UI);
211 if (iteration_ == iteration) {
212 return true;
213 }
214 if ((iteration < 0) && (iteration != ANIMATION_REPEAT_INFINITE)) {
215 LOGE("invalid iteration: %{public}d. id: %{public}d", iteration, controllerId_);
216 return false;
217 }
218 // if status is not idle, finish current animation and init animation
219 if (status_ != Status::IDLE) {
220 Finish();
221 }
222 LOGD("set iteration: %{public}d. id: %{public}d", iteration, controllerId_);
223 UpdateIteration(iteration);
224 repeatTimesLeft_ = repeatTimes_;
225 for (auto& controller : proxyControllers_) {
226 controller->SetIteration(iteration);
227 }
228 return true;
229 }
230
GetIteration() const231 int32_t Animator::GetIteration() const
232 {
233 return iteration_;
234 }
235
SetStartDelay(int32_t startDelay)236 void Animator::SetStartDelay(int32_t startDelay)
237 {
238 CHECK_RUN_ON(UI);
239 if (startDelay < 0) {
240 LOGE("invalid startDelay time, keep the old. id: %{public}d", controllerId_);
241 return;
242 }
243 LOGD("set start delay: %{public}d. id: %{public}d", startDelay, controllerId_);
244 startDelay_ = startDelay;
245 for (auto& controller : proxyControllers_) {
246 controller->SetStartDelay(startDelay);
247 }
248 }
249
SetFillMode(FillMode fillMode)250 void Animator::SetFillMode(FillMode fillMode)
251 {
252 CHECK_RUN_ON(UI);
253 fillMode_ = fillMode;
254 for (auto& controller : proxyControllers_) {
255 controller->SetFillMode(fillMode);
256 }
257 }
258
GetFillMode() const259 FillMode Animator::GetFillMode() const
260 {
261 return fillMode_;
262 }
263
SetTempo(float tempo)264 void Animator::SetTempo(float tempo)
265 {
266 CHECK_RUN_ON(UI);
267 if (tempo < 0.0f) {
268 return;
269 }
270 if (NearZero(tempo)) {
271 scaledStartDelay_ = 0;
272 scaledDuration_ = 0;
273 }
274 tempo_ = tempo;
275 }
276
ApplyOption(const AnimationOption & option)277 void Animator::ApplyOption(const AnimationOption& option)
278 {
279 SetDuration(option.GetDuration());
280 SetStartDelay(option.GetDelay());
281 SetIteration(option.GetIteration());
282 SetTempo(option.GetTempo());
283 SetAnimationDirection(option.GetAnimationDirection());
284 }
285
SetAnimationDirection(AnimationDirection direction)286 void Animator::SetAnimationDirection(AnimationDirection direction)
287 {
288 CHECK_RUN_ON(UI);
289 direction_ = direction;
290 for (auto& controller : proxyControllers_) {
291 controller->SetAnimationDirection(direction);
292 }
293 }
294
SetAllowRunningAsynchronously(bool runAsync)295 void Animator::SetAllowRunningAsynchronously(bool runAsync)
296 {
297 allowRunningAsynchronously_ = runAsync;
298 LOGD("Set allow running asynchronously. id: %{public}d, allow: %{public}d", controllerId_, runAsync);
299 }
300
GetAllowRunningAsynchronously()301 bool Animator::GetAllowRunningAsynchronously()
302 {
303 return allowRunningAsynchronously_;
304 }
305
306 // return true, the animation is played backward
307 // return false, the animation is played forward
GetInitAnimationDirection()308 bool Animator::GetInitAnimationDirection()
309 {
310 if (repeatTimes_ == ANIMATION_REPEAT_INFINITE) {
311 return isReverse_;
312 }
313 if (direction_ == AnimationDirection::ALTERNATE_REVERSE || direction_ == AnimationDirection::REVERSE) {
314 isReverse_ = true;
315 }
316 if (direction_ != AnimationDirection::ALTERNATE) {
317 return isReverse_;
318 }
319 return isReverse_ ? (repeatTimesLeft_ % 2) == 0 : false;
320 }
321
UpdatePlayedTime(int32_t playedTime,bool checkReverse)322 void Animator::UpdatePlayedTime(int32_t playedTime, bool checkReverse)
323 {
324 if (playedTime < 0 || playedTime > duration_) {
325 LOGE("UpdatePlayedTime failed. Invalid playedTime:%{public}d", playedTime);
326 return;
327 }
328 if (startDelay_ != 0 || motion_) {
329 LOGE("Unsupported UpdatePlayedTime when startDelay or motion");
330 return;
331 }
332 if (!checkReverse) {
333 // only support go forward.
334 isReverse_ = false;
335 isCurDirection_ = false;
336 }
337 float scale = GetAnimationScale();
338 if (!NearZero(tempo_)) {
339 int32_t scaledPlayedTime = playedTime * scale / tempo_;
340 elapsedTime_ = scaledPlayedTime;
341 }
342 }
343
GetPlayedTime() const344 int64_t Animator::GetPlayedTime() const
345 {
346 return elapsedTime_;
347 }
348
TriggerFrame(int32_t playedTime,bool checkReverse)349 void Animator::TriggerFrame(int32_t playedTime, bool checkReverse)
350 {
351 CHECK_RUN_ON(UI);
352 if (playedTime < 0 || playedTime > duration_) {
353 LOGE("TriggerFrame failed. Invalid playedTime:%{public}d", playedTime);
354 return;
355 }
356 if (startDelay_ != 0 || motion_) {
357 LOGE("Unsupported TriggerFrame when startDelay or motion");
358 return;
359 }
360 UpdatePlayedTime(playedTime, checkReverse);
361 UpdateScaledTime();
362 NotifyPrepareListener();
363 NotifyInterpolator(elapsedTime_);
364 }
365
PlayMotion(const RefPtr<Motion> & motion)366 void Animator::PlayMotion(const RefPtr<Motion>& motion)
367 {
368 CHECK_RUN_ON(UI);
369 if (!motion) {
370 LOGE("PlayMotion failed, motion is null.");
371 return;
372 }
373 interpolators_.clear();
374 isReverse_ = false;
375 motion_ = motion;
376 StartInner(false);
377 }
378
Play()379 void Animator::Play()
380 {
381 CHECK_RUN_ON(UI);
382 if (iteration_ == 0) {
383 LOGD("no need to play animation, iteration is zero.");
384 return;
385 }
386 LOGD("Play animation in current direction, id: %{public}d", controllerId_);
387 motion_ = nullptr;
388 StartInner(false);
389 }
390
Reverse()391 void Animator::Reverse()
392 {
393 CHECK_RUN_ON(UI);
394 if (iteration_ == 0) {
395 LOGD("no need to reverse animation, iteration is zero.");
396 return;
397 }
398 LOGD("Play animation in opposite direction, id: %{public}d", controllerId_);
399 motion_ = nullptr;
400 ToggleDirection();
401 StartInner(true);
402 }
403
Forward()404 void Animator::Forward()
405 {
406 CHECK_RUN_ON(UI);
407 if (iteration_ == 0) {
408 LOGD("no need to play animation forward, iteration is zero.");
409 return;
410 }
411 if (isReverse_) {
412 ToggleDirection();
413 }
414 Play();
415 }
416
Backward()417 void Animator::Backward()
418 {
419 CHECK_RUN_ON(UI);
420 if (iteration_ == 0) {
421 LOGD("no need to play animation backward, iteration is zero.");
422 return;
423 }
424 if (isReverse_) {
425 ToggleDirection();
426 }
427 Reverse();
428 }
429
Pause()430 void Animator::Pause()
431 {
432 CHECK_RUN_ON(UI);
433 if (iteration_ == 0) {
434 LOGD("no need to pause animation, iteration is zero.");
435 return;
436 }
437 if (status_ == Status::PAUSED) {
438 LOGW("Already paused, do not need pause again. id: %{public}d", controllerId_);
439 return;
440 }
441 if (status_ == Status::IDLE) {
442 Play();
443 }
444 LOGD("animation pause. id: %{public}d", controllerId_);
445 if (scheduler_ && scheduler_->IsActive()) {
446 scheduler_->Stop();
447 }
448 status_ = Status::PAUSED;
449 asyncTrace_ = nullptr;
450 StatusListenable::NotifyPauseListener();
451 for (auto& controller : proxyControllers_) {
452 controller->Pause();
453 }
454 }
455
Resume()456 void Animator::Resume()
457 {
458 CHECK_RUN_ON(UI);
459 if (iteration_ == 0) {
460 LOGD("no need to resume animation, iteration is zero.");
461 return;
462 }
463 if (status_ == Status::RUNNING) {
464 LOGW("Already running, do not need resume again. id: %{public}d", controllerId_);
465 return;
466 }
467 LOGD("animation resume. id: %{public}d", controllerId_);
468 if (scheduler_ && !scheduler_->IsActive()) {
469 scheduler_->Start();
470 }
471 status_ = Status::RUNNING;
472 if (!motion_) {
473 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>(animatorName_.c_str());
474 } else {
475 if (motion_->GetMotionType() == "friction") {
476 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>((animatorName_ + ": friction").c_str());
477 } else if (motion_->GetMotionType() == "spring") {
478 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>((animatorName_ + ": spring").c_str());
479 } else {
480 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>(animatorName_.c_str());
481 }
482 }
483 isResume_ = true;
484 StatusListenable::NotifyResumeListener();
485 for (auto& controller : proxyControllers_) {
486 controller->Resume();
487 }
488 }
489
Stop()490 void Animator::Stop()
491 {
492 CHECK_RUN_ON(UI);
493 if (iteration_ == 0) {
494 LOGD("no need to stop animation, iteration is zero.");
495 return;
496 }
497 if (status_ == Status::STOPPED) {
498 LOGD("Already stop, do not need stop again. id: %{public}d", controllerId_);
499 return;
500 }
501 LOGD("animation stop. id: %{public}d", controllerId_);
502
503 elapsedTime_ = 0;
504 repeatTimesLeft_ = repeatTimes_;
505 isBothBackwards = false;
506 UpdateScaledTime();
507 if (scheduler_ && scheduler_->IsActive()) {
508 scheduler_->Stop();
509 }
510 status_ = Status::STOPPED;
511 asyncTrace_ = nullptr;
512 StatusListenable::NotifyStopListener();
513 for (auto& controller : proxyControllers_) {
514 controller->Stop();
515 }
516 }
517
Finish()518 void Animator::Finish()
519 {
520 CHECK_RUN_ON(UI);
521 if (iteration_ == 0) {
522 LOGD("no need to finish animation, iteration is zero.");
523 return;
524 }
525 if (status_ == Status::STOPPED) {
526 LOGD("Already stop, do not need finish again. id: %{public}d", controllerId_);
527 return;
528 }
529 LOGD("animation finish. id: %{public}d", controllerId_);
530 if (motion_) {
531 LOGD("end action not supports for motion. just stop it. id: %{public}d", controllerId_);
532 Stop();
533 return;
534 }
535 repeatTimesLeft_ = 0;
536 UpdateScaledTime();
537 OnFrame(((int64_t)scaledStartDelay_) + scaledDuration_);
538 }
539
Cancel()540 void Animator::Cancel()
541 {
542 CHECK_RUN_ON(UI);
543 if (iteration_ == 0) {
544 LOGD("no need to cancel animation, iteration is zero.");
545 return;
546 }
547 if (status_ == Status::IDLE) {
548 LOGW("Already in idle, do not need cancel again. id: %{public}d", controllerId_);
549 return;
550 }
551 status_ = Status::IDLE;
552 LOGE("animation cancel. id: %{public}d", controllerId_);
553 elapsedTime_ = 0;
554 repeatTimesLeft_ = repeatTimes_;
555 UpdateScaledTime();
556 NotifyPrepareListener();
557 float normalizedTime = GetNormalizedTime(0.0f, true);
558 for (auto& interpolator : interpolators_) {
559 interpolator->OnInitNotify(normalizedTime, isReverse_);
560 }
561 if (scheduler_ && scheduler_->IsActive()) {
562 scheduler_->Stop();
563 }
564 NotifyIdleListener();
565 }
566
GetId() const567 int32_t Animator::GetId() const
568 {
569 return controllerId_;
570 }
571
572 // Private Functions.
OnFrame(int64_t duration)573 void Animator::OnFrame(int64_t duration)
574 {
575 CHECK_RUN_ON(UI);
576 // notify child first
577 for (auto& controller : proxyControllers_) {
578 controller->OnFrame(duration);
579 }
580 if (duration > INT64_MAX - elapsedTime_) {
581 LOGW("duration is too big, skip it. id:%{public}d", controllerId_);
582 return;
583 }
584 elapsedTime_ += duration;
585 UpdateScaledTime();
586 // skip delay time
587 if (elapsedTime_ < scaledStartDelay_) {
588 if ((fillMode_ == FillMode::BACKWARDS || fillMode_ == FillMode::BOTH) && !isBothBackwards) {
589 for (const auto& interpolator : interpolators_) {
590 interpolator->OnNormalizedTimestampChanged(0.0f, isReverse_);
591 }
592 isBothBackwards = true;
593 }
594 return;
595 }
596 NotifyPrepareListener();
597 // get playedTime
598 auto playedTime = elapsedTime_ - scaledStartDelay_;
599 // make playedTime in range 0 ~ INT32_MAX(max duration value)
600 playedTime = std::clamp<int64_t>(playedTime, 0L, (int64_t)INT32_MAX);
601 if (!motion_) {
602 NotifyInterpolator(playedTime);
603 } else {
604 NotifyMotion(playedTime);
605 }
606 }
607
NotifyInterpolator(int32_t playedTime)608 void Animator::NotifyInterpolator(int32_t playedTime)
609 {
610 CHECK_RUN_ON(UI);
611 bool needStop = false;
612 bool notifyRepeat = false;
613 // do not notify user when handling playedTime, because users may be change duration or repeat times in callback.
614 // if they change this parameter, it will take effect next tick.
615 if (playedTime >= scaledDuration_) {
616 notifyRepeat = true;
617 auto isAlternateDirection =
618 (direction_ == AnimationDirection::ALTERNATE) || (direction_ == AnimationDirection::ALTERNATE_REVERSE);
619 if ((scaledDuration_ == 0) && isAlternateDirection && (iteration_ % 2 == 0)) {
620 isCurDirection_ = !isCurDirection_;
621 }
622 // make playedTime in range 0 ~ INTERPOLATE_DURATION_MAX
623 if (repeatTimesLeft_ == 0 || scaledDuration_ == 0) {
624 LOGD("animation stop, repeatTimesLeft: %{public}d, duration: %{public}d, id: %{public}d", repeatTimesLeft_,
625 scaledDuration_, controllerId_);
626 repeatTimesLeft_ = 0;
627 needStop = true;
628 } else {
629 auto playedLoops = GetPlayedLoopsAndRemaining(playedTime);
630 if (repeatTimesLeft_ != ANIMATION_REPEAT_INFINITE) {
631 needStop = UpdateRepeatTimesLeftAndCheckFinished(playedLoops);
632 }
633 if (isAlternateDirection) {
634 isCurDirection_ = !isCurDirection_;
635 }
636 LOGD("animation next loop. repeat times remaining: %{public}d. id: %{public}d", repeatTimesLeft_,
637 controllerId_);
638 }
639
640 // after the above branches, playedTime in range 0 ~ INTERPOLATE_DURATION_MAX
641 // make elapsedTime_ in range 0 ~ scaledStartDelay_ + INTERPOLATE_DURATION_MAX
642 elapsedTime_ = playedTime + scaledStartDelay_;
643 }
644
645 float normalizedTime = GetNormalizedTime(playedTime, needStop);
646 // all calculation above is done, we can notify user from now.
647 // users can change controller's configuration, and it will take effect next tick.
648 if (notifyRepeat && !needStop) {
649 // notify repeat before on timestamp changed.
650 StatusListenable::NotifyRepeatListener();
651 }
652 for (const auto& interpolator : interpolators_) {
653 if (needStop && (fillMode_ == FillMode::NONE || fillMode_ == FillMode::BACKWARDS)) {
654 // notify init value set by user.
655 interpolator->OnInitNotify(normalizedTime, isReverse_);
656 } else {
657 // interpolate animation accept normalized time.
658 interpolator->OnNormalizedTimestampChanged(normalizedTime, isReverse_);
659 }
660 }
661 if (needStop && (!IsStopped())) {
662 // notify stop after on timestamp changed.
663 LOGD("animation stop in tick callback.");
664 Stop();
665 }
666 }
667
NotifyMotion(int32_t playedTime)668 void Animator::NotifyMotion(int32_t playedTime)
669 {
670 CHECK_RUN_ON(UI);
671 // motion do not have normalized time, because no exact duration in motion.
672 // just pass actual time to motion, normalized time always zero.
673 motion_->OnTimestampChanged(playedTime, 0.0f, false);
674 if (motion_->IsCompleted()) {
675 Stop();
676 }
677 }
678
StartInner(bool alwaysNotify)679 void Animator::StartInner(bool alwaysNotify)
680 {
681 CHECK_RUN_ON(UI);
682 if (status_ == Status::RUNNING) {
683 LOGD("controller already running, do not need start again. skip it. id: %{public}d", controllerId_);
684 if (toggleDirectionPending_) {
685 toggleDirectionPending_ = false;
686 isCurDirection_ = !isCurDirection_;
687 }
688
689 if (alwaysNotify) {
690 StatusListenable::NotifyStartListener();
691 for (auto& controller : proxyControllers_) {
692 controller->StartInner(alwaysNotify);
693 }
694 }
695 return;
696 }
697 toggleDirectionPending_ = false;
698 if (scheduler_ && !scheduler_->IsActive()) {
699 if (!StartAsync()) {
700 scheduler_->Start();
701 }
702 }
703 StatusListenable::NotifyStartListener();
704 status_ = Status::RUNNING;
705 if (!motion_) {
706 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>(animatorName_.c_str());
707 } else {
708 if (motion_->GetMotionType() == "friction") {
709 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>((animatorName_ + ": friction").c_str());
710 } else if (motion_->GetMotionType() == "spring") {
711 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>((animatorName_ + ": spring").c_str());
712 } else {
713 asyncTrace_ = std::make_shared<AceAsyncScopedTrace>(animatorName_.c_str());
714 }
715 }
716 isCurDirection_ = GetInitAnimationDirection();
717 for (auto& controller : proxyControllers_) {
718 controller->StartInner(alwaysNotify);
719 }
720 }
721
GetAnimationOption()722 AnimationOption Animator::GetAnimationOption()
723 {
724 AnimationOption option;
725 option.SetDuration(duration_ * GetAnimationScale());
726 option.SetDelay(startDelay_ * GetAnimationScale());
727 option.SetIteration(iteration_);
728 option.SetTempo(tempo_);
729 option.SetFillMode(fillMode_);
730
731 AnimationDirection direction = direction_;
732 if (GetInitAnimationDirection()) {
733 switch (direction_) {
734 case AnimationDirection::NORMAL:
735 direction = AnimationDirection::REVERSE;
736 break;
737 case AnimationDirection::ALTERNATE:
738 direction_ = AnimationDirection::ALTERNATE_REVERSE;
739 break;
740 case AnimationDirection::REVERSE:
741 direction = AnimationDirection::NORMAL;
742 break;
743 case AnimationDirection::ALTERNATE_REVERSE:
744 direction_ = AnimationDirection::ALTERNATE;
745 break;
746 default:
747 direction = AnimationDirection::NORMAL;
748 break;
749 }
750 }
751
752 option.SetAnimationDirection(direction);
753 return option;
754 }
755
IsSupportedRunningAsynchronously()756 bool Animator::IsSupportedRunningAsynchronously()
757 {
758 for (const auto& animation : interpolators_) {
759 if (!animation->IsSupportedRunningAsynchronously()) {
760 return false;
761 }
762 }
763
764 return true;
765 }
766
StartAsync()767 bool Animator::StartAsync()
768 {
769 if (!SystemProperties::GetRosenBackendEnabled()) {
770 return false;
771 }
772
773 if (!allowRunningAsynchronously_) {
774 return false;
775 }
776
777 if (interpolators_.empty()) {
778 LOGD("interpolators_ is empty, controller id: %{public}d", controllerId_);
779 return false;
780 }
781
782 if (!IsSupportedRunningAsynchronously()) {
783 LOGW("not support running asynchronously, controller id: %{public}d", controllerId_);
784 return false;
785 }
786 if (scheduler_) {
787 auto context = scheduler_->GetContext().Upgrade();
788 if (context && !context->IsRebuildFinished()) {
789 context->SetBuildAfterCallback([weak = AceType::WeakClaim(this)]() {
790 auto controller = weak.Upgrade();
791 if (controller != nullptr) {
792 controller->StartInnerAsync();
793 }
794 });
795 return true;
796 }
797 }
798 StartInnerAsync();
799 return true;
800 }
801
StartInnerAsync()802 bool Animator::StartInnerAsync()
803 {
804 LOGD("start inner async, controller id: %{public}d, interpolators size:%{public}zu", controllerId_,
805 interpolators_.size());
806
807 auto prepareCallback = [weak = AceType::WeakClaim(this)]() -> void {
808 auto controller = weak.Upgrade();
809 if (controller != nullptr) {
810 controller->NotifyPrepareListener();
811 }
812 };
813
814 auto stopCallback = [weak = AceType::WeakClaim(this), id = Container::CurrentId()]() -> void {
815 ContainerScope scope(id);
816 auto controller = weak.Upgrade();
817 if (controller == nullptr) {
818 LOGE("notify stop failed, controller is null");
819 return;
820 }
821 controller->StopInnerAsync();
822 };
823
824 auto animations = std::move(interpolators_);
825 auto option = GetAnimationOption();
826 asyncRunningAnimationCount_ = 0;
827 for (const auto& animation : animations) {
828 if (animation->RunAsync(scheduler_, option, prepareCallback, stopCallback)) {
829 asyncRunningAnimationCount_++;
830 }
831 }
832
833 LOGD("start animations async. controller id: %{public}d, count: %{public}d", controllerId_,
834 asyncRunningAnimationCount_);
835 return true;
836 }
837
StopInnerAsync()838 void Animator::StopInnerAsync()
839 {
840 if (--asyncRunningAnimationCount_ > 0) {
841 LOGD("notify stop, controller id: %{public}d, running animations count %{public}d", controllerId_,
842 asyncRunningAnimationCount_);
843 return;
844 }
845
846 if (status_ != Status::STOPPED && (!HasScheduler() || !scheduler_->IsActive())) {
847 Stop();
848 LOGD("native animations stop. controller id: %{public}d", controllerId_);
849 }
850 }
851
GetPlayedLoopsAndRemaining(int32_t & playedTime)852 int32_t Animator::GetPlayedLoopsAndRemaining(int32_t& playedTime)
853 {
854 // when duration equals 0, played loop equals INT32_MAX, and playedTime remains unchanged.
855 int32_t playedLoop = INT32_MAX;
856 if (scaledDuration_ != 0) {
857 // in order to make playedTime in range of 0 ~ INTERPOLATE_DURATION_MAX, calc elapsed loop between two vsyncs
858 playedLoop = std::clamp(playedTime / scaledDuration_, 0, INT32_MAX);
859 playedTime = playedTime % scaledDuration_;
860 }
861 return playedLoop;
862 }
863
UpdateRepeatTimesLeftAndCheckFinished(int32_t playedLoops)864 bool Animator::UpdateRepeatTimesLeftAndCheckFinished(int32_t playedLoops)
865 {
866 // get the remaining repeatTimesLeft_
867 repeatTimesLeft_ -= playedLoops;
868 if (playedLoops > 1) {
869 LOGW("too long time between neighbor vsync, elapsed loop count: %{public}d. id: %{public}d", playedLoops,
870 controllerId_);
871 }
872 if (repeatTimesLeft_ < 0) {
873 LOGD("elapse too long, no repeat remaining. Loop: %{public}d. id: %{public}d", playedLoops, controllerId_);
874 return true;
875 }
876 return false;
877 }
878
ToggleDirection()879 void Animator::ToggleDirection()
880 {
881 isReverse_ = !isReverse_;
882 LOGD("change direction. isReverse change to: %{public}d, id: %{public}d", isReverse_, controllerId_);
883 // if toggleDirectionPending_ is true, it will be cleared in StartInner
884 toggleDirectionPending_ = !toggleDirectionPending_;
885 if (status_ == Status::IDLE || status_ == Status::STOPPED) {
886 LOGD("toggle an idle controller, do not change time related params. id: %{public}d", controllerId_);
887 return;
888 }
889 if (repeatTimes_ == ANIMATION_REPEAT_INFINITE) {
890 elapsedTime_ = scaledDuration_ - elapsedTime_;
891 LOGI("duration is infinite, can not reverse time related params. id: %{public}d", controllerId_);
892 return;
893 }
894 repeatTimesLeft_ = repeatTimes_ - repeatTimesLeft_;
895 LOGD("change left repeat times: %{public}d. id: %{public}d", repeatTimesLeft_, controllerId_);
896 elapsedTime_ = scaledDuration_ - elapsedTime_;
897 }
898
GetNormalizedTime(float playedTime,bool needStop) const899 float Animator::GetNormalizedTime(float playedTime, bool needStop) const
900 {
901 float normalizedTime = 0.0f;
902 if (needStop) {
903 LOGD("animation stop. set played time to the end value according to fill mode. id: %{public}d", controllerId_);
904 switch (fillMode_) {
905 case FillMode::FORWARDS:
906 // Fall through.
907 case FillMode::BOTH:
908 LOGD("fill mode is FORWARDS or BOTH. id: %{public}d", controllerId_);
909 normalizedTime = 1.0f;
910 break;
911 case FillMode::NONE:
912 // Fall through.
913 case FillMode::BACKWARDS:
914 LOGD("fill mode is NONE or BACKWARDS. id: %{public}d", controllerId_);
915 normalizedTime = 0.0f;
916 break;
917 default:
918 LOGD("unknown fill mode, use default mode. id: %{public}d", controllerId_);
919 normalizedTime = 1.0f;
920 break;
921 }
922 } else {
923 normalizedTime = scaledDuration_ == 0 ? 1.0f : (1.0f * playedTime) / scaledDuration_;
924 }
925 return isCurDirection_ ? 1.0f - normalizedTime : normalizedTime;
926 }
927
UpdateScaledTime()928 void Animator::UpdateScaledTime()
929 {
930 float scale = GetAnimationScale();
931 if (!NearZero(tempo_)) {
932 scaledDuration_ = duration_ * scale / tempo_;
933 scaledStartDelay_ = startDelay_ * scale / tempo_;
934 }
935 }
936
UpdateIteration(int32_t iteration)937 void Animator::UpdateIteration(int32_t iteration)
938 {
939 iteration_ = iteration;
940 if (iteration <= 0 && iteration != ANIMATION_REPEAT_INFINITE) {
941 repeatTimes_ = 0;
942 } else if (iteration == ANIMATION_REPEAT_INFINITE) {
943 repeatTimes_ = ANIMATION_REPEAT_INFINITE;
944 } else {
945 repeatTimes_ = iteration - 1;
946 }
947 }
948
Copy(const RefPtr<Animator> & controller)949 void Animator::Copy(const RefPtr<Animator>& controller)
950 {
951 if (!controller) {
952 return;
953 }
954 fillMode_ = controller->fillMode_;
955 direction_ = controller->direction_;
956 isCurDirection_ = controller->isCurDirection_;
957 toggleDirectionPending_ = controller->toggleDirectionPending_;
958 duration_ = controller->duration_;
959 elapsedTime_ = controller->elapsedTime_;
960 startDelay_ = controller->startDelay_;
961 repeatTimes_ = controller->repeatTimes_;
962 iteration_ = controller->iteration_;
963 repeatTimesLeft_ = controller->repeatTimesLeft_;
964 isReverse_ = controller->isReverse_;
965 isResume_ = controller->isResume_;
966 status_ = controller->status_;
967 scaledDuration_ = controller->scaledDuration_;
968 scaledStartDelay_ = controller->scaledStartDelay_;
969 }
970
ResetIsReverse()971 void Animator::ResetIsReverse()
972 {
973 isReverse_ = false;
974 }
975
976 } // namespace OHOS::Ace
977