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