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