1 /*
2 * Copyright (C) 2025-2025 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 // LCOV_EXCL_START
17 #include "magnification_menu.h"
18 #include "visibility.h"
19
20 namespace OHOS {
21 namespace Accessibility {
22 namespace {
23 const std::string FULL_SCREEN_PATH = "/system/etc/accessibility/fullScreen.png";
24 const std::string WINDOW_PATH = "/system/etc/accessibility/window.png";
25 const std::string MENU_NAME = "magnification_menu";
26 }
27 static MagnificationMenu instance;
28
CreateMenuWindow()29 void MagnificationMenu::CreateMenuWindow()
30 {
31 HILOG_DEBUG();
32 GetWindowParam();
33 menuRect_ = {(static_cast<int32_t>(screenWidth_ - menuSize_) - margin_), (
34 static_cast<int32_t>(screenHeight_ - menuSize_) - margin_), menuSize_, menuSize_};
35 sptr<Rosen::WindowOption> windowOption = new(std::nothrow) Rosen::WindowOption();
36 if (windowOption == nullptr) {
37 HILOG_ERROR("windowOption is null");
38 return;
39 }
40 windowOption->SetWindowType(Rosen::WindowType::WINDOW_TYPE_MAGNIFICATION_MENU);
41 windowOption->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING);
42 windowOption->SetWindowRect(menuRect_);
43 menuWindow_ = Rosen::Window::Create(MENU_NAME, windowOption);
44 if (menuWindow_ == nullptr) {
45 HILOG_ERROR("create failed");
46 ExtUtils::RecordMagnificationUnavailableEvent("Create menu failed.");
47 return;
48 }
49 menuWindow_->SetCornerRadius(MENU_CORNER_RADIUS);
50 surfaceNode_ = menuWindow_->GetSurfaceNode();
51 if (surfaceNode_ == nullptr) {
52 HILOG_ERROR("surfaceNode_ is nullptr.");
53 return;
54 }
55 rsUIContext_ = surfaceNode_->GetRSUIContext();
56 canvasNode_ = Rosen::RSCanvasNode::Create(false, false, rsUIContext_);
57 if (canvasNode_ == nullptr) {
58 HILOG_ERROR("create canvasNode_ fail.");
59 return;
60 }
61 canvasNode_->SetSkipCheckInMultiInstance(true);
62 surfaceNode_->SetAbilityBGAlpha(BG_ALPHA);
63 surfaceNode_->AddChild(canvasNode_, -1);
64 canvasNode_->SetBounds(0, 0, menuSize_, menuSize_);
65 canvasNode_->SetFrame(0, 0, menuSize_, menuSize_);
66 canvasNode_->SetPositionZ(Rosen::RSSurfaceNode::POINTER_WINDOW_POSITION_Z);
67 canvasNode_->SetRotation(0);
68 rosenImage_ = std::make_shared<Rosen::RSImage>();
69 }
70
LoadMenuBgImage(uint32_t mode)71 void MagnificationMenu::LoadMenuBgImage(uint32_t mode)
72 {
73 HILOG_DEBUG();
74 std::string path = FULL_SCREEN_PATH;
75 if (mode == WINDOW_MAGNIFICATION) {
76 path = WINDOW_PATH;
77 }
78 bgpixelmap_ = DecodePixelMap(path, allocatorType_);
79 if (bgpixelmap_ == nullptr) {
80 HILOG_ERROR("DecodePixelMap failed.");
81 return;
82 }
83 if (canvasNode_ == nullptr) {
84 HILOG_ERROR("canvasNode_ is nullptr.");
85 return;
86 }
87 canvasNode_->SetBgImageWidth(menuSize_);
88 canvasNode_->SetBgImageHeight(menuSize_);
89 canvasNode_->SetBgImagePositionX(0);
90 canvasNode_->SetBgImagePositionY(0);
91 if (rosenImage_ == nullptr) {
92 HILOG_ERROR("rosenImage_ is nullptr.");
93 return;
94 }
95 rosenImage_->SetPixelMap(bgpixelmap_);
96 rosenImage_->SetImageFit(static_cast<int>(Rosen::ImageFit::FILL));
97 canvasNode_->SetBgImage(rosenImage_);
98 if (menuWindow_ == nullptr) {
99 HILOG_ERROR("create failed");
100 return;
101 }
102 menuWindow_->Show();
103 }
104
ShowMenuWindow(uint32_t mode)105 void MagnificationMenu::ShowMenuWindow(uint32_t mode)
106 {
107 HILOG_INFO();
108 menuMode_ = mode;
109 if (currentType_ != SWITCH_MAGNIFICATION) {
110 HILOG_WARN("no need show menu.");
111 return;
112 }
113
114 if (menuWindow_ == nullptr) {
115 HILOG_ERROR("window is null. need create.");
116 CreateMenuWindow();
117 }
118
119 if (menuWindow_ == nullptr) {
120 HILOG_ERROR("create window failed.");
121 return;
122 }
123
124 LoadMenuBgImage(mode);
125 FlushImplicitTransaction();
126 isMenuShown_ = true;
127 }
128
DisableMenuWindow()129 void MagnificationMenu::DisableMenuWindow()
130 {
131 HILOG_INFO();
132 if (!isMenuShown_) {
133 HILOG_INFO("menu not shown.");
134 return;
135 }
136 if (surfaceNode_ != nullptr) {
137 surfaceNode_->SetVisible(false);
138 surfaceNode_->ClearChildren();
139 FlushImplicitTransaction();
140 }
141
142 isMenuShown_ = false;
143 if (menuWindow_ != nullptr) {
144 menuWindow_->Hide();
145 menuWindow_->Destroy();
146 menuWindow_ = nullptr;
147 }
148 surfaceNode_ = nullptr;
149 canvasNode_ = nullptr;
150 rsUIContext_ = nullptr;
151 bgpixelmap_ = nullptr;
152 rosenImage_ = nullptr;
153 }
154
MoveMenuWindow(int32_t deltaX,int32_t deltaY)155 void MagnificationMenu::MoveMenuWindow(int32_t deltaX, int32_t deltaY)
156 {
157 HILOG_DEBUG();
158 if (menuWindow_ == nullptr) {
159 HILOG_ERROR("menuWindow_ is null.");
160 return;
161 }
162 int32_t menuPosX = menuRect_.posX_ + deltaX;
163 int32_t menuPosY = menuRect_.posY_ + deltaY;
164
165 menuRect_.posX_ = menuPosX;
166 menuRect_.posY_ = menuPosY;
167
168 AdjustMenuPosition();
169 menuWindow_->MoveTo(menuRect_.posX_, menuRect_.posY_);
170 }
171
AttachToEdge()172 void MagnificationMenu::AttachToEdge()
173 {
174 if (menuWindow_ == nullptr) {
175 HILOG_ERROR("menuWindow_ is null.");
176 return;
177 }
178
179 if (menuRect_.posX_ < static_cast<int32_t>(screenWidth_ / DIVISOR_TWO)) {
180 menuRect_.posX_ = margin_;
181 } else {
182 menuRect_.posX_ = static_cast<int32_t>(screenWidth_ - menuSize_) - margin_;
183 }
184 menuWindow_->MoveTo(menuRect_.posX_, menuRect_.posY_);
185 }
186
SetCurrentType(uint32_t type)187 void MagnificationMenu::SetCurrentType(uint32_t type)
188 {
189 currentType_ = type;
190 }
191
IsTapOnMenu(int32_t posX,int32_t posY)192 bool MagnificationMenu::IsTapOnMenu(int32_t posX, int32_t posY)
193 {
194 if (!isMenuShown_) {
195 return false;
196 }
197 return ExtUtils::IsInRect(posX, posY, menuRect_);
198 }
199
ChangeMode()200 uint32_t MagnificationMenu::ChangeMode()
201 {
202 if (menuMode_ == WINDOW_MAGNIFICATION) {
203 menuMode_ = FULL_SCREEN_MAGNIFICATION;
204 return menuMode_;
205 }
206 if (menuMode_ == FULL_SCREEN_MAGNIFICATION) {
207 menuMode_ = WINDOW_MAGNIFICATION;
208 return menuMode_;
209 }
210 return 0;
211 }
212
AdjustMenuPosition()213 void MagnificationMenu::AdjustMenuPosition()
214 {
215 if (menuRect_.posX_ < margin_) {
216 menuRect_.posX_ = margin_;
217 }
218
219 if (menuRect_.posY_ < margin_) {
220 menuRect_.posY_ = margin_;
221 }
222
223 if (menuRect_.posX_ + static_cast<int32_t>(menuRect_.width_) + margin_ > static_cast<int32_t>(screenWidth_)) {
224 menuRect_.posX_ = static_cast<int32_t>(screenWidth_) - static_cast<int32_t>(menuRect_.width_) - margin_;
225 }
226
227 if (menuRect_.posY_ + static_cast<int32_t>(menuRect_.height_) + margin_ > static_cast<int32_t>(screenHeight_)) {
228 menuRect_.posY_ = static_cast<int32_t>(screenHeight_) - static_cast<int32_t>(menuRect_.height_) - margin_;
229 }
230 }
231
DecodePixelMap(const std::string & pathName,const Media::AllocatorType & allocatorType)232 std::shared_ptr<Media::PixelMap> MagnificationMenu::DecodePixelMap(
233 const std::string& pathName, const Media::AllocatorType& allocatorType)
234 {
235 uint32_t errCode = 0;
236 std::unique_ptr<Media::ImageSource> imageSource =
237 Media::ImageSource::CreateImageSource(pathName, Media::SourceOptions(), errCode);
238 if (imageSource == nullptr || errCode != 0) {
239 HILOG_ERROR("CreateImageSource failed.");
240 return nullptr;
241 }
242
243 Media::DecodeOptions decodeOpt;
244 decodeOpt.allocatorType = allocatorType;
245 std::shared_ptr<Media::PixelMap> pixelmap = imageSource->CreatePixelMap(decodeOpt, errCode);
246 if (pixelmap == nullptr || errCode != 0) {
247 HILOG_ERROR("CreatePixelMap failed.");
248 return nullptr;
249 }
250 return pixelmap;
251 }
252
GetWindowParam()253 void MagnificationMenu::GetWindowParam()
254 {
255 HILOG_DEBUG();
256 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
257 screenId_ = Rosen::DisplayManager::GetInstance().GetDefaultDisplayId();
258 sptr<Rosen::Display> display = Rosen::DisplayManager::GetInstance().GetDisplayById(screenId_);
259 if (display == nullptr) {
260 HILOG_ERROR("display is nullptr.");
261 return;
262 }
263 screenWidth_ = static_cast<uint32_t>(display->GetWidth());
264 screenHeight_ = static_cast<uint32_t>(display->GetHeight());
265 screenRect_ = {0, 0, screenWidth_, screenHeight_};
266 #else
267 HILOG_INFO("not support");
268 #endif
269 }
270
RefreshWindowParam()271 void MagnificationMenu::RefreshWindowParam()
272 {
273 HILOG_DEBUG();
274 if (isMenuShown_) {
275 DisableMenuWindow();
276 ShowMenuWindow(menuMode_);
277 } else {
278 GetWindowParam();
279 }
280 }
281
FlushImplicitTransaction()282 void MagnificationMenu::FlushImplicitTransaction()
283 {
284 if (rsUIContext_ != nullptr) {
285 auto rsTransaction = rsUIContext_->GetRSTransaction();
286 if (rsTransaction != nullptr) {
287 rsTransaction->FlushImplicitTransaction();
288 }
289 } else {
290 Rosen::RSTransaction::FlushImplicitTransaction();
291 }
292 }
293
IsMenuShown()294 bool MagnificationMenu::IsMenuShown()
295 {
296 return isMenuShown_;
297 }
298
ShowMenuWindow(uint32_t mode)299 extern "C" API_EXPORT void ShowMenuWindow(uint32_t mode)
300 {
301 instance.ShowMenuWindow(mode);
302 }
303
DisableMenuWindow()304 extern "C" API_EXPORT void DisableMenuWindow()
305 {
306 instance.DisableMenuWindow();
307 }
308
MoveMenuWindow(int32_t deltaX,int32_t deltaY)309 extern "C" API_EXPORT void MoveMenuWindow(int32_t deltaX, int32_t deltaY)
310 {
311 instance.MoveMenuWindow(deltaX, deltaY);
312 }
313
IsTapOnMenu(int32_t posX,int32_t posY)314 extern "C" API_EXPORT bool IsTapOnMenu(int32_t posX, int32_t posY)
315 {
316 return instance.IsTapOnMenu(posX, posY);
317 }
318
AttachToEdge()319 extern "C" API_EXPORT void AttachToEdge()
320 {
321 instance.AttachToEdge();
322 }
323
RefreshWindowParamMenu()324 extern "C" API_EXPORT void RefreshWindowParamMenu()
325 {
326 instance.RefreshWindowParam();
327 }
328
SetCurrentType(uint32_t type)329 extern "C" API_EXPORT void SetCurrentType(uint32_t type)
330 {
331 instance.SetCurrentType(type);
332 }
333
ChangeMode()334 extern "C" API_EXPORT uint32_t ChangeMode()
335 {
336 return instance.ChangeMode();
337 }
338
IsMenuShown()339 extern "C" API_EXPORT bool IsMenuShown()
340 {
341 return instance.IsMenuShown();
342 }
343 }
344 }
345 // LCOV_EXCL_STOP