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