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