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