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