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