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