1 /*
2 * Copyright (c) 2024 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_embeddable_window_stage.h"
17 #include <string>
18 #include "js_runtime_utils.h"
19 #include "js_extension_window.h"
20 #include "js_extension_window_utils.h"
21 #include "window_manager_hilog.h"
22 #include "permission.h"
23
24 namespace OHOS {
25 namespace Rosen {
26 using namespace AbilityRuntime;
27
JsEmbeddableWindowStage(sptr<Rosen::Window> window,sptr<AAFwk::SessionInfo> sessionInfo)28 JsEmbeddableWindowStage::JsEmbeddableWindowStage(sptr<Rosen::Window> window, sptr<AAFwk::SessionInfo> sessionInfo)
29 : windowExtensionSessionImpl_(window), sessionInfo_(sessionInfo),
30 extwinRegisterManager_(std::make_unique<JsExtensionWindowRegisterManager>())
31 {
32 }
33
~JsEmbeddableWindowStage()34 JsEmbeddableWindowStage::~JsEmbeddableWindowStage()
35 {
36 }
37
Finalizer(napi_env env,void * data,void * hint)38 void JsEmbeddableWindowStage::Finalizer(napi_env env, void* data, void* hint)
39 {
40 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Finalizer");
41 std::unique_ptr<JsEmbeddableWindowStage>(static_cast<JsEmbeddableWindowStage*>(data));
42 }
43
GetMainWindow(napi_env env,napi_callback_info info)44 napi_value JsEmbeddableWindowStage::GetMainWindow(napi_env env, napi_callback_info info)
45 {
46 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]GetMainWindow");
47 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
48 return (me != nullptr) ? me->OnGetMainWindow(env, info) : nullptr;
49 }
50
GetMainWindowSync(napi_env env,napi_callback_info info)51 napi_value JsEmbeddableWindowStage::GetMainWindowSync(napi_env env, napi_callback_info info)
52 {
53 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]GetMainWindowSync");
54 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
55 return (me != nullptr) ? me->OnGetMainWindowSync(env, info) : nullptr;
56 }
57
On(napi_env env,napi_callback_info info)58 napi_value JsEmbeddableWindowStage::On(napi_env env, napi_callback_info info)
59 {
60 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]On");
61 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
62 return (me != nullptr) ? me->OnEvent(env, info) : nullptr;
63 }
64
Off(napi_env env,napi_callback_info info)65 napi_value JsEmbeddableWindowStage::Off(napi_env env, napi_callback_info info)
66 {
67 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]Off");
68 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
69 return (me != nullptr) ? me->OffEvent(env, info) : nullptr;
70 }
71
LoadContent(napi_env env,napi_callback_info info)72 napi_value JsEmbeddableWindowStage::LoadContent(napi_env env, napi_callback_info info)
73 {
74 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]LoadContent");
75 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
76 return (me != nullptr) ? me->OnLoadContent(env, info, false) : nullptr;
77 }
78
LoadContentByName(napi_env env,napi_callback_info info)79 napi_value JsEmbeddableWindowStage::LoadContentByName(napi_env env, napi_callback_info info)
80 {
81 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]LoadContentByName");
82 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
83 return (me != nullptr) ? me->OnLoadContent(env, info, true) : nullptr;
84 }
85
CreateSubWindow(napi_env env,napi_callback_info info)86 napi_value JsEmbeddableWindowStage::CreateSubWindow(napi_env env, napi_callback_info info)
87 {
88 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]CreateSubWindow");
89 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
90 return (me != nullptr) ? me->OnCreateSubWindow(env, info) : nullptr;
91 }
92
GetSubWindow(napi_env env,napi_callback_info info)93 napi_value JsEmbeddableWindowStage::GetSubWindow(napi_env env, napi_callback_info info)
94 {
95 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]GetSubWindow");
96 JsEmbeddableWindowStage* me = CheckParamsAndGetThis<JsEmbeddableWindowStage>(env, info);
97 return (me != nullptr) ? me->OnGetSubWindow(env, info) : nullptr;
98 }
99
OnGetSubWindow(napi_env env,napi_callback_info info)100 napi_value JsEmbeddableWindowStage::OnGetSubWindow(napi_env env, napi_callback_info info)
101 {
102 NapiAsyncTask::CompleteCallback complete =
103 [](napi_env env, NapiAsyncTask& task, int32_t status) {
104 task.Reject(env, CreateJsError(env,
105 static_cast<int32_t>(WmErrorCode::WM_ERROR_DEVICE_NOT_SUPPORT)));
106 };
107 size_t argc = 4;
108 napi_value argv[4] = {nullptr};
109 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
110 napi_value callback = (argv[0] != nullptr && GetType(env, argv[0]) == napi_function) ? argv[0] : nullptr;
111 napi_value result = nullptr;
112 NapiAsyncTask::Schedule("JsEmbeddableWindowStage::OnGetSubWindow",
113 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
114 return result;
115 }
116
OnCreateSubWindow(napi_env env,napi_callback_info info)117 napi_value JsEmbeddableWindowStage::OnCreateSubWindow(napi_env env, napi_callback_info info)
118 {
119 std::string windowName;
120 size_t argc = 4;
121 napi_value argv[4] = {nullptr};
122 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
123 NapiAsyncTask::CompleteCallback complete =
124 [](napi_env env, NapiAsyncTask& task, int32_t status) {
125 task.Reject(env, CreateJsError(env,
126 static_cast<int32_t>(WmErrorCode::WM_ERROR_DEVICE_NOT_SUPPORT)));
127 };
128 napi_value callback = (argv[1] != nullptr && GetType(env, argv[1]) == napi_function) ? argv[1] : nullptr;
129 napi_value result = nullptr;
130 NapiAsyncTask::Schedule("JsEmbeddableWindowStage::OnCreateSubWindow",
131 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
132 return result;
133 }
134
OnGetMainWindow(napi_env env,napi_callback_info info)135 napi_value JsEmbeddableWindowStage::OnGetMainWindow(napi_env env, napi_callback_info info)
136 {
137 NapiAsyncTask::CompleteCallback complete =
138 [windowImpl = windowExtensionSessionImpl_, sessionInfo = sessionInfo_]
139 (napi_env env, NapiAsyncTask& task, int32_t status) {
140 if (windowImpl != nullptr) {
141 task.Resolve(env, Rosen::JsExtensionWindow::CreateJsExtensionWindowObject(env,
142 windowImpl, sessionInfo));
143 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Get main window [%{public}u, %{public}s]",
144 windowImpl->GetWindowId(), windowImpl->GetWindowName().c_str());
145 } else {
146 task.Reject(env, CreateJsError(env,
147 static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY),
148 "Get main window failed."));
149 }
150 };
151 size_t argc = 4;
152 napi_value argv[4] = {nullptr};
153 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
154 napi_value callback = (argv[0] != nullptr && GetType(env, argv[0]) == napi_function) ?
155 argv[0] : nullptr;
156 napi_value result = nullptr;
157 NapiAsyncTask::Schedule("JsEmbeddableWindowStage::OnGetMainWindow",
158 env, CreateAsyncTaskWithLastParam(env, callback, nullptr, std::move(complete), &result));
159 return result;
160 }
161
OnGetMainWindowSync(napi_env env,napi_callback_info info)162 napi_value JsEmbeddableWindowStage::OnGetMainWindowSync(napi_env env, napi_callback_info info)
163 {
164 if (windowExtensionSessionImpl_ == nullptr) {
165 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]window is null");
166 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY)));
167 return NapiGetUndefined(env);
168 }
169
170 return Rosen::JsExtensionWindow::CreateJsExtensionWindowObject(env,
171 windowExtensionSessionImpl_, sessionInfo_);
172 }
173
OnEvent(napi_env env,napi_callback_info info)174 napi_value JsEmbeddableWindowStage::OnEvent(napi_env env, napi_callback_info info)
175 {
176 sptr<Window> windowImpl = windowExtensionSessionImpl_;
177 if (windowImpl == nullptr) {
178 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]windowImpl is null.");
179 return NapiGetUndefined(env);
180 }
181 size_t argc = 4;
182 napi_value argv[4] = {nullptr};
183 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
184 if (argc < 2) { // 2: minimum param nums
185 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]argc is invalid: %{public}zu", argc);
186 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
187 return NapiGetUndefined(env);
188 }
189
190 // Parse argv[0] as string
191 std::string eventString;
192 if (!ConvertFromJsValue(env, argv[0], eventString)) {
193 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Failed to convert parameter to string");
194 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
195 return NapiGetUndefined(env);
196 }
197 napi_value value = argv[1];
198 if (!NapiIsCallable(env, value)) {
199 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Callback(argv[1]) is not callable");
200 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
201 return NapiGetUndefined(env);
202 }
203
204 WmErrorCode ret = extwinRegisterManager_->RegisterListener(windowImpl, eventString,
205 CaseType::CASE_STAGE, env, value);
206 if (ret != WmErrorCode::WM_OK) {
207 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]RegisterListener fail");
208 return NapiThrowError(env, ret);
209 }
210 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Window [%{public}u, %{public}s] register event %{public}s",
211 windowImpl->GetWindowId(), windowImpl->GetWindowName().c_str(), eventString.c_str());
212
213 return NapiGetUndefined(env);
214 }
215
OffEvent(napi_env env,napi_callback_info info)216 napi_value JsEmbeddableWindowStage::OffEvent(napi_env env, napi_callback_info info)
217 {
218 sptr<Window> windowImpl = windowExtensionSessionImpl_;
219 if (windowImpl == nullptr) {
220 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]windowImpl is null");
221 return NapiGetUndefined(env);
222 }
223 size_t argc = 4;
224 napi_value argv[4] = {nullptr};
225 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
226 // Parse argv[0] as string
227 std::string eventString;
228 if (!ConvertFromJsValue(env, argv[0], eventString)) {
229 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Failed to convert parameter to string");
230 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
231 return NapiGetUndefined(env);
232 }
233 if (eventString.compare("windowStageEvent") != 0) {
234 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Envent %{public}s is invalid", eventString.c_str());
235 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
236 return NapiGetUndefined(env);
237 }
238
239 napi_value value = nullptr;
240 WmErrorCode ret = WmErrorCode::WM_OK;
241 if (argc == 1) {
242 ret = extwinRegisterManager_->UnregisterListener(windowImpl, eventString, CaseType::CASE_STAGE, env, nullptr);
243 } else {
244 value = argv[1];
245 if (value != nullptr && GetType(env, value) == napi_function) {
246 ret = extwinRegisterManager_->UnregisterListener(windowImpl, eventString, CaseType::CASE_STAGE, env, value);
247 } else {
248 ret = extwinRegisterManager_->UnregisterListener(windowImpl, eventString,
249 CaseType::CASE_STAGE, env, nullptr);
250 }
251 }
252 if (ret != WmErrorCode::WM_OK) {
253 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]UnregisterListener fail");
254 return NapiThrowError(env, ret);
255 }
256 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Window [%{public}u, %{public}s] unregister event %{public}s",
257 windowImpl->GetWindowId(), windowImpl->GetWindowName().c_str(), eventString.c_str());
258
259 return NapiGetUndefined(env);
260 }
261
LoadContentTask(std::shared_ptr<NativeReference> contentStorage,std::string contextUrl,sptr<Window> windowImpl,napi_env env,NapiAsyncTask & task,sptr<IRemoteObject> parentToken,bool isLoadedByName)262 static void LoadContentTask(std::shared_ptr<NativeReference> contentStorage, std::string contextUrl,
263 sptr<Window> windowImpl, napi_env env, NapiAsyncTask& task, sptr<IRemoteObject> parentToken,
264 bool isLoadedByName)
265 {
266 napi_value nativeStorage = (contentStorage == nullptr) ? nullptr : contentStorage->GetNapiValue();
267 WMError ret;
268 if (isLoadedByName) {
269 ret = windowImpl->SetUIContentByName(contextUrl, env, nativeStorage);
270 } else {
271 ret = windowImpl->NapiSetUIContent(contextUrl, env, nativeStorage, BackupAndRestoreType::NONE, parentToken);
272 }
273 if (ret == WMError::WM_OK) {
274 task.Resolve(env, NapiGetUndefined(env));
275 } else {
276 task.Reject(env, CreateJsError(env, static_cast<int32_t>(ret), "Window load content failed"));
277 }
278 TLOGI(WmsLogTag::WMS_UIEXT, "[NAPI]Window [%{public}u, %{public}s] load content end, ret = %{public}d",
279 windowImpl->GetWindowId(), windowImpl->GetWindowName().c_str(), ret);
280 }
281
OnLoadContent(napi_env env,napi_callback_info info,bool isLoadedByName)282 napi_value JsEmbeddableWindowStage::OnLoadContent(napi_env env, napi_callback_info info, bool isLoadedByName)
283 {
284 WmErrorCode errCode = WmErrorCode::WM_OK;
285 std::string contextUrl;
286 size_t argc = 4;
287 napi_value argv[4] = {nullptr};
288 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
289 if (!ConvertFromJsValue(env, argv[0], contextUrl)) {
290 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Failed to convert parameter to context url");
291 errCode = WmErrorCode::WM_ERROR_INVALID_PARAM;
292 }
293 napi_value storage = nullptr;
294 napi_value callBack = nullptr;
295 napi_value value1 = argv[1];
296 napi_value value2 = argv[2]; // 2: param index
297 if (GetType(env, value1) == napi_function) {
298 callBack = value1;
299 } else if (GetType(env, value1) == napi_object) {
300 storage = value1;
301 }
302 if (GetType(env, value2) == napi_function) {
303 callBack = value2;
304 }
305 if (errCode == WmErrorCode::WM_ERROR_INVALID_PARAM) {
306 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Window scene is null or get invalid param");
307 napi_throw(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_INVALID_PARAM)));
308 return NapiGetUndefined(env);
309 }
310
311 std::shared_ptr<NativeReference> contentStorage = nullptr;
312 if (storage != nullptr) {
313 napi_ref result = nullptr;
314 napi_create_reference(env, storage, 1, &result);
315 contentStorage = std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(result));
316 }
317
318 sptr<IRemoteObject> parentToken = sessionInfo_->parentToken;
319 NapiAsyncTask::CompleteCallback complete =
320 [window = windowExtensionSessionImpl_, contentStorage, contextUrl, parentToken, isLoadedByName](
321 napi_env env, NapiAsyncTask& task, int32_t status) {
322 if (window == nullptr) {
323 task.Reject(env, CreateJsError(env, static_cast<int32_t>(WmErrorCode::WM_ERROR_STATE_ABNORMALLY)));
324 TLOGE(WmsLogTag::WMS_UIEXT, "[NAPI]Get windowExtensionSessionImpl failed");
325 return;
326 }
327 LoadContentTask(contentStorage, contextUrl, window, env, task, parentToken, isLoadedByName);
328 };
329 napi_value result = nullptr;
330 NapiAsyncTask::Schedule("JsEmbeddableWindowStage::OnLoadContent",
331 env, CreateAsyncTaskWithLastParam(env, callBack, nullptr, std::move(complete), &result));
332 return result;
333 }
334
CreateJsEmbeddableWindowStage(napi_env env,sptr<Rosen::Window> window,sptr<AAFwk::SessionInfo> sessionInfo)335 napi_value JsEmbeddableWindowStage::CreateJsEmbeddableWindowStage(napi_env env, sptr<Rosen::Window> window,
336 sptr<AAFwk::SessionInfo> sessionInfo)
337 {
338 TLOGD(WmsLogTag::WMS_UIEXT, "[NAPI]CreateJsEmbeddableWindowStage");
339 napi_value objValue = nullptr;
340 napi_create_object(env, &objValue);
341
342 std::unique_ptr<JsEmbeddableWindowStage> jsEmbeddableWindowStage = std::make_unique<JsEmbeddableWindowStage>(window,
343 sessionInfo);
344 napi_wrap(env, objValue, jsEmbeddableWindowStage.release(), JsEmbeddableWindowStage::Finalizer, nullptr, nullptr);
345
346 const char *moduleName = "JsEmbeddableWindowStage";
347 BindNativeFunction(env,
348 objValue, "loadContent", moduleName, JsEmbeddableWindowStage::LoadContent);
349 BindNativeFunction(env,
350 objValue, "loadContentByName", moduleName, JsEmbeddableWindowStage::LoadContentByName);
351 BindNativeFunction(env,
352 objValue, "getMainWindow", moduleName, JsEmbeddableWindowStage::GetMainWindow);
353 BindNativeFunction(env,
354 objValue, "getMainWindowSync", moduleName, JsEmbeddableWindowStage::GetMainWindowSync);
355 BindNativeFunction(env, objValue, "on", moduleName, JsEmbeddableWindowStage::On);
356 BindNativeFunction(env, objValue, "off", moduleName, JsEmbeddableWindowStage::Off);
357 BindNativeFunction(env, objValue, "createSubWindow", moduleName, JsEmbeddableWindowStage::CreateSubWindow);
358 BindNativeFunction(env, objValue, "getSubWindow", moduleName, JsEmbeddableWindowStage::GetSubWindow);
359
360 return objValue;
361 }
362 } // namespace Rosen
363 } // namespace OHOS
364