1  /*
2   * Copyright (c) 2021 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/scheduler.h"
17  
18  #include "core/pipeline/pipeline_base.h"
19  
20  namespace OHOS::Ace {
21  
Start()22  void Scheduler::Start()
23  {
24      if (isRunning_) {
25          LOGW("Already running, no need to start again.");
26          return;
27      }
28      auto context = context_.Upgrade();
29      if (!context) {
30          LOGE("Start failed, context is null.");
31          return;
32      }
33      isRunning_ = true;
34      startupTimestamp_ = context->GetTimeFromExternalTimer();
35      scheduleId_ = static_cast<int32_t>(context->AddScheduleTask(AceType::Claim(this)));
36  
37      displaySync_->RegisterOnFrameWithTimestamp([weak = WeakClaim(this)] (uint64_t nanoTimestamp) {
38          auto scheduler = weak.Upgrade();
39          CHECK_NULL_VOID(scheduler);
40          scheduler->OnFrame(nanoTimestamp);
41      });
42      displaySync_->AddToPipeline(context_);
43  }
44  
Stop()45  void Scheduler::Stop()
46  {
47      if (!isRunning_) {
48          return;
49      }
50      auto context = context_.Upgrade();
51      if (!context) {
52          LOGE("Stop failed, context is null.");
53          return;
54      }
55      isRunning_ = false;
56      context->RemoveScheduleTask(scheduleId_);
57      displaySync_->DelFromPipeline(context_);
58      scheduleId_ = 0;
59  }
60  
SetExpectedFrameRateRange(const FrameRateRange & frameRateRange)61  void Scheduler::SetExpectedFrameRateRange(const FrameRateRange& frameRateRange)
62  {
63      displaySync_->SetExpectedFrameRateRange(frameRateRange);
64  }
65  
OnFrame(uint64_t nanoTimestamp)66  void Scheduler::OnFrame(uint64_t nanoTimestamp)
67  {
68      if (!isRunning_) {
69          return;
70      }
71  
72      // Refresh the startup time every frame.
73      uint64_t elapsedTimeMs = 0;
74      if (nanoTimestamp > startupTimestamp_) {
75          static const uint64_t milliToNano = 1000000;
76          elapsedTimeMs = (nanoTimestamp - startupTimestamp_) / milliToNano;
77          startupTimestamp_ += elapsedTimeMs * milliToNano;
78      }
79  
80      // Consume previous schedule as default.
81      scheduleId_ = 0;
82      if (callback_) {
83          // Need to convert nanoseconds to milliseconds
84          callback_(elapsedTimeMs);
85      }
86  
87      // Schedule next frame task.
88      auto context = context_.Upgrade();
89      if (!context) {
90          LOGE("Schedule next frame task failed, context is null.");
91          return;
92      }
93      if (IsActive()) {
94          scheduleId_ = static_cast<int32_t>(context->AddScheduleTask(AceType::Claim(this)));
95      }
96  }
97  
Animate(const AnimationOption & option,const RefPtr<Curve> & curve,const std::function<void ()> propertyCallback,const std::function<void ()> & finishCallBack)98  bool Scheduler::Animate(const AnimationOption& option, const RefPtr<Curve>& curve,
99      const std::function<void()> propertyCallback, const std::function<void()>& finishCallBack)
100  {
101      auto context = context_.Upgrade();
102      if (context == nullptr) {
103          LOGE("Failed to animate asynchronously, context is null!");
104          return false;
105      }
106  
107      return context->Animate(option, curve, propertyCallback, finishCallBack);
108  }
109  
OpenImplicitAnimation(const AnimationOption & option,const RefPtr<Curve> & curve,const std::function<void ()> & finishCallBack)110  void Scheduler::OpenImplicitAnimation(const AnimationOption& option, const RefPtr<Curve>& curve,
111      const std::function<void()>& finishCallBack)
112  {
113      auto context = context_.Upgrade();
114      if (context == nullptr) {
115          LOGE("Failed to open implicit animation, context is null!");
116          return;
117      }
118  
119      return context->OpenImplicitAnimation(option, curve, finishCallBack);
120  }
121  
CloseImplicitAnimation()122  bool Scheduler::CloseImplicitAnimation()
123  {
124      auto context = context_.Upgrade();
125      if (context == nullptr) {
126          LOGE("Failed to close implicit animation, context is null!");
127          return false;
128      }
129  
130      return context->CloseImplicitAnimation();
131  }
132  
AddKeyFrame(float fraction,const RefPtr<Curve> & curve,const std::function<void ()> & propertyCallback)133  void Scheduler::AddKeyFrame(
134      float fraction, const RefPtr<Curve>& curve, const std::function<void()>& propertyCallback)
135  {
136      auto context = context_.Upgrade();
137      if (context == nullptr) {
138          LOGE("Failed to add keyframe, context is null!");
139          return;
140      }
141  
142      return context->AddKeyFrame(fraction, curve, propertyCallback);
143  }
144  
AddKeyFrame(float fraction,const std::function<void ()> & propertyCallback)145  void Scheduler::AddKeyFrame(float fraction, const std::function<void()>& propertyCallback)
146  {
147      auto context = context_.Upgrade();
148      if (context == nullptr) {
149          LOGE("Failed to add keyframe, context is null!");
150          return;
151      }
152  
153      return context->AddKeyFrame(fraction, propertyCallback);
154  }
155  
PrintVsyncInfoIfNeed() const156  bool Scheduler::PrintVsyncInfoIfNeed() const
157  {
158      auto pipeline = context_.Upgrade();
159      CHECK_NULL_RETURN(pipeline, false);
160      if (pipeline->PrintVsyncInfoIfNeed()) {
161          return true;
162      }
163      auto taskExecutor = pipeline->GetTaskExecutor();
164      CHECK_NULL_RETURN(taskExecutor, false);
165      const uint32_t delay = 3000; // unit: ms
166      // check vsync info after delay time.
167      taskExecutor->PostDelayedTask(
168          [weakContext = context_]() {
169              auto pipeline = weakContext.Upgrade();
170              CHECK_NULL_VOID(pipeline);
171              pipeline->PrintVsyncInfoIfNeed();
172          },
173          TaskExecutor::TaskType::UI, delay, "ArkUIAnimationPrintVsyncInfo");
174      return false;
175  }
176  
177  } // namespace OHOS::Ace
178