1 /*
2 * Copyright (c) 2021-2022 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 "js_err_utils.h"
17 #include "js_window_stage.h"
18 #include "js_window.h"
19 #include "window_manager_hilog.h"
20 #include "permission.h"
21
22 namespace OHOS {
23 namespace Rosen {
24 using namespace AbilityRuntime;
25 namespace {
26 const int CONTENT_STORAGE_ARG = 2;
27 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "JsWindowStage"};
28 } // namespace
29
30 std::unique_ptr<JsWindowRegisterManager> g_listenerManager = std::make_unique<JsWindowRegisterManager>();
JsWindowStage(const std::shared_ptr<Rosen::WindowScene> & windowScene)31 JsWindowStage::JsWindowStage(const std::shared_ptr<Rosen::WindowScene>& windowScene)
32 : windowScene_(windowScene)
33 {
34 }
35
~JsWindowStage()36 JsWindowStage::~JsWindowStage()
37 {
38 }
39
Finalizer(napi_env env,void * data,void * hint)40 void JsWindowStage::Finalizer(napi_env env, void* data, void* hint)
41 {
42 WLOGI("[NAPI]Finalizer");
43 std::unique_ptr<JsWindowStage>(static_cast<JsWindowStage*>(data));
44 }
45
SetUIContent(napi_env env,napi_callback_info info)46 napi_value JsWindowStage::SetUIContent(napi_env env, napi_callback_info info)
47 {
48 WLOGFI("[NAPI]");
49 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
50 return (me != nullptr) ? me->OnSetUIContent(env, info) : nullptr;
51 }
52
GetMainWindow(napi_env env,napi_callback_info info)53 napi_value JsWindowStage::GetMainWindow(napi_env env, napi_callback_info info)
54 {
55 WLOGFD("[NAPI]GetMainWindow");
56 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
57 return (me != nullptr) ? me->OnGetMainWindow(env, info) : nullptr;
58 }
59
GetMainWindowSync(napi_env env,napi_callback_info info)60 napi_value JsWindowStage::GetMainWindowSync(napi_env env, napi_callback_info info)
61 {
62 WLOGFD("[NAPI]GetMainWindowSync");
63 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
64 return (me != nullptr) ? me->OnGetMainWindowSync(env, info) : nullptr;
65 }
66
On(napi_env env,napi_callback_info info)67 napi_value JsWindowStage::On(napi_env env, napi_callback_info info)
68 {
69 WLOGFD("[NAPI]On");
70 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
71 return (me != nullptr) ? me->OnEvent(env, info) : nullptr;
72 }
73
Off(napi_env env,napi_callback_info info)74 napi_value JsWindowStage::Off(napi_env env, napi_callback_info info)
75 {
76 WLOGFD("[NAPI]Off");
77 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
78 return (me != nullptr) ? me->OffEvent(env, info) : nullptr;
79 }
80
LoadContent(napi_env env,napi_callback_info info)81 napi_value JsWindowStage::LoadContent(napi_env env, napi_callback_info info)
82 {
83 WLOGFI("[NAPI]");
84 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
85 return (me != nullptr) ? me->OnLoadContent(env, info, false) : nullptr;
86 }
87
LoadContentByName(napi_env env,napi_callback_info info)88 napi_value JsWindowStage::LoadContentByName(napi_env env, napi_callback_info info)
89 {
90 WLOGFI("[NAPI]");
91 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
92 return (me != nullptr) ? me->OnLoadContent(env, info, true) : nullptr;
93 }
94
GetWindowMode(napi_env env,napi_callback_info info)95 napi_value JsWindowStage::GetWindowMode(napi_env env, napi_callback_info info)
96 {
97 WLOGFD("[NAPI]GetWindowMode");
98 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
99 return (me != nullptr) ? me->OnGetWindowMode(env, info) : nullptr;
100 }
101
CreateSubWindow(napi_env env,napi_callback_info info)102 napi_value JsWindowStage::CreateSubWindow(napi_env env, napi_callback_info info)
103 {
104 WLOGFD("[NAPI]CreateSubWindow");
105 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
106 return (me != nullptr) ? me->OnCreateSubWindow(env, info) : nullptr;
107 }
108
CreateSubWindowWithOptions(napi_env env,napi_callback_info info)109 napi_value JsWindowStage::CreateSubWindowWithOptions(napi_env env, napi_callback_info info)
110 {
111 WLOGFD("[NAPI]CreateSubWindowWithOptions");
112 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
113 return (me != nullptr) ? me->OnCreateSubWindowWithOptions(env, info) : nullptr;
114 }
115
GetSubWindow(napi_env env,napi_callback_info info)116 napi_value JsWindowStage::GetSubWindow(napi_env env, napi_callback_info info)
117 {
118 WLOGFD("[NAPI]GetSubWindow");
119 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
120 return (me != nullptr) ? me->OnGetSubWindow(env, info) : nullptr;
121 }
122
123 /** @note @window.hierarchy */
SetShowOnLockScreen(napi_env env,napi_callback_info info)124 napi_value JsWindowStage::SetShowOnLockScreen(napi_env env, napi_callback_info info)
125 {
126 WLOGFD("[NAPI]SetShowOnLockScreen");
127 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
128 return (me != nullptr) ? me->OnSetShowOnLockScreen(env, info) : nullptr;
129 }
130
DisableWindowDecor(napi_env env,napi_callback_info info)131 napi_value JsWindowStage::DisableWindowDecor(napi_env env, napi_callback_info info)
132 {
133 WLOGFD("[NAPI]DisableWindowDecor");
134 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
135 return (me != nullptr) ? me->OnDisableWindowDecor(env, info) : nullptr;
136 }
137
SetDefaultDensityEnabled(napi_env env,napi_callback_info info)138 napi_value JsWindowStage::SetDefaultDensityEnabled(napi_env env, napi_callback_info info)
139 {
140 TLOGD(WmsLogTag::WMS_LAYOUT, "SetDefaultDensityEnabled");
141 JsWindowStage* me = CheckParamsAndGetThis<JsWindowStage>(env, info);
142 return (me != nullptr) ? me->OnSetDefaultDensityEnabled(env, info) : nullptr;
143 }
144
OnSetUIContent(napi_env env,napi_callback_info info)145 napi_value JsWindowStage::OnSetUIContent(napi_env env, napi_callback_info info)
146 {
147 size_t argc = 4;
148 napi_value argv[4] = {nullptr};
149 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
150 if (argc < 2) { // 2: minimum param num
151 WLOGFE("[NAPI]Argc is invalid: %{public}zu", argc);
152 return NapiGetUndefined(env);
153 }
154
155 // Parse info->argv[0] as abilitycontext
156 auto objContext = argv[0];
157 if (objContext == nullptr) {
158 WLOGFE("[NAPI]Context is nullptr");
159 return NapiGetUndefined(env);
160 }
161
162 // Parse info->argv[1] as url
163 std::string contextUrl;
164 if (!ConvertFromJsValue(env, argv[1], contextUrl)) {
165 WLOGFE("[NAPI]Failed to convert parameter to url");
166 return NapiGetUndefined(env);
167 }
168
169 auto weakScene = windowScene_.lock();
170 if (weakScene == nullptr || weakScene->GetMainWindow() == nullptr) {
171 WLOGFE("[NAPI]WindowScene is null or window is null");
172 return NapiGetUndefined(env);
173 }
174 weakScene->GetMainWindow()->NapiSetUIContent(contextUrl, env, argv[CONTENT_STORAGE_ARG]);
175 return NapiGetUndefined(env);
176 }
177
OnGetMainWindow(napi_env env,napi_callback_info info)178 napi_value JsWindowStage::OnGetMainWindow(napi_env env, napi_callback_info info)
179 {
180 NapiAsyncTask::CompleteCallback complete =
181 [weak = windowScene_](napi_env env, NapiAsyncTask& task, int32_t status) {
182 auto weakScene = weak.lock();
183 if (weakScene == nullptr) {
184 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STAGE_ABNORMALLY));
185 WLOGFE("[NAPI]WindowScene_ is nullptr!");
186 return;
187 }
188 auto window = weakScene->GetMainWindow();
189 if (window != nullptr) {
190 task.Resolve(env, OHOS::Rosen::CreateJsWindowObject(env, window));
191 WLOGI("[NAPI]Get main window [%{public}u, %{public}s]",
192 window->GetWindowId(), window->GetWindowName().c_str());
193 } else {
194 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY,
195 "Get main window failed."));
196 }
197 };
198 size_t argc = 4;
199 napi_value argv[4] = {nullptr};
200 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
201 napi_value callback = (argv[0] != nullptr && GetType(env, argv[0]) == napi_function) ?
202 argv[0] : nullptr;
203 napi_value result = nullptr;
204 NapiAsyncTask::Schedule("JsWindowStage::OnGetMainWindow",
205 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
206 return result;
207 }
208
OnGetMainWindowSync(napi_env env,napi_callback_info info)209 napi_value JsWindowStage::OnGetMainWindowSync(napi_env env, napi_callback_info info)
210 {
211 auto weakScene = windowScene_.lock();
212 if (weakScene == nullptr) {
213 WLOGFE("[NAPI]WindowScene is null");
214 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STAGE_ABNORMALLY));
215 return NapiGetUndefined(env);
216 }
217 auto window = weakScene->GetMainWindow();
218 if (window == nullptr) {
219 WLOGFE("[NAPI]window is null");
220 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
221 return NapiGetUndefined(env);
222 }
223
224 return OHOS::Rosen::CreateJsWindowObject(env, window);
225 }
226
OnEvent(napi_env env,napi_callback_info info)227 napi_value JsWindowStage::OnEvent(napi_env env, napi_callback_info info)
228 {
229 auto weakScene = windowScene_.lock();
230 if (weakScene == nullptr) {
231 WLOGFE("[NAPI]Window scene is null");
232 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
233 return NapiGetUndefined(env);
234 }
235 size_t argc = 4;
236 napi_value argv[4] = {nullptr};
237 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
238 if (argc < 2) { // 2: minimum param nums
239 WLOGFE("[NAPI]argc is invalid: %{public}zu", argc);
240 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
241 return NapiGetUndefined(env);
242 }
243
244 // Parse argv[0] as string
245 std::string eventString;
246 if (!ConvertFromJsValue(env, argv[0], eventString)) {
247 WLOGFE("[NAPI]Failed to convert parameter to string");
248 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
249 return NapiGetUndefined(env);
250 }
251 napi_value value = argv[1];
252 if (!NapiIsCallable(env, value)) {
253 WLOGFE("[NAPI]Callback(argv[1]) is not callable");
254 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
255 return NapiGetUndefined(env);
256 }
257
258 auto window = weakScene->GetMainWindow();
259 if (window == nullptr) {
260 WLOGFE("[NAPI]Get window failed");
261 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
262 return NapiGetUndefined(env);
263 }
264 g_listenerManager->RegisterListener(window, eventString, CaseType::CASE_STAGE, env, value);
265 WLOGI("[NAPI]Window [%{public}u, %{public}s] register event %{public}s",
266 window->GetWindowId(), window->GetWindowName().c_str(), eventString.c_str());
267
268 return NapiGetUndefined(env);
269 }
270
OffEvent(napi_env env,napi_callback_info info)271 napi_value JsWindowStage::OffEvent(napi_env env, napi_callback_info info)
272 {
273 auto weakScene = windowScene_.lock();
274 if (weakScene == nullptr) {
275 WLOGFE("[NAPI]Window scene is null");
276 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
277 return NapiGetUndefined(env);
278 }
279 size_t argc = 4;
280 napi_value argv[4] = {nullptr};
281 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
282 // Parse argv[0] as string
283 std::string eventString;
284 if (!ConvertFromJsValue(env, argv[0], eventString)) {
285 WLOGFE("[NAPI]Failed to convert parameter to string");
286 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
287 return NapiGetUndefined(env);
288 }
289 if (eventString.compare("windowStageEvent") != 0) {
290 WLOGFE("[NAPI]Envent %{public}s is invalid", eventString.c_str());
291 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
292 return NapiGetUndefined(env);
293 }
294
295 auto window = weakScene->GetMainWindow();
296 if (window == nullptr) {
297 WLOGFE("[NAPI]Get window failed");
298 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
299 return NapiGetUndefined(env);
300 }
301 napi_value value = nullptr;
302 if (argc == 1) {
303 g_listenerManager->UnregisterListener(window, eventString, CaseType::CASE_STAGE, env, nullptr);
304 } else {
305 value = argv[1];
306 if (value != nullptr && GetType(env, value) == napi_function) {
307 g_listenerManager->UnregisterListener(window, eventString, CaseType::CASE_STAGE, env, value);
308 } else {
309 g_listenerManager->UnregisterListener(window, eventString, CaseType::CASE_STAGE, env, nullptr);
310 }
311 }
312 WLOGI("[NAPI]Window [%{public}u, %{public}s] unregister event %{public}s",
313 window->GetWindowId(), window->GetWindowName().c_str(), eventString.c_str());
314
315 return NapiGetUndefined(env);
316 }
317
LoadContentTask(std::shared_ptr<NativeReference> contentStorage,std::string contextUrl,sptr<Window> weakWindow,napi_env env,NapiAsyncTask & task,bool isLoadedByName)318 static void LoadContentTask(std::shared_ptr<NativeReference> contentStorage, std::string contextUrl,
319 sptr<Window> weakWindow, napi_env env, NapiAsyncTask& task, bool isLoadedByName)
320 {
321 napi_value nativeStorage = (contentStorage == nullptr) ? nullptr : contentStorage->GetNapiValue();
322 WMError ret;
323 if (isLoadedByName) {
324 ret = weakWindow->SetUIContentByName(contextUrl, env, nativeStorage);
325 } else {
326 ret = weakWindow->NapiSetUIContent(contextUrl, env, nativeStorage, false);
327 }
328 if (ret == WMError::WM_OK) {
329 task.Resolve(env, NapiGetUndefined(env));
330 } else {
331 task.Reject(env, JsErrUtils::CreateJsError(env, WM_JS_TO_ERROR_CODE_MAP.at(ret),
332 "Window load content failed"));
333 }
334 WLOGI("[NAPI]Window [%{public}u, %{public}s] load content end, ret = %{public}d",
335 weakWindow->GetWindowId(), weakWindow->GetWindowName().c_str(), ret);
336 return;
337 }
338
OnLoadContent(napi_env env,napi_callback_info info,bool isLoadedByName)339 napi_value JsWindowStage::OnLoadContent(napi_env env, napi_callback_info info, bool isLoadedByName)
340 {
341 WmErrorCode errCode = WmErrorCode::WM_OK;
342 std::string contextUrl;
343 size_t argc = 4;
344 napi_value argv[4] = {nullptr};
345 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
346 if (!ConvertFromJsValue(env, argv[0], contextUrl)) {
347 WLOGFE("[NAPI]Failed to convert parameter to context url");
348 errCode = WmErrorCode::WM_ERROR_INVALID_PARAM;
349 }
350 napi_value storage = nullptr;
351 napi_value callBack = nullptr;
352 napi_value value1 = argv[1];
353 napi_value value2 = argv[2]; // 2: param index
354 if (GetType(env, value1) == napi_function) {
355 callBack = value1;
356 } else if (GetType(env, value1) == napi_object) {
357 storage = value1;
358 }
359 if (GetType(env, value2) == napi_function) {
360 callBack = value2;
361 }
362 if (errCode == WmErrorCode::WM_ERROR_INVALID_PARAM) {
363 WLOGFE("[NAPI]Window scene is null or get invalid param");
364 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
365 return NapiGetUndefined(env);
366 }
367
368 std::shared_ptr<NativeReference> contentStorage = nullptr;
369 if (storage != nullptr) {
370 napi_ref result = nullptr;
371 napi_create_reference(env, storage, 1, &result);
372 contentStorage = std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(result));
373 }
374
375 NapiAsyncTask::CompleteCallback complete =
376 [weak = windowScene_, contentStorage, contextUrl, isLoadedByName](
377 napi_env env, NapiAsyncTask& task, int32_t status) {
378 auto weakScene = weak.lock();
379 sptr<Window> win = weakScene ? weakScene->GetMainWindow() : nullptr;
380 if (win == nullptr) {
381 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
382 WLOGFE("[NAPI]Get window failed");
383 return;
384 }
385 LoadContentTask(contentStorage, contextUrl, win, env, task, isLoadedByName);
386 };
387 napi_value result = nullptr;
388 NapiAsyncTask::Schedule("JsWindowStage::OnLoadContent",
389 env, CreateAsyncTaskWithLastParam(env, callBack, nullptr, std::move(complete), &result));
390 return result;
391 }
392
OnGetWindowMode(napi_env env,napi_callback_info info)393 napi_value JsWindowStage::OnGetWindowMode(napi_env env, napi_callback_info info)
394 {
395 NapiAsyncTask::CompleteCallback complete =
396 [weak = windowScene_](napi_env env, NapiAsyncTask& task, int32_t status) {
397 auto weakScene = weak.lock();
398 if (weakScene == nullptr) {
399 task.Reject(env, JsErrUtils::CreateJsError(env, WMError::WM_ERROR_NULLPTR));
400 WLOGFE("[NAPI]windowScene_ is nullptr");
401 return;
402 }
403 auto window = weakScene->GetMainWindow();
404 if (window == nullptr) {
405 task.Reject(env, JsErrUtils::CreateJsError(env, WMError::WM_ERROR_NULLPTR, "Get window failed"));
406 WLOGFE("[NAPI]Get window failed");
407 return;
408 }
409 Rosen::WindowMode mode = window->GetMode();
410 if (NATIVE_TO_JS_WINDOW_MODE_MAP.count(mode) != 0) {
411 task.Resolve(env, CreateJsValue(env, NATIVE_TO_JS_WINDOW_MODE_MAP.at(mode)));
412 WLOGI("[NAPI]Window [%{public}u, %{public}s] get mode %{public}u, api mode %{public}u",
413 window->GetWindowId(), window->GetWindowName().c_str(),
414 mode, NATIVE_TO_JS_WINDOW_MODE_MAP.at(mode));
415 } else {
416 task.Resolve(env, CreateJsValue(env, mode));
417 WLOGFE("[NAPI]Get mode %{public}u, but not in apimode", mode);
418 }
419 };
420
421 size_t argc = 4;
422 napi_value argv[4] = {nullptr};
423 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
424 napi_value callback = (GetType(env, argv[0]) == napi_function) ? argv[0] : nullptr;
425 napi_value result = nullptr;
426 NapiAsyncTask::Schedule("JsWindowStage::OnGetWindowMode",
427 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
428 return result;
429 }
430
OnCreateSubWindow(napi_env env,napi_callback_info info)431 napi_value JsWindowStage::OnCreateSubWindow(napi_env env, napi_callback_info info)
432 {
433 WmErrorCode errCode = WmErrorCode::WM_OK;
434 std::string windowName;
435 size_t argc = 4;
436 napi_value argv[4] = {nullptr};
437 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
438 if (!ConvertFromJsValue(env, argv[0], windowName)) {
439 WLOGFE("[NAPI]Failed to convert parameter to windowName");
440 errCode = WmErrorCode::WM_ERROR_INVALID_PARAM;
441 }
442 if (errCode == WmErrorCode::WM_ERROR_INVALID_PARAM) {
443 WLOGFE("[NAPI]get invalid param");
444 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
445 return NapiGetUndefined(env);
446 }
447 NapiAsyncTask::CompleteCallback complete =
448 [weak = windowScene_, windowName](napi_env env, NapiAsyncTask& task, int32_t status) {
449 auto weakScene = weak.lock();
450 if (weakScene == nullptr) {
451 WLOGFE("[NAPI]Window scene is null");
452 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
453 return;
454 }
455 sptr<Rosen::WindowOption> windowOption = new Rosen::WindowOption();
456 windowOption->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_SUB_WINDOW);
457 windowOption->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING);
458 auto window = weakScene->CreateWindow(windowName, windowOption);
459 if (window == nullptr) {
460 WLOGFE("[NAPI]Get window failed");
461 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY,
462 "Get window failed"));
463 return;
464 }
465 task.Resolve(env, CreateJsWindowObject(env, window));
466 WLOGI("[NAPI]Create sub window %{public}s end", windowName.c_str());
467 };
468 napi_value callback = (argv[1] != nullptr && GetType(env, argv[1]) == napi_function) ? argv[1] : nullptr;
469 napi_value result = nullptr;
470 NapiAsyncTask::Schedule("JsWindowStage::OnCreateSubWindow",
471 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
472 return result;
473 }
474
CreateJsSubWindowArrayObject(napi_env env,std::vector<sptr<Window>> subWinVec)475 static napi_value CreateJsSubWindowArrayObject(napi_env env,
476 std::vector<sptr<Window>> subWinVec)
477 {
478 napi_value arrayValue = nullptr;
479 napi_create_array_with_length(env, subWinVec.size(), &arrayValue);
480 if (arrayValue == nullptr) {
481 WLOGFE("[NAPI]Failed to convert subWinVec to jsArrayObject");
482 return nullptr;
483 }
484 uint32_t index = 0;
485 for (size_t i = 0; i < subWinVec.size(); i++) {
486 napi_set_element(env, arrayValue, index++, CreateJsWindowObject(env, subWinVec[i]));
487 }
488 return arrayValue;
489 }
490
OnGetSubWindow(napi_env env,napi_callback_info info)491 napi_value JsWindowStage::OnGetSubWindow(napi_env env, napi_callback_info info)
492 {
493 NapiAsyncTask::CompleteCallback complete =
494 [weak = windowScene_](napi_env env, NapiAsyncTask& task, int32_t status) {
495 auto weakScene = weak.lock();
496 if (weakScene == nullptr) {
497 WLOGFE("[NAPI]Window scene is nullptr");
498 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
499 return;
500 }
501 std::vector<sptr<Window>> subWindowVec = weakScene->GetSubWindow();
502 task.Resolve(env, CreateJsSubWindowArrayObject(env, subWindowVec));
503 WLOGI("[NAPI]Get sub windows, size = %{public}zu", subWindowVec.size());
504 };
505 size_t argc = 4;
506 napi_value argv[4] = {nullptr};
507 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
508 napi_value callback = (argv[0] != nullptr && GetType(env, argv[0]) == napi_function) ? argv[0] : nullptr;
509 napi_value result = nullptr;
510 NapiAsyncTask::Schedule("JsWindowStage::OnGetSubWindow",
511 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
512 return result;
513 }
514
OnSetShowOnLockScreen(napi_env env,napi_callback_info info)515 napi_value JsWindowStage::OnSetShowOnLockScreen(napi_env env, napi_callback_info info)
516 {
517 if (!Permission::IsSystemCalling() && !Permission::IsStartByHdcd()) {
518 WLOGFE("set show on lock screen permission denied!");
519 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_NOT_SYSTEM_APP));
520 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_NOT_SYSTEM_APP));
521 }
522
523 size_t argc = 4;
524 napi_value argv[4] = {nullptr};
525 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
526 if (argc < 1) {
527 WLOGFE("[NAPI]Argc is invalid: %{public}zu", argc);
528 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
529 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM));
530 }
531 auto weakScene = windowScene_.lock();
532 if (weakScene == nullptr || weakScene->GetMainWindow() == nullptr) {
533 WLOGFE("[NAPI]WindowScene is null or window is null");
534 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
535 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
536 }
537
538 bool showOnLockScreen = false;
539 napi_value nativeVal = argv[0];
540 if (nativeVal == nullptr) {
541 WLOGFE("[NAPI]Failed to convert parameter to boolean");
542 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
543 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM));
544 } else {
545 napi_get_value_bool(env, nativeVal, &showOnLockScreen);
546 }
547
548 auto window = weakScene->GetMainWindow();
549 WmErrorCode ret;
550 if (showOnLockScreen) {
551 ret = WM_JS_TO_ERROR_CODE_MAP.at(
552 window->AddWindowFlag(WindowFlag::WINDOW_FLAG_SHOW_WHEN_LOCKED));
553 } else {
554 ret = WM_JS_TO_ERROR_CODE_MAP.at(
555 window->RemoveWindowFlag(WindowFlag::WINDOW_FLAG_SHOW_WHEN_LOCKED));
556 }
557 WLOGI("[NAPI]Window [%{public}u, %{public}s] SetShowOnLockScreen %{public}u, ret = %{public}u",
558 window->GetWindowId(), window->GetWindowName().c_str(), showOnLockScreen, ret);
559
560 return CreateJsValue(env, static_cast<int32_t>(ret));
561 }
562
OnDisableWindowDecor(napi_env env,napi_callback_info info)563 napi_value JsWindowStage::OnDisableWindowDecor(napi_env env, napi_callback_info info)
564 {
565 auto weakScene = windowScene_.lock();
566 if (weakScene == nullptr) {
567 WLOGFE("[NAPI]WindowScene is null");
568 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STAGE_ABNORMALLY));
569 }
570
571 auto window = weakScene->GetMainWindow();
572 if (window == nullptr) {
573 WLOGFE("[NAPI]Window is null");
574 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
575 }
576 WmErrorCode ret = WM_JS_TO_ERROR_CODE_MAP.at(window->DisableAppWindowDecor());
577 if (ret != WmErrorCode::WM_OK) {
578 napi_throw(env, JsErrUtils::CreateJsError(env, ret));
579 WLOGI("[NAPI]Window [%{public}u, %{public}s] disable app window decor end",
580 window->GetWindowId(), window->GetWindowName().c_str());
581 return NapiGetUndefined(env);
582 }
583 return NapiGetUndefined(env);
584 }
585
OnSetDefaultDensityEnabled(napi_env env,napi_callback_info info)586 napi_value JsWindowStage::OnSetDefaultDensityEnabled(napi_env env, napi_callback_info info)
587 {
588 size_t argc = 4;
589 napi_value argv[4] = {nullptr};
590 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
591 if (argc != 1) {
592 TLOGE(WmsLogTag::WMS_LAYOUT, "Argc is invalid: %{public}zu", argc);
593 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
594 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM));
595 }
596
597 auto weakScene = windowScene_.lock();
598 if (weakScene == nullptr) {
599 TLOGE(WmsLogTag::WMS_LAYOUT, "WindowScene is null");
600 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STAGE_ABNORMALLY));
601 }
602
603 auto window = weakScene->GetMainWindow();
604 if (window == nullptr) {
605 TLOGE(WmsLogTag::WMS_LAYOUT, "Window is null");
606 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
607 }
608
609 bool enabled = false;
610 if (!ConvertFromJsValue(env, argv[0], enabled)) {
611 TLOGE(WmsLogTag::WMS_LAYOUT, "Failed to convert parameter to boolean");
612 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
613 return CreateJsValue(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM));
614 }
615
616 WmErrorCode ret = WM_JS_TO_ERROR_CODE_MAP.at(window->SetDefaultDensityEnabled(enabled));
617 TLOGI(WmsLogTag::WMS_LAYOUT, "Window [%{public}u,%{public}s] SetDefaultDensityEnabled=%{public}u ret=%{public}u",
618 window->GetWindowId(), window->GetWindowName().c_str(), enabled, ret);
619
620 return CreateJsValue(env, static_cast<int32_t>(ret));
621 }
622
OnCreateSubWindowWithOptions(napi_env env,napi_callback_info info)623 napi_value JsWindowStage::OnCreateSubWindowWithOptions(napi_env env, napi_callback_info info)
624 {
625 std::string windowName;
626 size_t argc = 4;
627 napi_value argv[4] = {nullptr};
628 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
629 if (!ConvertFromJsValue(env, argv[0], windowName)) {
630 WLOGFE("[NAPI]Failed to convert parameter to windowName");
631 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
632 return NapiGetUndefined(env);
633 }
634 WindowOption option;
635 if (!ParseSubWindowOptions(env, argv[1], option)) {
636 WLOGFE("[NAPI]get invalid options param");
637 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_INVALID_PARAM));
638 return NapiGetUndefined(env);
639 }
640
641 if (option.GetWindowTopmost() && !Permission::IsSystemCalling() && !Permission::IsStartByHdcd()) {
642 TLOGE(WmsLogTag::WMS_SUB, "Modal subwindow has topmost, but no system permission");
643 napi_throw(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_NOT_SYSTEM_APP));
644 return NapiGetUndefined(env);
645 }
646
647 NapiAsyncTask::CompleteCallback complete =
648 [weak = windowScene_, windowName, option](napi_env env, NapiAsyncTask& task, int32_t status) {
649 auto weakScene = weak.lock();
650 if (weakScene == nullptr) {
651 WLOGFE("[NAPI]Window scene is null");
652 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY));
653 return;
654 }
655 sptr<Rosen::WindowOption> windowOption = new Rosen::WindowOption(option);
656 windowOption->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_SUB_WINDOW);
657 windowOption->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING);
658 windowOption->SetOnlySupportSceneBoard(true);
659 auto window = weakScene->CreateWindow(windowName, windowOption);
660 if (window == nullptr) {
661 WLOGFE("[NAPI]Get window failed");
662 task.Reject(env, JsErrUtils::CreateJsError(env, WmErrorCode::WM_ERROR_STATE_ABNORMALLY,
663 "Get window failed"));
664 return;
665 }
666 task.Resolve(env, CreateJsWindowObject(env, window));
667 WLOGI("[NAPI]Create sub window %{public}s end", windowName.c_str());
668 };
669 napi_value callback = (argv[2] != nullptr && GetType(env, argv[2]) == napi_function) ? argv[2] : nullptr;
670 napi_value result = nullptr;
671 NapiAsyncTask::Schedule("JsWindowStage::OnCreateSubWindowWithOptions",
672 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
673 return result;
674 }
675
ParseSubWindowOptions(napi_env env,napi_value jsObject,WindowOption & option)676 bool JsWindowStage::ParseSubWindowOptions(napi_env env, napi_value jsObject, WindowOption& option)
677 {
678 if (jsObject == nullptr) {
679 WLOGFW("jsObject is null");
680 return true;
681 }
682
683 std::string title;
684 if (ParseJsValue(jsObject, env, "title", title)) {
685 option.SetSubWindowTitle(title);
686 } else {
687 WLOGFE("Failed to convert parameter to title");
688 return false;
689 }
690
691 bool decorEnabled;
692 if (ParseJsValue(jsObject, env, "decorEnabled", decorEnabled)) {
693 option.SetSubWindowDecorEnable(decorEnabled);
694 } else {
695 WLOGFE("Failed to convert parameter to decorEnabled");
696 return false;
697 }
698
699 bool isModal = false;
700 if (ParseJsValue(jsObject, env, "isModal", isModal)) {
701 TLOGI(WmsLogTag::WMS_SUB, "isModal:%{public}d", isModal);
702 if (isModal) {
703 option.AddWindowFlag(WindowFlag::WINDOW_FLAG_IS_MODAL);
704 }
705 }
706
707 bool isTopmost = false;
708 if (ParseJsValue(jsObject, env, "isTopmost", isTopmost)) {
709 if (!isModal && isTopmost) {
710 TLOGE(WmsLogTag::WMS_SUB, "Normal subwindow is topmost");
711 return false;
712 }
713 option.SetWindowTopmost(isTopmost);
714 }
715
716 return true;
717 }
718
CreateJsWindowStage(napi_env env,std::shared_ptr<Rosen::WindowScene> windowScene)719 napi_value CreateJsWindowStage(napi_env env, std::shared_ptr<Rosen::WindowScene> windowScene)
720 {
721 WLOGFD("[NAPI]CreateJsWindowStage");
722 napi_value objValue = nullptr;
723 napi_create_object(env, &objValue);
724
725 std::unique_ptr<JsWindowStage> jsWindowStage = std::make_unique<JsWindowStage>(windowScene);
726 napi_wrap(env, objValue, jsWindowStage.release(), JsWindowStage::Finalizer, nullptr, nullptr);
727
728 const char* moduleName = "JsWindowStage";
729 BindNativeFunction(env,
730 objValue, "setUIContent", moduleName, JsWindowStage::SetUIContent);
731 BindNativeFunction(env,
732 objValue, "loadContent", moduleName, JsWindowStage::LoadContent);
733 BindNativeFunction(env,
734 objValue, "loadContentByName", moduleName, JsWindowStage::LoadContentByName);
735 BindNativeFunction(env,
736 objValue, "getMainWindow", moduleName, JsWindowStage::GetMainWindow);
737 BindNativeFunction(env,
738 objValue, "getMainWindowSync", moduleName, JsWindowStage::GetMainWindowSync);
739 BindNativeFunction(env,
740 objValue, "getWindowMode", moduleName, JsWindowStage::GetWindowMode);
741 BindNativeFunction(env,
742 objValue, "createSubWindow", moduleName, JsWindowStage::CreateSubWindow);
743 BindNativeFunction(env,
744 objValue, "createSubWindowWithOptions", moduleName, JsWindowStage::CreateSubWindowWithOptions);
745 BindNativeFunction(env,
746 objValue, "getSubWindow", moduleName, JsWindowStage::GetSubWindow);
747 BindNativeFunction(env, objValue, "on", moduleName, JsWindowStage::On);
748 BindNativeFunction(env, objValue, "off", moduleName, JsWindowStage::Off);
749 BindNativeFunction(env,
750 objValue, "setShowOnLockScreen", moduleName, JsWindowStage::SetShowOnLockScreen);
751 BindNativeFunction(env,
752 objValue, "disableWindowDecor", moduleName, JsWindowStage::DisableWindowDecor);
753 BindNativeFunction(env,
754 objValue, "setDefaultDensityEnabled", moduleName, JsWindowStage::SetDefaultDensityEnabled);
755
756 return objValue;
757 }
758 } // namespace Rosen
759 } // namespace OHOS
760