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