• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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