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 27namespace OHOS { 28namespace MiscServices { 29using namespace std::chrono; 30using WMError = OHOS::Rosen::WMError; 31const std::string JsPanel::CLASS_NAME = "Panel"; 32thread_local napi_ref JsPanel::panelConstructorRef_ = nullptr; 33std::mutex JsPanel::panelConstructorMutex_; 34constexpr int32_t MAX_WAIT_TIME = 10; 35FFRTBlockQueue<JsEventInfo> JsPanel::jsQueue_{ MAX_WAIT_TIME }; 36 37napi_value JsPanel::Init(napi_env env) 38{ 39 IMSA_HILOGI("JsPanel start."); 40 napi_value constructor = nullptr; 41 std::lock_guard<std::mutex> lock(panelConstructorMutex_); 42 if (panelConstructorRef_ != nullptr) { 43 napi_status status = napi_get_reference_value(env, panelConstructorRef_, &constructor); 44 CHECK_RETURN(status == napi_ok, "failed to get jsPanel constructor.", nullptr); 45 return constructor; 46 } 47 const napi_property_descriptor properties[] = { 48 DECLARE_NAPI_FUNCTION("setUiContent", SetUiContent), 49 DECLARE_NAPI_FUNCTION("resize", Resize), 50 DECLARE_NAPI_FUNCTION("moveTo", MoveTo), 51 DECLARE_NAPI_FUNCTION("show", Show), 52 DECLARE_NAPI_FUNCTION("hide", Hide), 53 DECLARE_NAPI_FUNCTION("changeFlag", ChangeFlag), 54 DECLARE_NAPI_FUNCTION("setPrivacyMode", SetPrivacyMode), 55 DECLARE_NAPI_FUNCTION("on", Subscribe), 56 DECLARE_NAPI_FUNCTION("off", UnSubscribe), 57 DECLARE_NAPI_FUNCTION("adjustPanelRect", AdjustPanelRect), 58 }; 59 NAPI_CALL(env, napi_define_class(env, CLASS_NAME.c_str(), CLASS_NAME.size(), JsNew, nullptr, 60 sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor)); 61 CHECK_RETURN(constructor != nullptr, "failed to define class!", nullptr); 62 NAPI_CALL(env, napi_create_reference(env, constructor, 1, &panelConstructorRef_)); 63 return constructor; 64} 65 66napi_value JsPanel::JsNew(napi_env env, napi_callback_info info) 67{ 68 IMSA_HILOGD("create panel instance start."); 69 std::shared_ptr<PanelListenerImpl> panelImpl = PanelListenerImpl::GetInstance(); 70 if (panelImpl != nullptr) { 71 IMSA_HILOGD("set eventHandler."); 72 panelImpl->SetEventHandler(AppExecFwk::EventHandler::Current()); 73 } 74 JsPanel *panel = new (std::nothrow) JsPanel(); 75 CHECK_RETURN(panel != nullptr, "no memory for JsPanel!", nullptr); 76 auto finalize = [](napi_env env, void *data, void *hint) { 77 IMSA_HILOGD("jsPanel finalize."); 78 auto *jsPanel = reinterpret_cast<JsPanel *>(data); 79 CHECK_RETURN_VOID(jsPanel != nullptr, "finalize nullptr!"); 80 jsPanel->GetNative() = nullptr; 81 delete jsPanel; 82 }; 83 napi_value thisVar = nullptr; 84 napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr); 85 if (status != napi_ok) { 86 IMSA_HILOGE("failed to get cb info: %{public}d!", status); 87 delete panel; 88 return nullptr; 89 } 90 status = napi_wrap(env, thisVar, panel, finalize, nullptr, nullptr); 91 if (status != napi_ok) { 92 IMSA_HILOGE("failed to wrap: %{public}d!", status); 93 delete panel; 94 return nullptr; 95 } 96 return thisVar; 97} 98 99JsPanel::~JsPanel() 100{ 101 inputMethodPanel_ = nullptr; 102} 103 104void JsPanel::SetNative(const std::shared_ptr<InputMethodPanel> &panel) 105{ 106 inputMethodPanel_ = panel; 107} 108 109std::shared_ptr<InputMethodPanel> JsPanel::GetNative() 110{ 111 return inputMethodPanel_; 112} 113 114napi_value JsPanel::SetUiContent(napi_env env, napi_callback_info info) 115{ 116 IMSA_HILOGI("JsPanel start."); 117 auto ctxt = std::make_shared<PanelContentContext>(env, info); 118 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { 119 napi_status status = napi_generic_failure; 120 PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, status); 121 // 0 means the first param path<std::string> 122 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], ctxt->path) == napi_ok, 123 "js param path covert failed, must be string!", TYPE_NONE, status); 124 // if type of argv[1] is object, we will get value of 'storage' from it. 125 if (argc >= 2) { 126 napi_valuetype valueType = napi_undefined; 127 status = napi_typeof(env, argv[1], &valueType); 128 CHECK_RETURN(status == napi_ok, "get valueType failed!", status); 129 if (valueType == napi_object) { 130 napi_ref storage = nullptr; 131 napi_create_reference(env, argv[1], 1, &storage); 132 auto contentStorage = (storage == nullptr) ? nullptr 133 : std::shared_ptr<NativeReference>( 134 reinterpret_cast<NativeReference *>(storage)); 135 ctxt->contentStorage = contentStorage; 136 } 137 } 138 return napi_ok; 139 }; 140 141 auto exec = [ctxt](AsyncCall::Context *ctx) { ctxt->SetState(napi_ok); }; 142 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { 143 CHECK_RETURN(ctxt->inputMethodPanel != nullptr, "inputMethodPanel is nullptr!", napi_generic_failure); 144 auto code = ctxt->inputMethodPanel->SetUiContent(ctxt->path, env, ctxt->contentStorage); 145 if (code == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) { 146 ctxt->SetErrorCode(code); 147 ctxt->SetErrorMessage("path should be a path to specific page."); 148 return napi_generic_failure; 149 } 150 return napi_ok; 151 }; 152 ctxt->SetAction(std::move(input), std::move(output)); 153 // 3 means JsAPI:setUiContent has 3 params at most. 154 AsyncCall asyncCall(env, info, ctxt, 3); 155 return asyncCall.Call(env, exec, "setUiContent"); 156} 157 158napi_value JsPanel::Resize(napi_env env, napi_callback_info info) 159{ 160 auto ctxt = std::make_shared<PanelContentContext>(env, info); 161 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { 162 napi_status status = napi_generic_failure; 163 PARAM_CHECK_RETURN(env, argc > 1, "at least two parameters is required", TYPE_NONE, status); 164 // 0 means the first param width<uint32_t> 165 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], ctxt->width) == napi_ok, 166 "width type must be number!", TYPE_NONE, status); 167 // 1 means the second param height<uint32_t> 168 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[1], ctxt->height) == napi_ok, 169 "height type must be number!", TYPE_NONE, status); 170 ctxt->info = { std::chrono::system_clock::now(), JsEvent::RESIZE }; 171 jsQueue_.Push(ctxt->info); 172 return napi_ok; 173 }; 174 175 auto exec = [ctxt](AsyncCall::Context *ctx) { 176 jsQueue_.Wait(ctxt->info); 177 if (ctxt->inputMethodPanel == nullptr) { 178 IMSA_HILOGE("inputMethodPanel_ is nullptr!"); 179 jsQueue_.Pop(); 180 return; 181 } 182 SysPanelStatus sysPanelStatus = { 183 InputType::NONE, 184 ctxt->inputMethodPanel->GetPanelFlag(), 185 ctxt->width, 186 ctxt->height 187 }; 188 InputMethodAbility::GetInstance()->NotifyPanelStatus(ctxt->inputMethodPanel, sysPanelStatus); 189 auto code = ctxt->inputMethodPanel->Resize(ctxt->width, ctxt->height); 190 jsQueue_.Pop(); 191 if (code == ErrorCode::NO_ERROR) { 192 ctxt->SetState(napi_ok); 193 return; 194 } 195 ctxt->SetErrorCode(code); 196 }; 197 ctxt->SetAction(std::move(input)); 198 // 3 means JsAPI:resize has 3 params at most. 199 AsyncCall asyncCall(env, info, ctxt, 3); 200 return asyncCall.Call(env, exec, "resize"); 201} 202 203napi_value JsPanel::MoveTo(napi_env env, napi_callback_info info) 204{ 205 auto ctxt = std::make_shared<PanelContentContext>(env, info); 206 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { 207 napi_status status = napi_generic_failure; 208 PARAM_CHECK_RETURN(env, argc > 1, "at least two parameters is required ", TYPE_NONE, status); 209 // 0 means the first param x<int32_t> 210 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[0], ctxt->x) == napi_ok, "x type must be number", 211 TYPE_NONE, status); 212 // 1 means the second param y<int32_t> 213 PARAM_CHECK_RETURN(env, JsUtils::GetValue(env, argv[1], ctxt->y) == napi_ok, "y type must be number", 214 TYPE_NONE, status); 215 ctxt->info = { std::chrono::system_clock::now(), JsEvent::MOVE_TO }; 216 jsQueue_.Push(ctxt->info); 217 return napi_ok; 218 }; 219 220 auto exec = [ctxt](AsyncCall::Context *ctx) { 221 int64_t start = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); 222 jsQueue_.Wait(ctxt->info); 223 PrintEditorQueueInfoIfTimeout(start, ctxt->info); 224 if (ctxt->inputMethodPanel == nullptr) { 225 IMSA_HILOGE("inputMethodPanel_ is nullptr!"); 226 jsQueue_.Pop(); 227 return; 228 } 229 auto code = ctxt->inputMethodPanel->MoveTo(ctxt->x, ctxt->y); 230 jsQueue_.Pop(); 231 if (code == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) { 232 ctxt->SetErrorCode(code); 233 return; 234 } 235 ctxt->SetState(napi_ok); 236 }; 237 ctxt->SetAction(std::move(input)); 238 // 3 means JsAPI:moveTo has 3 params at most. 239 AsyncCall asyncCall(env, info, ctxt, 3); 240 return asyncCall.Call(env, exec, "moveTo"); 241} 242 243void JsPanel::PrintEditorQueueInfoIfTimeout(int64_t start, const JsEventInfo ¤tInfo) 244{ 245 int64_t end = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); 246 if (end - start >= MAX_WAIT_TIME) { 247 JsEventInfo frontInfo; 248 auto ret = jsQueue_.GetFront(frontInfo); 249 int64_t frontTime = duration_cast<microseconds>(frontInfo.timestamp.time_since_epoch()).count(); 250 int64_t currentTime = duration_cast<microseconds>(currentInfo.timestamp.time_since_epoch()).count(); 251 IMSA_HILOGI("ret:%{public}d,front[%{public}" PRId64 ",%{public}d],current[%{public}" PRId64 ",%{public}d]", ret, 252 frontTime, static_cast<int32_t>(frontInfo.event), currentTime, static_cast<int32_t>(currentInfo.event)); 253 } 254} 255 256napi_value JsPanel::Show(napi_env env, napi_callback_info info) 257{ 258 InputMethodSyncTrace tracer("JsPanel_Show"); 259 auto ctxt = std::make_shared<PanelContentContext>(env, info); 260 auto exec = [ctxt](AsyncCall::Context *ctx) { 261 CHECK_RETURN_VOID(ctxt->inputMethodPanel != nullptr, "inputMethodPanel is nullptr!"); 262 auto code = InputMethodAbility::GetInstance()->ShowPanel(ctxt->inputMethodPanel); 263 if (code == ErrorCode::NO_ERROR) { 264 ctxt->SetState(napi_ok); 265 return; 266 } 267 ctxt->SetErrorCode(code); 268 }; 269 // 1 means JsAPI:show has 1 param at most. 270 AsyncCall asyncCall(env, info, ctxt, 1); 271 return asyncCall.Call(env, exec, "show"); 272} 273 274napi_value JsPanel::Hide(napi_env env, napi_callback_info info) 275{ 276 InputMethodSyncTrace tracer("JsPanel_Hide"); 277 auto ctxt = std::make_shared<PanelContentContext>(env, info); 278 auto exec = [ctxt](AsyncCall::Context *ctx) { 279 CHECK_RETURN_VOID(ctxt->inputMethodPanel != nullptr, "inputMethodPanel is nullptr!"); 280 auto code = InputMethodAbility::GetInstance()->HidePanel(ctxt->inputMethodPanel); 281 if (code == ErrorCode::NO_ERROR) { 282 ctxt->SetState(napi_ok); 283 return; 284 } 285 ctxt->SetErrorCode(code); 286 }; 287 // 1 means JsAPI:hide has 1 param at most. 288 AsyncCall asyncCall(env, info, ctxt, 1); 289 return asyncCall.Call(env, exec, "panel.hide"); 290} 291 292napi_value JsPanel::ChangeFlag(napi_env env, napi_callback_info info) 293{ 294 size_t argc = ARGC_MAX; 295 napi_value argv[ARGC_MAX] = { nullptr }; 296 napi_value thisVar = nullptr; 297 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); 298 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, nullptr); 299 int32_t panelFlag = 0; 300 // 0 means the first param flag<PanelFlag> 301 napi_status status = JsUtils::GetValue(env, argv[0], panelFlag); 302 PARAM_CHECK_RETURN(env, status == napi_ok, "flag type must be PanelFlag!", TYPE_NONE, nullptr); 303 auto inputMethodPanel = UnwrapPanel(env, thisVar); 304 if (inputMethodPanel == nullptr) { 305 IMSA_HILOGE("inputMethodPanel is nullptr!"); 306 return nullptr; 307 } 308 PARAM_CHECK_RETURN(env, 309 (panelFlag == PanelFlag::FLG_FIXED || panelFlag == PanelFlag::FLG_FLOATING || 310 panelFlag == PanelFlag::FLG_CANDIDATE_COLUMN), 311 "flag type must be one of PanelFlag!", TYPE_NONE, nullptr); 312 JsEventInfo eventInfo = { std::chrono::system_clock::now(), JsEvent::CHANGE_FLAG }; 313 jsQueue_.Push(eventInfo); 314 jsQueue_.Wait(eventInfo); 315 auto ret = inputMethodPanel->ChangePanelFlag(PanelFlag(panelFlag)); 316 jsQueue_.Pop(); 317 CHECK_RETURN(ret == ErrorCode::NO_ERROR, "failed to ChangePanelFlag!", nullptr); 318 return nullptr; 319} 320 321napi_value JsPanel::SetPrivacyMode(napi_env env, napi_callback_info info) 322{ 323 size_t argc = ARGC_MAX; 324 napi_value argv[ARGC_MAX] = { nullptr }; 325 napi_value thisVar = nullptr; 326 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); 327 PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, nullptr); 328 bool isPrivacyMode = false; 329 // 0 means the first param isPrivacyMode<boolean> 330 napi_status status = JsUtils::GetValue(env, argv[0], isPrivacyMode); 331 PARAM_CHECK_RETURN(env, status == napi_ok, "isPrivacyMode type must be boolean!", TYPE_NONE, nullptr); 332 CHECK_RETURN(status == napi_ok, "failed to get isPrivacyMode!", nullptr); 333 auto inputMethodPanel = UnwrapPanel(env, thisVar); 334 if (inputMethodPanel == nullptr) { 335 IMSA_HILOGE("inputMethodPanel is nullptr!"); 336 return nullptr; 337 } 338 auto ret = inputMethodPanel->SetPrivacyMode(isPrivacyMode); 339 if (ret == static_cast<int32_t>(WMError::WM_ERROR_INVALID_PERMISSION)) { 340 JsUtils::ThrowException(env, JsUtils::Convert(ErrorCode::ERROR_STATUS_PERMISSION_DENIED), 341 " ohos.permission.PRIVACY_WINDOW permission denied", TYPE_NONE); 342 } 343 CHECK_RETURN(ret == ErrorCode::NO_ERROR, "failed to SetPrivacyMode!", nullptr); 344 return nullptr; 345} 346 347napi_value JsPanel::Subscribe(napi_env env, napi_callback_info info) 348{ 349 IMSA_HILOGD("JsPanel start."); 350 size_t argc = ARGC_MAX; 351 napi_value argv[ARGC_MAX] = { nullptr }; 352 napi_value thisVar = nullptr; 353 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); 354 std::string type; 355 // 2 means least param num. 356 if (argc < 2 || !JsUtil::GetValue(env, argv[0], type) || 357 !EventChecker::IsValidEventType(EventSubscribeModule::PANEL, type) || 358 JsUtil::GetType(env, argv[1]) != napi_function) { 359 IMSA_HILOGE("subscribe failed, type: %{public}s!", type.c_str()); 360 return nullptr; 361 } 362 IMSA_HILOGD("subscribe type: %{public}s.", type.c_str()); 363 std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance(); 364 auto inputMethodPanel = UnwrapPanel(env, thisVar); 365 // 1 means the second param callback. 366 std::shared_ptr<JSCallbackObject> cbObject = 367 std::make_shared<JSCallbackObject>(env, argv[1], std::this_thread::get_id()); 368 observer->Subscribe(inputMethodPanel->windowId_, type, cbObject); 369 bool ret = inputMethodPanel->SetPanelStatusListener(observer, type); 370 if (!ret) { 371 IMSA_HILOGE("failed to subscribe %{public}s!", type.c_str()); 372 observer->RemoveInfo(type, inputMethodPanel->windowId_); 373 } 374 napi_value result = nullptr; 375 napi_get_undefined(env, &result); 376 return result; 377} 378 379napi_value JsPanel::UnSubscribe(napi_env env, napi_callback_info info) 380{ 381 size_t argc = ARGC_MAX; 382 napi_value argv[ARGC_MAX] = { nullptr }; 383 napi_value thisVar = nullptr; 384 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); 385 std::string type; 386 // 1 means least param num. 387 PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, nullptr); 388 PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], type), "type must be string!", TYPE_NONE, nullptr); 389 PARAM_CHECK_RETURN(env, EventChecker::IsValidEventType(EventSubscribeModule::PANEL, type), 390 "type should be show/hide/sizeChange!", TYPE_NONE, nullptr); 391 // if the second param is not napi_function/napi_null/napi_undefined, return 392 auto paramType = JsUtil::GetType(env, argv[1]); 393 PARAM_CHECK_RETURN(env, (paramType == napi_function || paramType == napi_null || paramType == napi_undefined), 394 "callback should be function or null or undefined!", TYPE_NONE, nullptr); 395 // if the second param is napi_function, delete it, else delete all 396 argv[1] = paramType == napi_function ? argv[1] : nullptr; 397 398 IMSA_HILOGD("unsubscribe type: %{public}s.", type.c_str()); 399 std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance(); 400 auto inputMethodPanel = UnwrapPanel(env, thisVar); 401 if (inputMethodPanel == nullptr) { 402 IMSA_HILOGE("inputMethodPanel is nullptr!"); 403 return nullptr; 404 } 405 observer->RemoveInfo(type, inputMethodPanel->windowId_); 406 inputMethodPanel->ClearPanelListener(type); 407 napi_value result = nullptr; 408 napi_get_null(env, &result); 409 return result; 410} 411 412napi_status JsPanel::CheckParam(napi_env env, size_t argc, napi_value *argv, 413 std::shared_ptr<PanelContentContext> ctxt) 414{ 415 napi_status status = napi_generic_failure; 416 PARAM_CHECK_RETURN(env, argc > 1, "at least two paramsters is required", TYPE_NONE, status); 417 // 0 means the first param flag 418 PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "flag", 419 TYPE_NUMBER, napi_generic_failure); 420 int32_t panelFlag = 0; 421 CHECK_RETURN(JsUtils::GetValue(env, argv[0], panelFlag) == napi_ok, 422 "js param flag covert failed", napi_generic_failure); 423 ctxt->panelFlag = PanelFlag(panelFlag); 424 if (InputMethodAbility::GetInstance()->IsDefaultIme()) { 425 PARAM_CHECK_RETURN(env, ctxt->panelFlag == 0 || ctxt->panelFlag == 1 || 426 ctxt->panelFlag == FLG_CANDIDATE_COLUMN, 427 "param flag type shoule be FLG_FIXED or FLG_FLOATING or FLG_CANDIDATE_COLUMN", TYPE_NONE, 428 napi_generic_failure); 429 } else { 430 PARAM_CHECK_RETURN(env, ctxt->panelFlag == 0 || ctxt->panelFlag == 1, 431 "param flag type shoule be FLG_FIXED or FLG_FLOATING ", TYPE_NONE, napi_generic_failure); 432 } 433 // 1 means the second param rect 434 PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[1]) == napi_object, "param rect type must be PanelRect", 435 TYPE_NONE, napi_generic_failure); 436 PARAM_CHECK_RETURN(env, JsPanelRect::Read(env, argv[1], ctxt->layoutParams), "js param rect covert failed", 437 TYPE_NONE, napi_generic_failure); 438 return napi_ok; 439} 440 441napi_value JsPanel::AdjustPanelRect(napi_env env, napi_callback_info info) 442{ 443 auto ctxt = std::make_shared<PanelContentContext>(env, info); 444 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { 445 if (CheckParam(env, argc, argv, ctxt) != napi_ok) { 446 return napi_generic_failure; 447 } 448 ctxt->info = { std::chrono::system_clock::now(), JsEvent::ADJUST_PANEL_RECT }; 449 jsQueue_.Push(ctxt->info); 450 return napi_ok; 451 }; 452 453 auto exec = [ctxt](AsyncCall::Context *ctx) { 454 jsQueue_.Wait(ctxt->info); 455 if (ctxt->inputMethodPanel == nullptr) { 456 IMSA_HILOGE("inputMethodPanel_ is nullptr!"); 457 jsQueue_.Pop(); 458 return; 459 } 460 SysPanelStatus sysPanelStatus; 461 if (ctxt->inputMethodPanel->IsDisplayPortrait()) { 462 sysPanelStatus = { InputType::NONE, ctxt->panelFlag, ctxt->layoutParams.portraitRect.width_, 463 ctxt->layoutParams.portraitRect.height_ }; 464 } else { 465 sysPanelStatus = { InputType::NONE, ctxt->panelFlag, ctxt->layoutParams.landscapeRect.width_, 466 ctxt->layoutParams.landscapeRect.height_ }; 467 } 468 InputMethodAbility::GetInstance()->NotifyPanelStatus(ctxt->inputMethodPanel, sysPanelStatus); 469 auto code = ctxt->inputMethodPanel->AdjustPanelRect(ctxt->panelFlag, ctxt->layoutParams); 470 jsQueue_.Pop(); 471 if (code == ErrorCode::NO_ERROR) { 472 ctxt->SetState(napi_ok); 473 return; 474 } else if (code == ErrorCode::ERROR_PARAMETER_CHECK_FAILED) { 475 ctxt->SetErrorMessage("width limit:[0, displayWidth], height limit:[0, 70 percent of displayHeight]!"); 476 } 477 ctxt->SetErrorCode(code); 478 }; 479 ctxt->SetAction(std::move(input)); 480 // 2 means JsAPI:adjustPanelRect has 2 params at most 481 AsyncCall asyncCall(env, info, ctxt, 2); 482 return asyncCall.Call(env, exec, "adjustPanelRect"); 483} 484 485std::shared_ptr<InputMethodPanel> JsPanel::UnwrapPanel(napi_env env, napi_value thisVar) 486{ 487 void *native = nullptr; 488 napi_status status = napi_unwrap(env, thisVar, &native); 489 CHECK_RETURN((status == napi_ok && native != nullptr), "failed to unwrap!", nullptr); 490 auto jsPanel = reinterpret_cast<JsPanel *>(native); 491 if (jsPanel == nullptr) { 492 return nullptr; 493 } 494 auto inputMethodPanel = jsPanel->GetNative(); 495 CHECK_RETURN(inputMethodPanel != nullptr, "inputMethodPanel is nullptr", nullptr); 496 return inputMethodPanel; 497} 498 499napi_value JsPanelRect::Write(napi_env env, const LayoutParams &layoutParams) 500{ 501 napi_value jsObject = nullptr; 502 napi_create_object(env, &jsObject); 503 bool ret = 504 JsUtil::Object::WriteProperty(env, jsObject, "landscapeRect", JsRect::Write(env, layoutParams.landscapeRect)); 505 ret = ret && 506 JsUtil::Object::WriteProperty(env, jsObject, "portraitRect", JsRect::Write(env, layoutParams.portraitRect)); 507 return ret ? jsObject : JsUtil::Const::Null(env); 508} 509bool JsPanelRect::Read(napi_env env, napi_value object, LayoutParams &layoutParams) 510{ 511 napi_value rectObject = nullptr; 512 napi_get_named_property(env, object, "landscapeRect", &rectObject); 513 bool ret = JsRect::Read(env, rectObject, layoutParams.landscapeRect); 514 napi_get_named_property(env, object, "portraitRect", &rectObject); 515 ret = ret && JsRect::Read(env, rectObject, layoutParams.portraitRect); 516 return ret; 517} 518} // namespace MiscServices 519} // namespace OHOS