1 /*
2 * Copyright (c) 2023 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 #include "boot_animation.h"
16
17 #include "boot_animation_utils.h"
18 #include "event_handler.h"
19 #include "rs_trace.h"
20 #include "transaction/rs_render_service_client.h"
21 #include "transaction/rs_interfaces.h"
22 #include "transaction/rs_transaction.h"
23 #ifdef NEW_RENDER_CONTEXT
24 #include "render_context_factory.h"
25 #include "rs_surface_factory.h"
26 #endif
27 #include "parameter.h"
28 #include "platform/common/rs_system_properties.h"
29
30 using namespace OHOS;
31
32 constexpr float MAX_ZORDER = 100000.0f;
33 constexpr int HALF_NUM = 2;
34
OnDraw(SkCanvas * canvas,int32_t curNo)35 void BootAnimation::OnDraw(SkCanvas* canvas, int32_t curNo)
36 {
37 if (canvas == nullptr) {
38 LOGE("OnDraw canvas is nullptr");
39 return;
40 }
41 if (curNo > (imgVecSize_ - 1) || curNo < 0) {
42 return;
43 }
44 std::shared_ptr<ImageStruct> imgstruct = imageVector_[curNo];
45 sk_sp<SkImage> image = imgstruct->imageData;
46
47 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawRect");
48 SkPaint backPaint;
49 backPaint.setColor(SK_ColorBLACK);
50 canvas->drawRect(SkRect::MakeXYWH(0.0, 0.0, windowWidth_, windowHeight_), backPaint);
51 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
52 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawImageRect");
53 SkPaint paint;
54 SkRect rect;
55 rect.setXYWH(pointX_, pointY_, realWidth_, realHeight_);
56 canvas->drawImageRect(image.get(), rect, SkSamplingOptions(), &paint);
57 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
58 }
59
Draw()60 void BootAnimation::Draw()
61 {
62 if (picCurNo_ < (imgVecSize_ - 1)) {
63 picCurNo_ = picCurNo_ + 1;
64 } else {
65 CheckExitAnimation();
66 return;
67 }
68 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw RequestFrame");
69 auto frame = rsSurface_->RequestFrame(windowWidth_, windowHeight_);
70 if (frame == nullptr) {
71 LOGE("Draw frame is nullptr");
72 return;
73 }
74 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
75 #ifdef NEW_RENDER_CONTEXT
76 if (rsSurface_ == nullptr) {
77 LOGE("rsSurface is nullptr");
78 return;
79 }
80 auto canvas = rsSurface_->GetCanvas();
81 OnDraw(canvas, picCurNo_);
82 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
83 rsSurface_->FlushFrame();
84 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
85 #else
86 framePtr_ = std::move(frame);
87 auto canvas = framePtr_->GetCanvas();
88 OnDraw(canvas, picCurNo_);
89 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
90 rsSurface_->FlushFrame(framePtr_);
91 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
92 #endif
93 }
94
Init(Rosen::ScreenId defaultId,int32_t width,int32_t height)95 void BootAnimation::Init(Rosen::ScreenId defaultId, int32_t width, int32_t height)
96 {
97 defaultId_ = defaultId;
98 windowWidth_ = width;
99 windowHeight_ = height;
100 LOGI("Init enter, width: %{public}d, height: %{public}d", width, height);
101
102 InitPicCoordinates();
103 InitRsDisplayNode();
104 InitRsSurfaceNode();
105 #ifdef PLAYER_FRAMEWORK_ENABLE
106 if (animationConfig_.IsBootVideoEnabled()) {
107 LOGI("Init end");
108 return;
109 }
110 #endif
111 LOGI("Playing boot animation using sequence frames.");
112 system::SetParameter("bootevent.bootanimation.started", "true");
113 auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
114 while (receiver_ == nullptr) {
115 receiver_ = rsClient.CreateVSyncReceiver("BootAnimation", mainHandler_);
116 }
117 VsyncError ret = receiver_->Init();
118 if (ret) {
119 LOGE("vsync receiver init failed: %{public}d", ret);
120 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
121 return;
122 }
123 InitRsSurface();
124 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::preload");
125 if (animationConfig_.ReadPicZipFile(imageVector_, freq_)) {
126 imgVecSize_ = imageVector_.size();
127 } else {
128 LOGE("Read PicZipFile failed");
129 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
130 return;
131 }
132 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
133
134 OHOS::Rosen::VSyncReceiver::FrameCallback fcb = {
135 .userData_ = this,
136 .callback_ = std::bind(&BootAnimation::OnVsync, this),
137 };
138 int32_t changefreq = static_cast<int32_t>((1000.0 / freq_) / 16);
139 ret = receiver_->SetVSyncRate(fcb, changefreq);
140 if (ret) {
141 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
142 LOGE("SetVSyncRate failed: %{public}d %{public}d %{public}d", ret, freq_, changefreq);
143 return;
144 } else {
145 LOGI("SetVSyncRate success: %{public}d %{public}d", freq_, changefreq);
146 }
147 }
148
Run(Rosen::ScreenId id,int screenWidth,int screenHeight)149 void BootAnimation::Run(Rosen::ScreenId id, int screenWidth, int screenHeight)
150 {
151 LOGI("Run enter");
152 animationConfig_.ParserCustomCfgFile();
153 Rosen::RSInterfaces& interface = Rosen::RSInterfaces::GetInstance();
154 if (animationConfig_.GetRotateScreenId() >= 0) {
155 id = interface.GetActiveScreenId();
156 LOGI("GetActiveScreenId: " BPUBU64 "", id);
157 Rosen::RSScreenModeInfo modeinfo = interface.GetScreenActiveMode(id);
158 screenWidth = modeinfo.GetScreenWidth();
159 screenHeight = modeinfo.GetScreenHeight();
160 LOGI("screenWidth: %{public}d, screenHeight: %{public}d", screenWidth, screenHeight);
161 if (id > 0) {
162 LOGI("SetScreenPowerStatus POWER_STATUS_OFF_FAKE: 0");
163 interface.SetScreenPowerStatus(0, Rosen::ScreenPowerStatus::POWER_STATUS_OFF_FAKE);
164 LOGI("SetScreenPowerStatus POWER_STATUS_ON: " BPUBU64 "", id);
165 interface.SetScreenPowerStatus(id, Rosen::ScreenPowerStatus::POWER_STATUS_ON);
166 }
167 } else if (interface.GetScreenPowerStatus(id) != Rosen::ScreenPowerStatus::POWER_STATUS_ON) {
168 interface.SetScreenPowerStatus(id, Rosen::ScreenPowerStatus::POWER_STATUS_ON);
169 }
170
171 runner_ = AppExecFwk::EventRunner::Create(false);
172 mainHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
173 mainHandler_->PostTask(std::bind(&BootAnimation::Init, this, id, screenWidth, screenHeight));
174 LOGI("PostTask Init");
175 #ifdef PLAYER_FRAMEWORK_ENABLE
176 if (animationConfig_.IsBootVideoEnabled()) {
177 mainHandler_->PostTask(std::bind(&BootAnimation::PlayVideo, this));
178 LOGI("PostTask PlayVideo");
179 } else {
180 mainHandler_->PostTask(std::bind(&BootAnimation::PlaySound, this));
181 LOGI("PostTask PlaySound");
182 }
183 #else
184 LOGI("player_framework part is not enabled.");
185 #endif
186 runner_->Run();
187 }
188
InitRsSurfaceNode()189 void BootAnimation::InitRsSurfaceNode()
190 {
191 LOGI("Init RsSurfaceNode enter");
192 struct Rosen::RSSurfaceNodeConfig rsSurfaceNodeConfig;
193 rsSurfaceNodeConfig.SurfaceNodeName = "BootAnimationNode";
194 rsSurfaceNodeConfig.isSync = true;
195 Rosen::RSSurfaceNodeType rsSurfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_WINDOW_NODE;
196 rsSurfaceNode_ = Rosen::RSSurfaceNode::Create(rsSurfaceNodeConfig, rsSurfaceNodeType);
197 if (!rsSurfaceNode_) {
198 LOGE("rsSurfaceNode_ is nullptr");
199 return;
200 }
201 int32_t rotateScreenId = animationConfig_.GetRotateScreenId();
202 if (rotateScreenId >= 0 && (Rosen::ScreenId)rotateScreenId == defaultId_) {
203 LOGI("SurfaceNode set rotation degree: %{public}d", animationConfig_.GetRotateDegree());
204 rsSurfaceNode_->SetRotation(animationConfig_.GetRotateDegree());
205 }
206 rsSurfaceNode_->SetPositionZ(MAX_ZORDER);
207 rsSurfaceNode_->SetBounds({0, 0, windowWidth_, windowHeight_});
208 rsSurfaceNode_->SetBackgroundColor(0xFF000000);
209 rsSurfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT);
210 rsSurfaceNode_->SetBootAnimation(true);
211 OHOS::Rosen::RSTransaction::FlushImplicitTransaction();
212 rsSurfaceNode_->AttachToDisplay(defaultId_);
213 OHOS::Rosen::RSTransaction::FlushImplicitTransaction();
214 system::SetParameter("bootevent.bootanimation.ready", "true");
215 LOGI("Set bootevent.bootanimation.ready true");
216 }
217
InitRsSurface()218 void BootAnimation::InitRsSurface()
219 {
220 LOGI("InitRsSurface");
221 #if defined(NEW_RENDER_CONTEXT)
222 renderContext_ = Rosen::RenderContextBaseFactory::CreateRenderContext();
223 if (renderContext_ == nullptr) {
224 LOGE("Create Render Context failed");
225 return;
226 }
227 renderContext_->Init();
228 std::shared_ptr<Rosen::DrawingContext> drawingContext = std::make_shared<Rosen::DrawingContext>(
229 renderContext_->GetRenderType());
230 sptr<Surface> surface = rsSurfaceNode_->GetSurface();
231 drawingContext->SetUpDrawingContext();
232 rsSurface_ = Rosen::RSSurfaceFactory::CreateRSSurface(Rosen::PlatformName::OHOS, surface, drawingContext);
233 rsSurface_->SetRenderContext(renderContext_);
234 #else
235 rsSurface_ = OHOS::Rosen::RSSurfaceExtractor::ExtractRSSurface(rsSurfaceNode_);
236 if (rsSurface_ == nullptr) {
237 LOGE("rsSurface is nullptr");
238 return;
239 }
240 #ifdef ACE_ENABLE_GL
241 if (Rosen::RSSystemProperties::GetGpuApiType() == OHOS::Rosen::GpuApiType::OPENGL) {
242 rc_ = OHOS::Rosen::RenderContextFactory::GetInstance().CreateEngine();
243 if (rc_ == nullptr) {
244 LOGE("InitilizeEglContext failed");
245 return;
246 } else {
247 LOGI("init egl context");
248 rc_->InitializeEglContext();
249 rsSurface_->SetRenderContext(rc_);
250 }
251 }
252 #endif // ACE_ENABLE_GL
253 if (rc_ == nullptr) {
254 LOGI("rc is nullptr, use cpu");
255 }
256 #endif
257 }
258
~BootAnimation()259 BootAnimation::~BootAnimation()
260 {
261 if (rsSurfaceNode_) {
262 rsSurfaceNode_->DetachToDisplay(defaultId_);
263 }
264 if (rsDisplayNode_) {
265 rsDisplayNode_->RemoveFromTree();
266 }
267 OHOS::Rosen::RSTransaction::FlushImplicitTransaction();
268 }
269
InitPicCoordinates()270 void BootAnimation::InitPicCoordinates()
271 {
272 if (windowWidth_ >= windowHeight_) {
273 realHeight_ = windowHeight_;
274 realWidth_ = realHeight_;
275 pointX_ = (windowWidth_ - realWidth_) / HALF_NUM;
276 } else {
277 realWidth_ = windowWidth_;
278 realHeight_ = realWidth_;
279 pointY_ = (windowHeight_ - realHeight_) / HALF_NUM;
280 }
281 }
282
OnVsync()283 void BootAnimation::OnVsync()
284 {
285 PostTask(std::bind(&BootAnimation::Draw, this));
286 }
287
CheckExitAnimation()288 bool BootAnimation::CheckExitAnimation()
289 {
290 if (!isAnimationEnd_) {
291 LOGI("Boot animation is end");
292 system::SetParameter("bootevent.bootanimation.finished", "true");
293 isAnimationEnd_ = true;
294 }
295 std::string bootEventCompleted = system::GetParameter("bootevent.boot.completed", "false");
296 if (bootEventCompleted == "true") {
297 mainHandler_->PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
298 LOGI("Read bootevent.boot.completed is true");
299 return true;
300 }
301 return false;
302 }
303
304 #ifdef PLAYER_FRAMEWORK_ENABLE
PlaySound()305 void BootAnimation::PlaySound()
306 {
307 LOGI("PlaySound start");
308 bool bootSoundEnabled = BootAnimationUtils::GetBootAnimationSoundEnabled();
309 if (bootSoundEnabled == true) {
310 LOGI("PlaySound read bootSoundEnabled is true");
311 if (soundPlayer_ == nullptr) {
312 soundPlayer_ = Media::PlayerFactory::CreatePlayer();
313 }
314 std::string uri = animationConfig_.GetSoundUrl();
315 soundPlayer_->SetSource(uri);
316 soundPlayer_->SetLooping(false);
317 soundPlayer_->PrepareAsync();
318 soundPlayer_->Play();
319 }
320 LOGI("PlaySound end");
321 }
322 #endif
323
324 #ifdef PLAYER_FRAMEWORK_ENABLE
PlayVideo()325 void BootAnimation::PlayVideo()
326 {
327 LOGI("PlayVideo start w:%{public}d h:%{public}d", windowWidth_, windowHeight_);
328 if (!animationConfig_.IsBootVideoEnabled()) {
329 return;
330 }
331 fcb_ = {
332 .userData_ = this,
333 .callback_ = std::bind(&BootAnimation::CloseVideoPlayer, this),
334 };
335 LOGI("PlayVideo setVideo screenId:%{public}d", (int32_t)defaultId_);
336 bootVideoPlayer_ = std::make_shared<BootVideoPlayer>();
337 bootVideoPlayer_->SetVideoPath(
338 defaultId_ == 0 ? animationConfig_.GetBootVideoPath() : animationConfig_.GetBootExtraVideoPath());
339 bootVideoPlayer_->SetPlayerSurface(rsSurfaceNode_ ? rsSurfaceNode_->GetSurface() : nullptr);
340 bootVideoPlayer_->SetCallback(&fcb_);
341 if (!bootVideoPlayer_->PlayVideo()) {
342 LOGE("Play video failed.");
343 CloseVideoPlayer();
344 }
345 }
346 #endif
347
348 #ifdef PLAYER_FRAMEWORK_ENABLE
CloseVideoPlayer()349 void BootAnimation::CloseVideoPlayer()
350 {
351 LOGI("Close video player.");
352 while (!CheckExitAnimation()) {
353 usleep(SLEEP_TIME_US);
354 }
355 LOGI("Check Exit Animation end.");
356 }
357 #endif
358
InitRsDisplayNode()359 void BootAnimation::InitRsDisplayNode()
360 {
361 OHOS::Rosen::RSDisplayNodeConfig config = {defaultId_, false, 0};
362
363 rsDisplayNode_ = OHOS::Rosen::RSDisplayNode::Create(config);
364 if (rsDisplayNode_ == nullptr) {
365 LOGE("Failed to init display node!");
366 return;
367 }
368 rsDisplayNode_->SetDisplayOffset(0, 0);
369 rsDisplayNode_->SetFrame(0, 0, windowWidth_, windowHeight_);
370 rsDisplayNode_->SetBounds(0, 0, windowWidth_, windowHeight_);
371 rsDisplayNode_->SetBootAnimation(true);
372 // flush transaction
373 auto transactionProxy = OHOS::Rosen::RSTransactionProxy::GetInstance();
374 if (transactionProxy != nullptr) {
375 transactionProxy->FlushImplicitTransaction();
376 }
377 LOGD("InitRsDisplayNode success");
378 }