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