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 &currentInfo)
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