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