• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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