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