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 #include "event_handler.h"
17 #include "rs_trace.h"
18 #include "transaction/rs_render_service_client.h"
19 #include "transaction/rs_interfaces.h"
20 #include "transaction/rs_transaction.h"
21 #ifdef NEW_RENDER_CONTEXT
22 #include "render_context_factory.h"
23 #include "render_backend/rs_surface_factory.h"
24 #endif
25 #include <display_manager.h>
26
27 using namespace OHOS;
28 using namespace Rosen;
29
30 constexpr float MAX_ZORDER = 100000.0f;
31
OnDraw(SkCanvas * canvas,int32_t curNo)32 void BootAnimation::OnDraw(SkCanvas* canvas, int32_t curNo)
33 {
34 if (canvas == nullptr) {
35 LOGE("OnDraw canvas is nullptr");
36 return;
37 }
38 if (curNo > (imgVecSize_ - 1) || curNo < 0) {
39 return;
40 }
41 std::shared_ptr<ImageStruct> imgstruct = imageVector_[curNo];
42 sk_sp<SkImage> image = imgstruct->imageData;
43
44 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawRect");
45 SkPaint backPaint;
46 backPaint.setColor(SK_ColorBLACK);
47 canvas->drawRect(SkRect::MakeXYWH(0.0, 0.0, windowWidth_, windowHeight_), backPaint);
48 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
49 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::OnDraw in drawImageRect");
50 SkPaint paint;
51 SkRect rect;
52 rect.setXYWH(pointX_, pointY_, realWidth_, realHeight_);
53 #ifdef NEW_SKIA
54 canvas->drawImageRect(image.get(), rect, SkSamplingOptions(), &paint);
55 #else
56 canvas->drawImageRect(image.get(), rect, &paint);
57 #endif
58 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
59 }
60
Draw()61 void BootAnimation::Draw()
62 {
63 if (picCurNo_ < (imgVecSize_ - 1)) {
64 picCurNo_ = picCurNo_ + 1;
65 } else {
66 CheckExitAnimation();
67 return;
68 }
69 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw RequestFrame");
70 auto frame = rsSurface_->RequestFrame(windowWidth_, windowHeight_);
71 if (frame == nullptr) {
72 LOGE("Draw frame is nullptr");
73 return;
74 }
75 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
76 #ifdef NEW_RENDER_CONTEXT
77 if (rsSurface_ == nullptr) {
78 LOGE("rsSurface is nullptr");
79 return;
80 }
81 auto canvas = rsSurface_->GetCanvas();
82 OnDraw(canvas, picCurNo_);
83 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
84 rsSurface_->FlushFrame();
85 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
86 #else
87 framePtr_ = std::move(frame);
88 auto canvas = framePtr_->GetCanvas();
89 OnDraw(canvas, picCurNo_);
90 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::Draw FlushFrame");
91 rsSurface_->FlushFrame(framePtr_);
92 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
93 #endif
94 }
95
Init(Rosen::ScreenId defaultId,int32_t width,int32_t height)96 void BootAnimation::Init(Rosen::ScreenId defaultId, int32_t width, int32_t height)
97 {
98 defaultId_ = defaultId;
99 windowWidth_ = width;
100 windowHeight_ = height;
101 LOGI("Init enter, width: %{public}d, height: %{public}d", width, height);
102
103 InitPicCoordinates();
104 InitRsSurfaceNode();
105 if (animationConfig_.IsBootVideoEnabled()) {
106 LOGI("Init end");
107 return;
108 }
109
110 auto& rsClient = OHOS::Rosen::RSInterfaces::GetInstance();
111 while (receiver_ == nullptr) {
112 receiver_ = rsClient.CreateVSyncReceiver("BootAnimation", mainHandler_);
113 }
114 VsyncError ret = receiver_->Init();
115 if (ret) {
116 LOGE("vsync receiver init failed: %{public}d", ret);
117 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
118 return;
119 }
120 InitRsSurface();
121 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "BootAnimation::preload");
122 if (animationConfig_.ReadPicZipFile(imageVector_, freq_)) {
123 imgVecSize_ = imageVector_.size();
124 } else {
125 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
126 return;
127 }
128 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
129
130 OHOS::Rosen::VSyncReceiver::FrameCallback fcb = {
131 .userData_ = this,
132 .callback_ = std::bind(&BootAnimation::OnVsync, this),
133 };
134 int32_t changefreq = static_cast<int32_t>((1000.0 / freq_) / 16);
135 ret = receiver_->SetVSyncRate(fcb, changefreq);
136 if (ret) {
137 PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
138 LOGE("SetVSyncRate failed: %{public}d %{public}d %{public}d", ret, freq_, changefreq);
139 return;
140 } else {
141 LOGI("SetVSyncRate success: %{public}d %{public}d", freq_, changefreq);
142 }
143 }
144
Run(Rosen::ScreenId id,int screenWidth,int screenHeight)145 void BootAnimation::Run(Rosen::ScreenId id, int screenWidth, int screenHeight)
146 {
147 LOGI("Run enter");
148 animationConfig_.ParserCustomCfgFile();
149
150 runner_ = AppExecFwk::EventRunner::Create(false);
151 mainHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
152 mainHandler_->PostTask(std::bind(&BootAnimation::Init, this, id, screenWidth, screenHeight));
153 if (animationConfig_.IsBootVideoEnabled()) {
154 mainHandler_->PostTask(std::bind(&BootAnimation::PlayVideo, this));
155 } else {
156 mainHandler_->PostTask(std::bind(&BootAnimation::PlaySound, this));
157 }
158 runner_->Run();
159 }
160
InitRsSurfaceNode()161 void BootAnimation::InitRsSurfaceNode()
162 {
163 LOGI("Init RsSurfaceNode enter");
164 struct Rosen::RSSurfaceNodeConfig rsSurfaceNodeConfig;
165 Rosen::RSSurfaceNodeType rsSurfaceNodeType = Rosen::RSSurfaceNodeType::SELF_DRAWING_NODE;
166 rsSurfaceNode_ = Rosen::RSSurfaceNode::Create(rsSurfaceNodeConfig, rsSurfaceNodeType);
167 if (!rsSurfaceNode_) {
168 LOGE("rsSurfaceNode_ is nullptr");
169 return;
170 }
171 rsSurfaceNode_->SetPositionZ(MAX_ZORDER);
172 rsSurfaceNode_->SetBounds({0, 0, windowWidth_, windowHeight_});
173 rsSurfaceNode_->SetBackgroundColor(0xFF000000);
174 rsSurfaceNode_->SetFrameGravity(Rosen::Gravity::RESIZE_ASPECT);
175 rsSurfaceNode_->AttachToDisplay(defaultId_);
176 OHOS::Rosen::RSTransaction::FlushImplicitTransaction();
177 system::SetParameter("bootevent.bootanimation.started", "true");
178 LOGI("Set bootevent.bootanimation.started true");
179 }
180
InitRsSurface()181 void BootAnimation::InitRsSurface()
182 {
183 #if defined(NEW_RENDER_CONTEXT)
184 renderContext_ = Rosen::RenderContextBaseFactory::CreateRenderContext();
185 if (renderContext_ == nullptr) {
186 LOGE("Create Render Context failed");
187 return;
188 }
189 renderContext_->Init();
190 std::shared_ptr<Rosen::DrawingContext> drawingContext = std::make_shared<Rosen::DrawingContext>(
191 renderContext_->GetRenderType());
192 sptr<Surface> surface = rsSurfaceNode_->GetSurface();
193 drawingContext->SetUpDrawingContext();
194 rsSurface_ = Rosen::RSSurfaceFactory::CreateRSSurface(Rosen::PlatformName::OHOS, surface, drawingContext);
195 rsSurface_->SetRenderContext(renderContext_);
196 #else
197 rsSurface_ = OHOS::Rosen::RSSurfaceExtractor::ExtractRSSurface(rsSurfaceNode_);
198 if (rsSurface_ == nullptr) {
199 LOGE("rsSurface is nullptr");
200 return;
201 }
202 #ifdef ACE_ENABLE_GL
203 rc_ = OHOS::Rosen::RenderContextFactory::GetInstance().CreateEngine();
204 if (rc_ == nullptr) {
205 LOGE("InitilizeEglContext failed");
206 return;
207 } else {
208 LOGI("init egl context");
209 rc_->InitializeEglContext();
210 rsSurface_->SetRenderContext(rc_);
211 }
212 #endif
213 if (rc_ == nullptr) {
214 LOGI("rc is nullptr, use cpu");
215 }
216 #endif
217 }
218
~BootAnimation()219 BootAnimation::~BootAnimation()
220 {
221 rsSurfaceNode_->DetachToDisplay(defaultId_);
222 OHOS::Rosen::RSTransaction::FlushImplicitTransaction();
223 }
224
InitPicCoordinates()225 void BootAnimation::InitPicCoordinates()
226 {
227 if (windowWidth_ >= windowHeight_) {
228 realHeight_ = windowHeight_;
229 realWidth_ = realHeight_;
230 pointX_ = (windowWidth_ - realWidth_) / 2;
231 } else {
232 realWidth_ = windowWidth_;
233 realHeight_ = realWidth_;
234 pointY_ = (windowHeight_ - realHeight_) / 2;
235 }
236 }
237
OnVsync()238 void BootAnimation::OnVsync()
239 {
240 PostTask(std::bind(&BootAnimation::Draw, this));
241 }
242
CheckExitAnimation()243 bool BootAnimation::CheckExitAnimation()
244 {
245 if (!isAnimationEnd_) {
246 LOGI("Boot animation is end");
247 isAnimationEnd_ = true;
248 }
249 std::string bootEventCompleted = system::GetParameter("bootevent.boot.completed", "false");
250 if (bootEventCompleted == "true") {
251 mainHandler_->PostTask(std::bind(&AppExecFwk::EventRunner::Stop, runner_));
252 LOGI("Read bootevent.boot.completed is true");
253 return true;
254 }
255 return false;
256 }
257
PlaySound()258 void BootAnimation::PlaySound()
259 {
260 LOGI("PlaySound start");
261 bool bootSoundEnabled = system::GetBoolParameter("persist.graphic.bootsound.enabled", true);
262 if (bootSoundEnabled == true) {
263 LOGI("PlaySound read bootSoundEnabled is true");
264 if (soundPlayer_ == nullptr) {
265 soundPlayer_ = Media::PlayerFactory::CreatePlayer();
266 }
267 std::string uri = animationConfig_.GetSoundUrl();
268 soundPlayer_->SetSource(uri);
269 soundPlayer_->SetLooping(false);
270 soundPlayer_->PrepareAsync();
271 soundPlayer_->Play();
272 }
273 LOGI("PlaySound end");
274 }
275
PlayVideo()276 void BootAnimation::PlayVideo()
277 {
278 LOGI("PlayVideo start w:%{public}d h:%{public}d", windowWidth_, windowHeight_);
279 if (!animationConfig_.IsBootVideoEnabled()) {
280 return;
281 }
282 fcb_ = {
283 .userData_ = this,
284 .callback_ = std::bind(&BootAnimation::CloseVideoPlayer, this),
285 };
286 bootVideoPlayer_ = std::make_shared<BootVideoPlayer>();
287 bootVideoPlayer_->SetVideoPath(animationConfig_.GetBootVideoPath());
288 bootVideoPlayer_->SetPlayerSurface(rsSurfaceNode_ ? rsSurfaceNode_->GetSurface() : nullptr);
289 bootVideoPlayer_->SetCallback(&fcb_);
290 if (!bootVideoPlayer_->PlayVideo()) {
291 LOGE("Play video failed.");
292 CloseVideoPlayer();
293 }
294 }
295
CloseVideoPlayer()296 void BootAnimation::CloseVideoPlayer()
297 {
298 LOGI("Close video player.");
299 while (!CheckExitAnimation()) {
300 usleep(SLEEP_TIME_US);
301 }
302 LOGI("Check Exit Animation end.");
303 }
304