1 /*
2 * Copyright (c) 2023 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_panel.h"
17
18 #include "event_checker.h"
19 #include "input_method_ability.h"
20 #include "inputmethod_trace.h"
21 #include "js_text_input_client_engine.h"
22 #include "js_util.h"
23 #include "js_utils.h"
24 #include "napi/native_common.h"
25 #include "panel_listener_impl.h"
26
27 namespace OHOS {
28 namespace MiscServices {
29 using namespace std::chrono;
30 using WMError = OHOS::Rosen::WMError;
31 const std::string JsPanel::CLASS_NAME = "Panel";
32 thread_local napi_ref JsPanel::panelConstructorRef_ = nullptr;
33 std::mutex JsPanel::panelConstructorMutex_;
34 constexpr int32_t MAX_WAIT_TIME = 10;
35 constexpr int32_t MAX_INPUT_REGION_LEN = 4;
36 const constexpr char *LANDSCAPE_REGION_PARAM_NAME = "landscapeInputRegion";
37 const constexpr char *PORTRAIT_REGION_PARAM_NAME = "portraitInputRegion";
38 FFRTBlockQueue<JsEventInfo> JsPanel::jsQueue_{ MAX_WAIT_TIME };
39
Init(napi_env env)40 napi_value JsPanel::Init(napi_env env)
41 {
42 IMSA_HILOGI("JsPanel start.");
43 napi_value constructor = nullptr;
44 std::lock_guard<std::mutex> lock(panelConstructorMutex_);
45 if (panelConstructorRef_ != nullptr) {
46 napi_status status = napi_get_reference_value(env, panelConstructorRef_, &constructor);
47 CHECK_RETURN(status == napi_ok, "failed to get jsPanel constructor.", nullptr);
48 return constructor;
49 }
50 const napi_property_descriptor properties[] = {
51 DECLARE_NAPI_FUNCTION("setUiContent", SetUiContent),
52 DECLARE_NAPI_FUNCTION("resize", Resize),
53 DECLARE_NAPI_FUNCTION("moveTo", MoveTo),
54 DECLARE_NAPI_FUNCTION("show", Show),
55 DECLARE_NAPI_FUNCTION("hide", Hide),
56 DECLARE_NAPI_FUNCTION("changeFlag", ChangeFlag),
57 DECLARE_NAPI_FUNCTION("setPrivacyMode", SetPrivacyMode),
58 DECLARE_NAPI_FUNCTION("on", Subscribe),
59 DECLARE_NAPI_FUNCTION("off", UnSubscribe),
60 DECLARE_NAPI_FUNCTION("adjustPanelRect", AdjustPanelRect),
61 DECLARE_NAPI_FUNCTION("updateRegion", UpdateRegion),
62 DECLARE_NAPI_FUNCTION("startMoving", StartMoving),
63 DECLARE_NAPI_FUNCTION("getDisplayId", GetDisplayId),
64 DECLARE_NAPI_FUNCTION("setImmersiveMode", SetImmersiveMode),
65 DECLARE_NAPI_FUNCTION("getImmersiveMode", GetImmersiveMode),
66 DECLARE_NAPI_FUNCTION("setImmersiveEffect", SetImmersiveEffect),
67 DECLARE_NAPI_FUNCTION("setKeepScreenOn", SetKeepScreenOn),
68 };
69 NAPI_CALL(env, napi_define_class(env, CLASS_NAME.c_str(), CLASS_NAME.size(), JsNew, nullptr,
70 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor));
71 CHECK_RETURN(constructor != nullptr, "failed to define class!", nullptr);
72 NAPI_CALL(env, napi_create_reference(env, constructor, 1, &panelConstructorRef_));
73 return constructor;
74 }
75
JsNew(napi_env env,napi_callback_info info)76 napi_value JsPanel::JsNew(napi_env env, napi_callback_info info)
77 {
78 IMSA_HILOGD("create panel instance start.");
79 std::shared_ptr<PanelListenerImpl> panelImpl = PanelListenerImpl::GetInstance();
80 if (panelImpl != nullptr) {
81 IMSA_HILOGD("set eventHandler.");
82 panelImpl->SetEventHandler(AppExecFwk::EventHandler::Current());
83 }
84 JsPanel *panel = new (std::nothrow) JsPanel();
85 CHECK_RETURN(panel != nullptr, "no memory for JsPanel!", nullptr);
86 auto finalize = [](napi_env env, void *data, void *hint) {
87 IMSA_HILOGD("jsPanel finalize.");
88 auto *jsPanel = reinterpret_cast<JsPanel *>(data);
89 CHECK_RETURN_VOID(jsPanel != nullptr, "finalize nullptr!");
90 jsPanel->GetNative() = nullptr;
91 delete jsPanel;
92 };
93 napi_value thisVar = nullptr;
94 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
95 if (status != napi_ok) {
96 IMSA_HILOGE("failed to get cb info: %{public}d!", status);
97 delete panel;
98 return nullptr;
99 }
100 status = napi_wrap(env, thisVar, panel, finalize, nullptr, nullptr);
101 if (status != napi_ok) {
102 IMSA_HILOGE("failed to wrap: %{public}d!", status);
103 delete panel;
104 return nullptr;
105 }
106 return thisVar;
107 }
108
~JsPanel()109 JsPanel::~JsPanel()
110 {
111 inputMethodPanel_ = nullptr;
112 }
113
SetNative(const std::shared_ptr<InputMethodPanel> & panel)114 void JsPanel::SetNative(const std::shared_ptr<InputMethodPanel> &panel)
115 {
116 inputMethodPanel_ = panel;
117 }
118
GetNative()119 std::shared_ptr<InputMethodPanel> JsPanel::GetNative()
120 {
121 return inputMethodPanel_;
122 }
123
SetUiContent(napi_env env,napi_callback_info info)124 napi_value JsPanel::SetUiContent(napi_env env, napi_callback_info info)
125 {
126 IMSA_HILOGI("JsPanel start.");
127 auto ctxt = std::make_shared<PanelContentContext>(env, info);
128 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
129 napi_status status = napi_generic_failure;
130 PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, status);
131 // 0 means the first param path<std::string>
132 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], ctxt->path) == napi_ok,
133 "js param path covert failed, must be string!", TYPE_NONE, status);
134 // if type of argv[1] is object, we will get value of 'storage' from it.
135 if (argc >= 2) {
136 napi_valuetype valueType = napi_undefined;
137 status = napi_typeof(env, argv[1], &valueType);
138 CHECK_RETURN(status == napi_ok, "get valueType failed!", status);
139 if (valueType == napi_object) {
140 napi_ref storage = nullptr;
141 napi_create_reference(env, argv[1], 1, &storage);
142 auto contentStorage = (storage == nullptr) ? nullptr
143 : std::shared_ptr<NativeReference>(
144 reinterpret_cast<NativeReference *>(storage));
145 ctxt->contentStorage = contentStorage;
146 }
147 }
148 ctxt->info = { std::chrono::system_clock::now(), JsEvent::SET_UI_CONTENT };
149 jsQueue_.Push(ctxt->info);
150 return napi_ok;
151 };
152
153 auto exec = [ctxt](AsyncCall::Context *ctx) { ctxt->SetState(napi_ok); };
154 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
155 jsQueue_.Wait(ctxt->info);
156 if (ctxt->inputMethodPanel == nullptr) {
157 IMSA_HILOGE("inputMethodPanel is nullptr!");
158 jsQueue_.Pop();
159 return napi_generic_failure;
160 }
161 auto code = ctxt->inputMethodPanel->SetUiContent(ctxt->path, env, ctxt->contentStorage);
162 jsQueue_.Pop();
163 if (code == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) {
164 ctxt->SetErrorCode(code);
165 ctxt->SetErrorMessage("path should be a path to specific page.");
166 return napi_generic_failure;
167 }
168 return napi_ok;
169 };
170 ctxt->SetAction(std::move(input), std::move(output));
171 // 3 means JsAPI:setUiContent has 3 params at most.
172 AsyncCall asyncCall(env, info, ctxt, 3);
173 return asyncCall.Call(env, exec, "setUiContent");
174 }
175
Resize(napi_env env,napi_callback_info info)176 napi_value JsPanel::Resize(napi_env env, napi_callback_info info)
177 {
178 auto ctxt = std::make_shared<PanelContentContext>(env, info);
179 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
180 napi_status status = napi_generic_failure;
181 PARAM_CHECK_RETURN(env, argc > 1, "at least two parameters is required", TYPE_NONE, status);
182 // 0 means the first param width<uint32_t>
183 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], ctxt->width) == napi_ok,
184 "width type must be number!", TYPE_NONE, status);
185 // 1 means the second param height<uint32_t>
186 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[1], ctxt->height) == napi_ok,
187 "height type must be number!", TYPE_NONE, status);
188 ctxt->info = { std::chrono::system_clock::now(), JsEvent::RESIZE };
189 jsQueue_.Push(ctxt->info);
190 return napi_ok;
191 };
192
193 auto exec = [ctxt](AsyncCall::Context *ctx) {
194 jsQueue_.Wait(ctxt->info);
195 if (ctxt->inputMethodPanel == nullptr) {
196 IMSA_HILOGE("inputMethodPanel_ is nullptr!");
197 jsQueue_.Pop();
198 return;
199 }
200 auto code = ctxt->inputMethodPanel->Resize(ctxt->width, ctxt->height);
201 jsQueue_.Pop();
202 if (code == ErrorCode::NO_ERROR) {
203 ctxt->SetState(napi_ok);
204 return;
205 }
206 ctxt->SetErrorCode(code);
207 };
208 ctxt->SetAction(std::move(input));
209 // 3 means JsAPI:resize has 3 params at most.
210 AsyncCall asyncCall(env, info, ctxt, 3);
211 return asyncCall.Call(env, exec, "resize");
212 }
213
MoveTo(napi_env env,napi_callback_info info)214 napi_value JsPanel::MoveTo(napi_env env, napi_callback_info info)
215 {
216 auto ctxt = std::make_shared<PanelContentContext>(env, info);
217 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
218 napi_status status = napi_generic_failure;
219 PARAM_CHECK_RETURN(env, argc > 1, "at least two parameters is required ", TYPE_NONE, status);
220 // 0 means the first param x<int32_t>
221 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], ctxt->x) == napi_ok, "x type must be number",
222 TYPE_NONE, status);
223 // 1 means the second param y<int32_t>
224 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[1], ctxt->y) == napi_ok, "y type must be number",
225 TYPE_NONE, status);
226 ctxt->info = { std::chrono::system_clock::now(), JsEvent::MOVE_TO };
227 jsQueue_.Push(ctxt->info);
228 return napi_ok;
229 };
230
231 auto exec = [ctxt](AsyncCall::Context *ctx) {
232 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
233 jsQueue_.Wait(ctxt->info);
234 PrintEditorQueueInfoIfTimeout(start, ctxt->info);
235 if (ctxt->inputMethodPanel == nullptr) {
236 IMSA_HILOGE("inputMethodPanel_ is nullptr!");
237 jsQueue_.Pop();
238 return;
239 }
240 auto code = ctxt->inputMethodPanel->MoveTo(ctxt->x, ctxt->y);
241 jsQueue_.Pop();
242 if (code == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) {
243 ctxt->SetErrorCode(code);
244 return;
245 }
246 ctxt->SetState(napi_ok);
247 };
248 ctxt->SetAction(std::move(input));
249 // 3 means JsAPI:moveTo has 3 params at most.
250 AsyncCall asyncCall(env, info, ctxt, 3);
251 return asyncCall.Call(env, exec, "moveTo");
252 }
253
StartMoving(napi_env env,napi_callback_info info)254 napi_value JsPanel::StartMoving(napi_env env, napi_callback_info info)
255 {
256 napi_value self = nullptr;
257 NAPI_CALL(env, napi_get_cb_info(env, info, 0, nullptr, &self, nullptr));
258 RESULT_CHECK_RETURN(env, (self != nullptr), JsUtils::Convert(ErrorCode::ERROR_IME),
259 "", TYPE_NONE, JsUtil::Const::Null(env));
260 void *native = nullptr;
261 NAPI_CALL(env, napi_unwrap(env, self, &native));
262 RESULT_CHECK_RETURN(env, (native != nullptr), JsUtils::Convert(ErrorCode::ERROR_IME),
263 "", TYPE_NONE, JsUtil::Const::Null(env));
264 auto inputMethodPanel = reinterpret_cast<JsPanel *>(native)->GetNative();
265 if (inputMethodPanel == nullptr) {
266 IMSA_HILOGE("inputMethodPanel is nullptr!");
267 JsUtils::ThrowException(env, JsUtils::Convert(ErrorCode::ERROR_IME),
268 "failed to start moving, inputMethodPanel is nullptr", TYPE_NONE);
269 return JsUtil::Const::Null(env);
270 }
271
272 auto ret = inputMethodPanel->StartMoving();
273 if (ret != ErrorCode::NO_ERROR) {
274 JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to start moving", TYPE_NONE);
275 }
276 return JsUtil::Const::Null(env);
277 }
278
GetDisplayId(napi_env env,napi_callback_info info)279 napi_value JsPanel::GetDisplayId(napi_env env, napi_callback_info info)
280 {
281 auto ctxt = std::make_shared<PanelContentContext>(env, info);
282 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
283 ctxt->info = { std::chrono::system_clock::now(), JsEvent::GET_DISPLAYID };
284 jsQueue_.Push(ctxt->info);
285 return napi_ok;
286 };
287 auto exec = [ctxt](AsyncCall::Context *ctx) {
288 jsQueue_.Wait(ctxt->info);
289 if (ctxt->inputMethodPanel == nullptr) {
290 IMSA_HILOGE("inputMethodPanel_ is nullptr!");
291 ctxt->SetErrorCode(ErrorCode::ERROR_IME);
292 jsQueue_.Pop();
293 return;
294 }
295 auto ret = ctxt->inputMethodPanel->GetDisplayId(ctxt->displayId);
296 jsQueue_.Pop();
297 if (ret != ErrorCode::NO_ERROR) {
298 IMSA_HILOGE("failed get displayId!");
299 ctxt->SetErrorCode(ret);
300 return;
301 }
302
303 if (ctxt->displayId > UINT32_MAX) {
304 IMSA_HILOGE("displayId is too large, displayId: %{public}" PRIu64 "", ctxt->displayId);
305 ctxt->SetErrorCode(ErrorCode::ERROR_WINDOW_MANAGER);
306 return;
307 }
308 ctxt->SetState(napi_ok);
309 };
310 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
311 uint32_t displayId = static_cast<uint32_t>(ctxt->displayId);
312 return napi_create_uint32(env, displayId, result);
313 };
314 ctxt->SetAction(std::move(input), std::move(output));
315 // 1 means JsAPI:GetDisplayId has 1 params at most.
316 AsyncCall asyncCall(env, info, ctxt, 1);
317 return asyncCall.Call(env, exec, "getDisplayId");
318 }
319
PrintEditorQueueInfoIfTimeout(int64_t start,const JsEventInfo & currentInfo)320 void JsPanel::PrintEditorQueueInfoIfTimeout(int64_t start, const JsEventInfo ¤tInfo)
321 {
322 int64_t end = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
323 if (end - start >= MAX_WAIT_TIME) {
324 JsEventInfo frontInfo;
325 auto ret = jsQueue_.GetFront(frontInfo);
326 int64_t frontTime = duration_cast<microseconds>(frontInfo.timestamp.time_since_epoch()).count();
327 int64_t currentTime = duration_cast<microseconds>(currentInfo.timestamp.time_since_epoch()).count();
328 IMSA_HILOGI("ret:%{public}d,front[%{public}" PRId64 ",%{public}d],current[%{public}" PRId64 ",%{public}d]", ret,
329 frontTime, static_cast<int32_t>(frontInfo.event), currentTime, static_cast<int32_t>(currentInfo.event));
330 }
331 }
332
Show(napi_env env,napi_callback_info info)333 napi_value JsPanel::Show(napi_env env, napi_callback_info info)
334 {
335 InputMethodSyncTrace tracer("JsPanel_Show");
336 auto ctxt = std::make_shared<PanelContentContext>(env, info);
337 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
338 ctxt->info = { std::chrono::system_clock::now(), JsEvent::SHOW };
339 jsQueue_.Push(ctxt->info);
340 return napi_ok;
341 };
342 auto exec = [ctxt](AsyncCall::Context *ctx) {
343 jsQueue_.Wait(ctxt->info);
344 if (ctxt->inputMethodPanel == nullptr) {
345 IMSA_HILOGE("inputMethodPanel is nullptr!");
346 jsQueue_.Pop();
347 return;
348 }
349 auto code = InputMethodAbility::GetInstance().ShowPanel(ctxt->inputMethodPanel);
350 if (code == ErrorCode::NO_ERROR) {
351 ctxt->SetState(napi_ok);
352 jsQueue_.Pop();
353 return;
354 }
355 jsQueue_.Pop();
356 ctxt->SetErrorCode(code);
357 };
358 ctxt->SetAction(std::move(input));
359 // 1 means JsAPI:show has 1 param at most.
360 AsyncCall asyncCall(env, info, ctxt, 1);
361 return asyncCall.Call(env, exec, "show");
362 }
363
Hide(napi_env env,napi_callback_info info)364 napi_value JsPanel::Hide(napi_env env, napi_callback_info info)
365 {
366 InputMethodSyncTrace tracer("JsPanel_Hide");
367 auto ctxt = std::make_shared<PanelContentContext>(env, info);
368
369 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
370 ctxt->info = { std::chrono::system_clock::now(), JsEvent::HIDE };
371 jsQueue_.Push(ctxt->info);
372 return napi_ok;
373 };
374 auto exec = [ctxt](AsyncCall::Context *ctx) {
375 jsQueue_.Wait(ctxt->info);
376 if (ctxt->inputMethodPanel == nullptr) {
377 IMSA_HILOGE("inputMethodPanel is nullptr!");
378 jsQueue_.Pop();
379 return;
380 }
381 auto code = InputMethodAbility::GetInstance().HidePanel(ctxt->inputMethodPanel);
382 jsQueue_.Pop();
383 if (code == ErrorCode::NO_ERROR) {
384 ctxt->SetState(napi_ok);
385 return;
386 }
387 ctxt->SetErrorCode(code);
388 };
389 ctxt->SetAction(std::move(input));
390 // 1 means JsAPI:hide has 1 param at most.
391 AsyncCall asyncCall(env, info, ctxt, 1);
392 return asyncCall.Call(env, exec, "panel.hide");
393 }
394
ChangeFlag(napi_env env,napi_callback_info info)395 napi_value JsPanel::ChangeFlag(napi_env env, napi_callback_info info)
396 {
397 size_t argc = ARGC_MAX;
398 napi_value argv[ARGC_MAX] = { nullptr };
399 napi_value thisVar = nullptr;
400 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
401 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, nullptr);
402 int32_t panelFlag = 0;
403 // 0 means the first param flag<PanelFlag>
404 napi_status status = JsUtils::GetValue(env, argv[0], panelFlag);
405 PARAM_CHECK_RETURN(env, status == napi_ok, "flag type must be PanelFlag!", TYPE_NONE, nullptr);
406 auto inputMethodPanel = UnwrapPanel(env, thisVar);
407 if (inputMethodPanel == nullptr) {
408 IMSA_HILOGE("inputMethodPanel is nullptr!");
409 return nullptr;
410 }
411 PARAM_CHECK_RETURN(env,
412 (panelFlag == PanelFlag::FLG_FIXED || panelFlag == PanelFlag::FLG_FLOATING ||
413 panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN),
414 "flag type must be one of PanelFlag!", TYPE_NONE, nullptr);
415 auto ret = inputMethodPanel->ChangePanelFlag(PanelFlag(panelFlag));
416 CHECK_RETURN(ret == ErrorCode::NO_ERROR, "failed to ChangePanelFlag!", nullptr);
417 return nullptr;
418 }
419
SetPrivacyMode(napi_env env,napi_callback_info info)420 napi_value JsPanel::SetPrivacyMode(napi_env env, napi_callback_info info)
421 {
422 size_t argc = ARGC_MAX;
423 napi_value argv[ARGC_MAX] = { nullptr };
424 napi_value thisVar = nullptr;
425 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
426 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, nullptr);
427 bool isPrivacyMode = false;
428 // 0 means the first param isPrivacyMode<boolean>
429 napi_status status = JsUtils::GetValue(env, argv[0], isPrivacyMode);
430 PARAM_CHECK_RETURN(env, status == napi_ok, "isPrivacyMode type must be boolean!", TYPE_NONE, nullptr);
431 CHECK_RETURN(status == napi_ok, "failed to get isPrivacyMode!", nullptr);
432 auto inputMethodPanel = UnwrapPanel(env, thisVar);
433 if (inputMethodPanel == nullptr) {
434 IMSA_HILOGE("inputMethodPanel is nullptr!");
435 return nullptr;
436 }
437 auto ret = inputMethodPanel->SetPrivacyMode(isPrivacyMode);
438 if (ret == static_cast<int32_t>(WMError::WM_ERROR_INVALID_PERMISSION)) {
439 JsUtils::ThrowException(env, JsUtils::Convert(ErrorCode::ERROR_STATUS_PERMISSION_DENIED),
440 " ohos.permission.PRIVACY_WINDOW permission denied", TYPE_NONE);
441 }
442 CHECK_RETURN(ret == ErrorCode::NO_ERROR, "failed to SetPrivacyMode!", nullptr);
443 return nullptr;
444 }
445
Subscribe(napi_env env,napi_callback_info info)446 napi_value JsPanel::Subscribe(napi_env env, napi_callback_info info)
447 {
448 IMSA_HILOGD("JsPanel start.");
449 size_t argc = ARGC_MAX;
450 napi_value argv[ARGC_MAX] = { nullptr };
451 napi_value thisVar = nullptr;
452 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
453 std::string type;
454 // 2 means least param num.
455 if (argc < 2 || !JsUtil::GetValue(env, argv[0], type) ||
456 !EventChecker::IsValidEventType(EventSubscribeModule::PANEL, type) ||
457 JsUtil::GetType(env, argv[1]) != napi_function) {
458 IMSA_HILOGE("subscribe failed, type: %{public}s!", type.c_str());
459 return nullptr;
460 }
461 IMSA_HILOGD("subscribe type: %{public}s.", type.c_str());
462 std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance();
463 auto inputMethodPanel = UnwrapPanel(env, thisVar);
464 if (inputMethodPanel == nullptr) {
465 IMSA_HILOGE("inputMethodPanel is nullptr!");
466 return nullptr;
467 }
468 // 1 means the second param callback.
469 std::shared_ptr<JSCallbackObject> cbObject =
470 std::make_shared<JSCallbackObject>(env, argv[1], std::this_thread::get_id(),
471 AppExecFwk::EventHandler::Current());
472 observer->Subscribe(inputMethodPanel->windowId_, type, cbObject);
473 bool ret = inputMethodPanel->SetPanelStatusListener(observer, type);
474 if (!ret) {
475 IMSA_HILOGE("failed to subscribe %{public}s!", type.c_str());
476 observer->RemoveInfo(type, inputMethodPanel->windowId_);
477 }
478 napi_value result = nullptr;
479 napi_get_undefined(env, &result);
480 return result;
481 }
482
UnSubscribe(napi_env env,napi_callback_info info)483 napi_value JsPanel::UnSubscribe(napi_env env, napi_callback_info info)
484 {
485 size_t argc = ARGC_MAX;
486 napi_value argv[ARGC_MAX] = { nullptr };
487 napi_value thisVar = nullptr;
488 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
489 std::string type;
490 // 1 means least param num.
491 PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, nullptr);
492 PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], type), "type must be string!", TYPE_NONE, nullptr);
493 PARAM_CHECK_RETURN(env, EventChecker::IsValidEventType(EventSubscribeModule::PANEL, type),
494 "type should be show/hide/sizeChange!", TYPE_NONE, nullptr);
495 // if the second param is not napi_function/napi_null/napi_undefined, return
496 auto paramType = JsUtil::GetType(env, argv[1]);
497 PARAM_CHECK_RETURN(env, (paramType == napi_function || paramType == napi_null || paramType == napi_undefined),
498 "callback should be function or null or undefined!", TYPE_NONE, nullptr);
499 // if the second param is napi_function, delete it, else delete all.
500 argv[1] = paramType == napi_function ? argv[1] : nullptr;
501
502 IMSA_HILOGD("unsubscribe type: %{public}s.", type.c_str());
503 std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance();
504 auto inputMethodPanel = UnwrapPanel(env, thisVar);
505 if (inputMethodPanel == nullptr) {
506 IMSA_HILOGE("inputMethodPanel is nullptr!");
507 return nullptr;
508 }
509 observer->RemoveInfo(type, inputMethodPanel->windowId_);
510 inputMethodPanel->ClearPanelListener(type);
511 napi_value result = nullptr;
512 napi_get_null(env, &result);
513 return result;
514 }
515
IsEnhancedAdjust(napi_env env,napi_value * argv)516 bool JsPanel::IsEnhancedAdjust(napi_env env, napi_value *argv)
517 {
518 PARAM_CHECK_RETURN(
519 env, JsUtil::GetType(env, argv[1]) == napi_object, "param rect type must be PanelRect", TYPE_NONE, false);
520 std::vector<const char *> properties = { "landscapeAvoidY", "portraitAvoidY", LANDSCAPE_REGION_PARAM_NAME,
521 PORTRAIT_REGION_PARAM_NAME, "fullScreenMode" };
522 return std::any_of(properties.begin(), properties.end(), [env, argv](const char *prop) {
523 bool hasProperty = false;
524 napi_has_named_property(env, argv[1], prop, &hasProperty);
525 return hasProperty;
526 });
527 }
528
CheckParam(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<PanelContentContext> ctxt)529 napi_status JsPanel::CheckParam(napi_env env, size_t argc, napi_value *argv, std::shared_ptr<PanelContentContext> ctxt)
530 {
531 ctxt->isEnhancedCall = false;
532 CHECK_RETURN(ParsePanelFlag(env, argv, ctxt->panelFlag, false) == napi_ok, "parse flag", napi_generic_failure);
533 // 1 means the second param rect
534 PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[1]) == napi_object, "param rect type must be PanelRect",
535 TYPE_NONE, napi_generic_failure);
536 PARAM_CHECK_RETURN(env, JsPanelRect::Read(env, argv[1], ctxt->layoutParams), "js param rect covert failed",
537 TYPE_NONE, napi_generic_failure);
538 return napi_ok;
539 }
540
CheckEnhancedParam(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<PanelContentContext> ctxt)541 napi_status JsPanel::CheckEnhancedParam(
542 napi_env env, size_t argc, napi_value *argv, std::shared_ptr<PanelContentContext> ctxt)
543 {
544 ctxt->isEnhancedCall = true;
545 CHECK_RETURN(ParsePanelFlag(env, argv, ctxt->panelFlag, true) == napi_ok, "parse flag", napi_generic_failure);
546 // 1 means the second param rect
547 PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[1]) == napi_object, "param rect type must be PanelRect",
548 TYPE_NONE, napi_generic_failure);
549 CHECK_RETURN(
550 JsEnhancedPanelRect::Read(env, argv[1], ctxt->enhancedLayoutParams), "read param", napi_generic_failure);
551 if (JsUtil::HasProperty(env, argv[1], LANDSCAPE_REGION_PARAM_NAME)) {
552 napi_value jsObject = nullptr;
553 napi_get_named_property(env, argv[1], LANDSCAPE_REGION_PARAM_NAME, &jsObject);
554 CHECK_RETURN(JsHotArea::Read(env, jsObject, ctxt->hotAreas.landscape.keyboardHotArea), "read landscape region",
555 napi_generic_failure);
556 } else {
557 ctxt->hotAreas.landscape.keyboardHotArea.clear();
558 }
559 if (JsUtil::HasProperty(env, argv[1], PORTRAIT_REGION_PARAM_NAME)) {
560 napi_value jsObject = nullptr;
561 napi_get_named_property(env, argv[1], PORTRAIT_REGION_PARAM_NAME, &jsObject);
562 CHECK_RETURN(JsHotArea::Read(env, jsObject, ctxt->hotAreas.portrait.keyboardHotArea), "read portrait region",
563 napi_generic_failure);
564 } else {
565 ctxt->hotAreas.portrait.keyboardHotArea.clear();
566 }
567 int32_t ret = ctxt->inputMethodPanel->IsEnhancedParamValid(ctxt->panelFlag, ctxt->enhancedLayoutParams);
568 if (ret == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) {
569 RESULT_CHECK_RETURN(env, false, JsUtils::Convert(ret),
570 "width limit:[0, displayWidth], avoidHeight limit:[0, 70 percent of displayHeight]", TYPE_NONE,
571 napi_generic_failure);
572 } else if (ret == ErrorCode::ERROR_INVALID_PANEL_TYPE) {
573 RESULT_CHECK_RETURN(
574 env, false, JsUtils::Convert(ret), "only used for SOFT_KEYBOARD panel", TYPE_NONE, napi_generic_failure);
575 } else if (ret != ErrorCode::NO_ERROR) {
576 RESULT_CHECK_RETURN(env, false, JsUtils::Convert(ret), "adjust failed", TYPE_NONE, napi_generic_failure);
577 }
578 return napi_ok;
579 }
580
IsPanelFlagValid(napi_env env,PanelFlag panelFlag,bool isEnhancedCalled)581 bool JsPanel::IsPanelFlagValid(napi_env env, PanelFlag panelFlag, bool isEnhancedCalled)
582 {
583 bool isValid = false;
584 if (InputMethodAbility::GetInstance().IsDefaultIme()) {
585 isValid = panelFlag == FLG_FIXED || panelFlag == FLG_FLOATING || panelFlag == FLG_CANDIDATE_COLUMN;
586 } else {
587 isValid = panelFlag == FLG_FIXED || panelFlag == FLG_FLOATING;
588 }
589 IMSA_HILOGI("flag: %{public}d, isEnhanced: %{public}d, isValid: %{public}d", panelFlag, isEnhancedCalled, isValid);
590 if (!isEnhancedCalled) {
591 PARAM_CHECK_RETURN(env, isValid, "param flag type should be FLG_FIXED or FLG_FLOATING", TYPE_NONE, false);
592 } else {
593 RESULT_CHECK_RETURN(env, isValid, JsUtils::Convert(ErrorCode::ERROR_INVALID_PANEL_FLAG),
594 "param flag should be FIXED or FLOATING", TYPE_NONE, false);
595 }
596 return true;
597 }
598
ParsePanelFlag(napi_env env,napi_value * argv,PanelFlag & panelFlag,bool isEnhancedCalled)599 napi_status JsPanel::ParsePanelFlag(napi_env env, napi_value *argv, PanelFlag &panelFlag, bool isEnhancedCalled)
600 {
601 int32_t flag = 0;
602 // 0 means the first param flag
603 PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "flag", TYPE_NUMBER, napi_generic_failure);
604 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], flag) == napi_ok, "js param flag covert failed", TYPE_NONE,
605 napi_generic_failure);
606 panelFlag = PanelFlag(flag);
607 CHECK_RETURN(IsPanelFlagValid(env, panelFlag, isEnhancedCalled), "invalid panelFlag", napi_generic_failure);
608 return napi_ok;
609 }
610
AdjustLayoutParam(std::shared_ptr<PanelContentContext> ctxt)611 void JsPanel::AdjustLayoutParam(std::shared_ptr<PanelContentContext> ctxt)
612 {
613 int32_t ret = ctxt->inputMethodPanel->AdjustPanelRect(ctxt->panelFlag, ctxt->layoutParams);
614 if (ret == ErrorCode::NO_ERROR) {
615 ctxt->SetState(napi_ok);
616 return;
617 } else if (ret == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) {
618 ctxt->SetErrorMessage("width limit:[0, displayWidth], height limit:[0, 70 percent of displayHeight]!");
619 }
620 ctxt->SetErrorCode(ret);
621 }
622
AdjustEnhancedLayoutParam(std::shared_ptr<PanelContentContext> ctxt)623 void JsPanel::AdjustEnhancedLayoutParam(std::shared_ptr<PanelContentContext> ctxt)
624 {
625 int32_t ret = ctxt->inputMethodPanel->AdjustPanelRect(ctxt->panelFlag, ctxt->enhancedLayoutParams, ctxt->hotAreas);
626 if (ret == ErrorCode::NO_ERROR) {
627 ctxt->SetState(napi_ok);
628 return;
629 } else if (ret == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) {
630 ctxt->SetErrorMessage("width limit:[0, displayWidth], avoidHeight limit:[0, 70 percent of displayHeight]");
631 } else if (ret == ErrorCode::ERROR_INVALID_PANEL_TYPE) {
632 ctxt->SetErrorMessage("only used for SOFT_KEYBOARD panel");
633 }
634 ctxt->SetErrorCode(ret);
635 }
636
AdjustPanelRect(napi_env env,napi_callback_info info)637 napi_value JsPanel::AdjustPanelRect(napi_env env, napi_callback_info info)
638 {
639 auto ctxt = std::make_shared<PanelContentContext>(env, info);
640 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
641 PARAM_CHECK_RETURN(env, argc > 1, "at least two parameters is required", TYPE_NONE, napi_generic_failure);
642 napi_status status = napi_generic_failure;
643 if (!IsEnhancedAdjust(env, argv)) {
644 CHECK_RETURN(CheckParam(env, argc, argv, ctxt) == napi_ok, "check param", napi_generic_failure);
645 } else {
646 CHECK_RETURN(CheckEnhancedParam(env, argc, argv, ctxt) == napi_ok, "check param", napi_generic_failure);
647 }
648 ctxt->info = { std::chrono::system_clock::now(), JsEvent::ADJUST_PANEL_RECT };
649 jsQueue_.Push(ctxt->info);
650 return napi_ok;
651 };
652
653 auto exec = [ctxt](AsyncCall::Context *ctx) {
654 jsQueue_.Wait(ctxt->info);
655 if (ctxt->inputMethodPanel == nullptr) {
656 IMSA_HILOGE("inputMethodPanel_ is nullptr!");
657 jsQueue_.Pop();
658 return;
659 }
660 if (!ctxt->isEnhancedCall) {
661 AdjustLayoutParam(ctxt);
662 } else {
663 AdjustEnhancedLayoutParam(ctxt);
664 }
665 jsQueue_.Pop();
666 };
667 ctxt->SetAction(std::move(input));
668 // 2 means JsAPI:adjustPanelRect has 2 params at most
669 AsyncCall asyncCall(env, info, ctxt, 2);
670 return asyncCall.Call(env, exec, "adjustPanelRect");
671 }
672
UpdateRegion(napi_env env,napi_callback_info info)673 napi_value JsPanel::UpdateRegion(napi_env env, napi_callback_info info)
674 {
675 auto ctxt = std::make_shared<PanelContentContext>(env, info);
676 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
677 PARAM_CHECK_RETURN(env, ctxt->inputMethodPanel != nullptr, "panel is null", TYPE_NONE, napi_generic_failure);
678 RESULT_CHECK_RETURN(env, ctxt->inputMethodPanel->GetPanelType() == PanelType::SOFT_KEYBOARD,
679 JsUtils::Convert(ErrorCode::ERROR_INVALID_PANEL_TYPE), "only used for SOFT_KEYBOARD panel", TYPE_NONE,
680 napi_generic_failure);
681 CHECK_RETURN(IsPanelFlagValid(env, ctxt->inputMethodPanel->GetPanelFlag(), true), "invalid panelFlag",
682 napi_generic_failure);
683 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameters is required", TYPE_NONE, napi_generic_failure);
684 PARAM_CHECK_RETURN(env, JsHotArea::Read(env, argv[0], ctxt->hotArea), "failed to convert inputRegion",
685 TYPE_NONE, napi_generic_failure);
686 ctxt->info = { std::chrono::system_clock::now(), JsEvent::UPDATE_REGION };
687 jsQueue_.Push(ctxt->info);
688 return napi_ok;
689 };
690 auto exec = [ctxt](AsyncCall::Context *ctx) {
691 jsQueue_.Wait(ctxt->info);
692 if (ctxt->inputMethodPanel == nullptr) {
693 IMSA_HILOGE("inputMethodPanel_ is nullptr!");
694 jsQueue_.Pop();
695 return;
696 }
697 int32_t code = ctxt->inputMethodPanel->UpdateRegion(ctxt->hotArea);
698 if (code == ErrorCode::NO_ERROR) {
699 ctxt->SetState(napi_ok);
700 return;
701 } else if (code == ErrorCode::ERROR_INVALID_PANEL_TYPE) {
702 ctxt->SetErrorMessage("only used for SOFT_KEYBOARD panel");
703 } else if (code == ErrorCode::ERROR_INVALID_PANEL_FLAG) {
704 ctxt->SetErrorMessage("only used for fixed or floating panel");
705 }
706 ctxt->SetErrorCode(code);
707 jsQueue_.Pop();
708 };
709 ctxt->SetAction(std::move(input));
710 // 1 means JsAPI:updateRegion has 1 params at most
711 AsyncCall asyncCall(env, info, ctxt, 1);
712 return asyncCall.Call(env, exec, "updateRegion");
713 }
714
UnwrapPanel(napi_env env,napi_value thisVar)715 std::shared_ptr<InputMethodPanel> JsPanel::UnwrapPanel(napi_env env, napi_value thisVar)
716 {
717 void *native = nullptr;
718 napi_status status = napi_unwrap(env, thisVar, &native);
719 CHECK_RETURN((status == napi_ok && native != nullptr), "failed to unwrap!", nullptr);
720 auto jsPanel = reinterpret_cast<JsPanel *>(native);
721 if (jsPanel == nullptr) {
722 return nullptr;
723 }
724 auto inputMethodPanel = jsPanel->GetNative();
725 CHECK_RETURN(inputMethodPanel != nullptr, "inputMethodPanel is nullptr", nullptr);
726 return inputMethodPanel;
727 }
728
Write(napi_env env,const LayoutParams & layoutParams)729 napi_value JsPanelRect::Write(napi_env env, const LayoutParams &layoutParams)
730 {
731 napi_value jsObject = nullptr;
732 napi_create_object(env, &jsObject);
733 bool ret =
734 JsUtil::Object::WriteProperty(env, jsObject, "landscapeRect", JsRect::Write(env, layoutParams.landscapeRect));
735 ret = ret &&
736 JsUtil::Object::WriteProperty(env, jsObject, "portraitRect", JsRect::Write(env, layoutParams.portraitRect));
737 return ret ? jsObject : JsUtil::Const::Null(env);
738 }
Read(napi_env env,napi_value object,LayoutParams & layoutParams)739 bool JsPanelRect::Read(napi_env env, napi_value object, LayoutParams &layoutParams)
740 {
741 napi_value rectObject = nullptr;
742 napi_get_named_property(env, object, "landscapeRect", &rectObject);
743 bool ret = JsRect::Read(env, rectObject, layoutParams.landscapeRect);
744 napi_get_named_property(env, object, "portraitRect", &rectObject);
745 ret = ret && JsRect::Read(env, rectObject, layoutParams.portraitRect);
746 return ret;
747 }
748
Read(napi_env env,napi_value object,ImmersiveEffect & effect)749 bool JsImmersiveEffect::Read(napi_env env, napi_value object, ImmersiveEffect &effect)
750 {
751 int32_t gradientHeight = 0;
752 auto ret = JsUtil::Object::ReadProperty(env, object, "gradientHeight", gradientHeight);
753 if (!ret || gradientHeight < 0) {
754 IMSA_HILOGE("ret is false or gradientHeight is invalid, gradientHeight:%{public}d", gradientHeight);
755 return false;
756 }
757
758 effect.gradientHeight = static_cast<uint32_t>(gradientHeight);
759 int32_t gradientMode = 0;
760 ret = ret && JsUtil::Object::ReadProperty(env, object, "gradientMode", gradientMode);
761 if (gradientMode < static_cast<int32_t>(GradientMode::NONE) ||
762 gradientMode >= static_cast<int32_t>(GradientMode::END)) {
763 IMSA_HILOGW("gradientMode is invalid");
764 effect.gradientMode = GradientMode::NONE;
765 } else {
766 effect.gradientMode = static_cast<GradientMode>(gradientMode);
767 }
768 // optional property
769 int32_t fluidLightMode = 0;
770 JsUtil::Object::ReadProperty(env, object, "fluidLightMode", fluidLightMode);
771 if (fluidLightMode < static_cast<int32_t>(FluidLightMode::NONE) ||
772 fluidLightMode >= static_cast<int32_t>(FluidLightMode::END)) {
773 IMSA_HILOGW("fluidLightMode is invalid");
774 effect.fluidLightMode = FluidLightMode::NONE;
775 } else {
776 effect.fluidLightMode = static_cast<FluidLightMode>(fluidLightMode);
777 }
778 return ret;
779 }
780
Read(napi_env env,napi_value object,EnhancedLayoutParams & layoutParams)781 bool JsEnhancedPanelRect::Read(napi_env env, napi_value object, EnhancedLayoutParams &layoutParams)
782 {
783 napi_status status = napi_generic_failure;
784 napi_value jsObject = nullptr;
785 bool ret = JsUtils::ReadOptionalProperty(
786 env, object, { napi_boolean, TYPE_BOOLEAN, "fullScreenMode" }, layoutParams.isFullScreen);
787 if (ret && layoutParams.isFullScreen) {
788 IMSA_HILOGD("full screen mode, no need to parse rect");
789 } else {
790 ret = JsUtils::ReadOptionalProperty(
791 env, object, { napi_object, TYPE_OBJECT, "landscapeRect" }, layoutParams.landscape.rect);
792 ret = ret && JsUtils::ReadOptionalProperty(
793 env, object, { napi_object, TYPE_OBJECT, "portraitRect" }, layoutParams.portrait.rect);
794 PARAM_CHECK_RETURN(env, ret, "landscapeRect and portraitRect should not be empty", TYPE_NONE, false);
795 }
796 JsUtils::ReadOptionalProperty(
797 env, object, { napi_number, TYPE_NUMBER, "landscapeAvoidY" }, layoutParams.landscape.avoidY);
798 JsUtils::ReadOptionalProperty(
799 env, object, { napi_number, TYPE_NUMBER, "portraitAvoidY" }, layoutParams.portrait.avoidY);
800 return ret;
801 }
802
Read(napi_env env,napi_value object,std::vector<Rosen::Rect> & hotAreas)803 bool JsHotArea::Read(napi_env env, napi_value object, std::vector<Rosen::Rect> &hotAreas)
804 {
805 bool isArray = false;
806 napi_is_array(env, object, &isArray);
807 PARAM_CHECK_RETURN(env, isArray, "inputRegion", TYPE_ARRAY, false);
808 uint32_t length = 0;
809 napi_status status = napi_get_array_length(env, object, &length);
810 PARAM_CHECK_RETURN(env, status == napi_ok, "get array failed", TYPE_NONE, false);
811 PARAM_CHECK_RETURN(
812 env, (length > 0) && (length <= MAX_INPUT_REGION_LEN), "inputRegion size limit: [1, 4]", TYPE_NONE, false);
813 for (uint32_t i = 0; i < length; ++i) {
814 napi_value jsElement;
815 napi_get_element(env, object, i, &jsElement);
816 PARAM_CHECK_RETURN(
817 env, JsUtil::GetType(env, jsElement) == napi_object, "element of inputRegion", TYPE_OBJECT, false);
818 Rosen::Rect element;
819 PARAM_CHECK_RETURN(
820 env, JsRect::Read(env, jsElement, element), "failed to convert element in inputRegion", TYPE_NONE, false);
821 hotAreas.push_back(element);
822 }
823 return true;
824 }
SetImmersiveMode(napi_env env,napi_callback_info info)825 napi_value JsPanel::SetImmersiveMode(napi_env env, napi_callback_info info)
826 {
827 size_t argc = ARGC_MAX;
828 napi_value argv[ARGC_MAX] = { nullptr };
829 napi_value thisVar = nullptr;
830 napi_value retVal = JsUtil::Const::Null(env);
831 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
832 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required", TYPE_NONE, retVal);
833 int32_t immersiveMode = 0;
834 // 0 means the first param immersiveMode<ImmersiveMode>
835 bool result = JsUtil::GetValue(env, argv[0], immersiveMode);
836 PARAM_CHECK_RETURN(env, result, "immersiveMode type must be ImmersiveMode", TYPE_NONE, retVal);
837 auto panel = UnwrapPanel(env, thisVar);
838 RESULT_CHECK_RETURN(env, panel != nullptr, JsUtils::Convert(ErrorCode::ERROR_IME), "", TYPE_NONE, retVal);
839 PARAM_CHECK_RETURN(env,
840 (immersiveMode == static_cast<int32_t>(ImmersiveMode::NONE_IMMERSIVE) ||
841 immersiveMode == static_cast<int32_t>(ImmersiveMode::LIGHT_IMMERSIVE) ||
842 immersiveMode == static_cast<int32_t>(ImmersiveMode::DARK_IMMERSIVE)),
843 "immersiveMode type must be ImmersiveMode and can not be IMMERSIVE", TYPE_NONE, retVal);
844 JsEventInfo eventInfo = { std::chrono::system_clock::now(), JsEvent::SET_IMMERSIVE_MODE };
845 jsQueue_.Push(eventInfo);
846 jsQueue_.Wait(eventInfo);
847 auto ret = panel->SetImmersiveMode(ImmersiveMode(immersiveMode));
848 jsQueue_.Pop();
849 RESULT_CHECK_RETURN(env, ret == ErrorCode::NO_ERROR, JsUtils::Convert(ret), "", TYPE_NONE, retVal);
850 return retVal;
851 }
852
SetImmersiveEffect(napi_env env,napi_callback_info info)853 napi_value JsPanel::SetImmersiveEffect(napi_env env, napi_callback_info info)
854 {
855 size_t argc = ARGC_MAX;
856 napi_value argv[ARGC_MAX] = { nullptr };
857 napi_value thisVar = nullptr;
858 napi_value retVal = JsUtil::Const::Null(env);
859 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
860 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required", TYPE_NONE, retVal);
861
862 PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_object, "param effect type must be ImmersiveEffect",
863 TYPE_NONE, retVal);
864 ImmersiveEffect immersiveEffect;
865 PARAM_CHECK_RETURN(env, JsImmersiveEffect::Read(env, argv[0], immersiveEffect), "js param effect covert failed",
866 TYPE_NONE, retVal);
867
868 auto panel = UnwrapPanel(env, thisVar);
869 RESULT_CHECK_RETURN(env, panel != nullptr, JsUtils::Convert(ErrorCode::ERROR_IME), "", TYPE_NONE, retVal);
870 JsEventInfo eventInfo = { std::chrono::system_clock::now(), JsEvent::SET_IMMERSIVE_EFFECT };
871 jsQueue_.Push(eventInfo);
872 jsQueue_.Wait(eventInfo);
873 auto ret = panel->SetImmersiveEffect(immersiveEffect);
874 jsQueue_.Pop();
875 RESULT_CHECK_RETURN(env, ret == ErrorCode::NO_ERROR, JsUtils::Convert(ret), "", TYPE_NONE, retVal);
876 return retVal;
877 }
878
GetImmersiveMode(napi_env env,napi_callback_info info)879 napi_value JsPanel::GetImmersiveMode(napi_env env, napi_callback_info info)
880 {
881 napi_value thisVar = nullptr;
882 napi_value retVal = JsUtil::Const::Null(env);
883 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
884 auto panel = UnwrapPanel(env, thisVar);
885 RESULT_CHECK_RETURN(env, panel != nullptr, JsUtils::Convert(ErrorCode::ERROR_IME), "", TYPE_NONE, retVal);
886 JsEventInfo eventInfo = { std::chrono::system_clock::now(), JsEvent::GET_IMMERSIVE_MODE };
887 jsQueue_.Push(eventInfo);
888 jsQueue_.Wait(eventInfo);
889 auto immersiveMode = panel->GetImmersiveMode();
890 jsQueue_.Pop();
891 napi_value jsImmersiveMode = nullptr;
892 NAPI_CALL(env, napi_create_int32(env, static_cast<int32_t>(immersiveMode), &jsImmersiveMode));
893 return jsImmersiveMode;
894 }
895
SetKeepScreenOn(napi_env env,napi_callback_info info)896 napi_value JsPanel::SetKeepScreenOn(napi_env env, napi_callback_info info)
897 {
898 auto ctxt = std::make_shared<PanelContentContext>(env, info);
899 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
900 PARAM_CHECK_RETURN(env, ctxt->inputMethodPanel != nullptr, "panel is null", TYPE_NONE, napi_generic_failure);
901 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameters is required", TYPE_NONE, napi_generic_failure);
902 PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], ctxt->isKeepScreenOn),
903 "isKeepScreenOn type must be boolean!", TYPE_NONE, napi_generic_failure);
904 return napi_ok;
905 };
906 auto exec = [ctxt](AsyncCall::Context *ctx) {
907 if (ctxt->inputMethodPanel == nullptr) {
908 IMSA_HILOGE("inputMethodPanel_ is nullptr!");
909 return;
910 }
911 auto ret = ctxt->inputMethodPanel->SetKeepScreenOn(ctxt->isKeepScreenOn);
912 if (ret == ErrorCode::NO_ERROR) {
913 ctxt->SetState(napi_ok);
914 return;
915 }
916 ctxt->SetErrorCode(ret);
917 };
918
919 ctxt->SetAction(std::move(input));
920 // 1 means JsAPI:setKeepScreenOn has 1 params at most.
921 AsyncCall asyncCall(env, info, ctxt, 1);
922 return asyncCall.Call(env, exec, "setKeepScreenOn");
923 }
924 } // namespace MiscServices
925 } // namespace OHOS