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