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