• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "js_util.h"
21 #include "js_utils.h"
22 #include "napi/native_common.h"
23 #include "panel_listener_impl.h"
24 
25 namespace OHOS {
26 namespace MiscServices {
27 const std::string JsPanel::CLASS_NAME = "Panel";
28 thread_local napi_ref JsPanel::panelConstructorRef_ = nullptr;
29 std::mutex JsPanel::panelConstructorMutex_;
30 
Init(napi_env env)31 napi_value JsPanel::Init(napi_env env)
32 {
33     IMSA_HILOGI("JsPanel in.");
34     napi_value constructor = nullptr;
35     std::lock_guard<std::mutex> lock(panelConstructorMutex_);
36     if (panelConstructorRef_ != nullptr) {
37         napi_status status = napi_get_reference_value(env, panelConstructorRef_, &constructor);
38         CHECK_RETURN(status == napi_ok, "Failed to get jsPanel constructor.", nullptr);
39         return constructor;
40     }
41     const napi_property_descriptor properties[] = {
42         DECLARE_NAPI_FUNCTION("setUiContent", SetUiContent),
43         DECLARE_NAPI_FUNCTION("resize", Resize),
44         DECLARE_NAPI_FUNCTION("moveTo", MoveTo),
45         DECLARE_NAPI_FUNCTION("show", Show),
46         DECLARE_NAPI_FUNCTION("hide", Hide),
47         DECLARE_NAPI_FUNCTION("changeFlag", ChangeFlag),
48         DECLARE_NAPI_FUNCTION("on", Subscribe),
49         DECLARE_NAPI_FUNCTION("off", UnSubscribe),
50     };
51     NAPI_CALL(env, napi_define_class(env, CLASS_NAME.c_str(), CLASS_NAME.size(), JsNew, nullptr,
52                        sizeof(properties) / sizeof(napi_property_descriptor), properties, &constructor));
53     CHECK_RETURN(constructor != nullptr, "napi_define_class failed!", nullptr);
54     NAPI_CALL(env, napi_create_reference(env, constructor, 1, &panelConstructorRef_));
55     return constructor;
56 }
57 
JsNew(napi_env env,napi_callback_info info)58 napi_value JsPanel::JsNew(napi_env env, napi_callback_info info)
59 {
60     IMSA_HILOGD("JsPanel, create panel instance in.");
61     JsPanel *panel = new (std::nothrow) JsPanel();
62     CHECK_RETURN(panel != nullptr, "no memory for JsPanel", nullptr);
63     auto finalize = [](napi_env env, void *data, void *hint) {
64         IMSA_HILOGI("jsPanel finalize.");
65         auto *jsPanel = reinterpret_cast<JsPanel *>(data);
66         CHECK_RETURN_VOID(jsPanel != nullptr, "finalize null!");
67         jsPanel->GetNative() = nullptr;
68         delete jsPanel;
69     };
70     napi_value thisVar = nullptr;
71     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
72     napi_status status = napi_wrap(env, thisVar, panel, finalize, nullptr, nullptr);
73     if (status != napi_ok) {
74         IMSA_HILOGE("JsPanel napi_wrap failed: %{public}d", status);
75         delete panel;
76         return nullptr;
77     }
78     return thisVar;
79 }
80 
~JsPanel()81 JsPanel::~JsPanel()
82 {
83     inputMethodPanel_ = nullptr;
84 }
85 
SetNative(const std::shared_ptr<InputMethodPanel> & panel)86 void JsPanel::SetNative(const std::shared_ptr<InputMethodPanel> &panel)
87 {
88     inputMethodPanel_ = panel;
89 }
90 
GetNative()91 std::shared_ptr<InputMethodPanel> JsPanel::GetNative()
92 {
93     return inputMethodPanel_;
94 }
95 
SetUiContent(napi_env env,napi_callback_info info)96 napi_value JsPanel::SetUiContent(napi_env env, napi_callback_info info)
97 {
98     IMSA_HILOGI("JsPanel in.");
99     auto ctxt = std::make_shared<PanelContentContext>(env, info);
100     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
101         napi_status status = napi_generic_failure;
102         PARAM_CHECK_RETURN(env, argc >= 1, "should 1 or 2 parameters!", TYPE_NONE, status);
103         // 0 means the first param path<std::string>
104         status = JsUtils::GetValue(env, argv[0], ctxt->path);
105         CHECK_RETURN(status == napi_ok, "get path failed!", status);
106         // if type of argv[1] is object, we will get value of 'storage' from it.
107         if (argc >= 2) {
108             napi_valuetype valueType = napi_undefined;
109             status = napi_typeof(env, argv[1], &valueType);
110             CHECK_RETURN(status == napi_ok, "get valueType failed!", status);
111             if (valueType == napi_object) {
112                 NativeValue *storage = nullptr;
113                 storage = reinterpret_cast<NativeValue *>(argv[1]);
114                 auto contentStorage = (storage == nullptr)
115                                           ? nullptr
116                                           : std::shared_ptr<NativeReference>(
117                                                 reinterpret_cast<NativeEngine *>(env)->CreateReference(storage, 1));
118                 ctxt->contentStorage = contentStorage;
119             }
120         }
121         return napi_ok;
122     };
123 
124     auto exec = [ctxt](AsyncCall::Context *ctx) { ctxt->SetState(napi_ok); };
125     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
126         CHECK_RETURN(ctxt->inputMethodPanel != nullptr, "inputMethodPanel is nullptr!", napi_generic_failure);
127         auto code = ctxt->inputMethodPanel->SetUiContent(
128             ctxt->path, *(reinterpret_cast<NativeEngine *>(env)), ctxt->contentStorage);
129         CHECK_RETURN(code == ErrorCode::NO_ERROR, "SetUiContent failed!", napi_generic_failure);
130         return napi_ok;
131     };
132     ctxt->SetAction(std::move(input), std::move(output));
133     // 3 means JsAPI:setUiContent has 3 params at most.
134     AsyncCall asyncCall(env, info, ctxt, 3);
135     return asyncCall.Call(env, exec, "setUiContent");
136 }
137 
Resize(napi_env env,napi_callback_info info)138 napi_value JsPanel::Resize(napi_env env, napi_callback_info info)
139 {
140     auto ctxt = std::make_shared<PanelContentContext>(env, info);
141     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
142         napi_status status = napi_generic_failure;
143         PARAM_CHECK_RETURN(env, argc > 1, "should 2 or 3 parameters!", TYPE_NONE, status);
144         // 0 means the first param width<uint32_t>
145         status = JsUtils::GetValue(env, argv[0], ctxt->width);
146         CHECK_RETURN(status == napi_ok, "get width failed!", status);
147         // 1 means the second param height<uint32_t>
148         status = JsUtils::GetValue(env, argv[1], ctxt->height);
149         CHECK_RETURN(status == napi_ok, "get height failed!", status);
150         return napi_ok;
151     };
152 
153     auto exec = [ctxt](AsyncCall::Context *ctx) {
154         CHECK_RETURN_VOID(ctxt->inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
155         auto code = ctxt->inputMethodPanel->Resize(ctxt->width, ctxt->height);
156         if (code == ErrorCode::NO_ERROR) {
157             ctxt->SetState(napi_ok);
158             return;
159         }
160         ctxt->SetErrorCode(code);
161     };
162     ctxt->SetAction(std::move(input));
163     // 3 means JsAPI:resize has 3 params at most.
164     AsyncCall asyncCall(env, info, ctxt, 3);
165     return asyncCall.Call(env, exec, "resize");
166 }
167 
MoveTo(napi_env env,napi_callback_info info)168 napi_value JsPanel::MoveTo(napi_env env, napi_callback_info info)
169 {
170     auto ctxt = std::make_shared<PanelContentContext>(env, info);
171     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
172         napi_status status = napi_generic_failure;
173         PARAM_CHECK_RETURN(env, argc > 1, " should 2 or 3 parameters! ", TYPE_NONE, status);
174         // 0 means the first param x<int32_t>
175         status = JsUtils::GetValue(env, argv[0], ctxt->x);
176         CHECK_RETURN(status == napi_ok, "get x failed!", status);
177         // 1 means the second param y<int32_t>
178         status = JsUtils::GetValue(env, argv[1], ctxt->y);
179         CHECK_RETURN(status == napi_ok, "get y failed!", status);
180         return napi_ok;
181     };
182 
183     auto exec = [ctxt](AsyncCall::Context *ctx) {
184         CHECK_RETURN_VOID(ctxt->inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
185         auto code = ctxt->inputMethodPanel->MoveTo(ctxt->x, ctxt->y);
186         if (code == ErrorCode::NO_ERROR) {
187             ctxt->SetState(napi_ok);
188             return;
189         }
190         ctxt->SetErrorCode(code);
191     };
192     ctxt->SetAction(std::move(input));
193     // 3 means JsAPI:moveTo has 3 params at most.
194     AsyncCall asyncCall(env, info, ctxt, 3);
195     return asyncCall.Call(env, exec, "moveTo");
196 }
197 
Show(napi_env env,napi_callback_info info)198 napi_value JsPanel::Show(napi_env env, napi_callback_info info)
199 {
200     auto ctxt = std::make_shared<PanelContentContext>(env, info);
201     auto exec = [ctxt](AsyncCall::Context *ctx) {
202         CHECK_RETURN_VOID(ctxt->inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
203         auto code = ctxt->inputMethodPanel->ShowPanel();
204         if (code == ErrorCode::NO_ERROR) {
205             ctxt->SetState(napi_ok);
206             return;
207         }
208         ctxt->SetErrorCode(code);
209     };
210     // 1 means JsAPI:show has 1 params at most.
211     AsyncCall asyncCall(env, info, ctxt, 1);
212     return asyncCall.Call(env, exec, "show");
213 }
214 
Hide(napi_env env,napi_callback_info info)215 napi_value JsPanel::Hide(napi_env env, napi_callback_info info)
216 {
217     auto ctxt = std::make_shared<PanelContentContext>(env, info);
218     auto exec = [ctxt](AsyncCall::Context *ctx) {
219         CHECK_RETURN_VOID(ctxt->inputMethodPanel != nullptr, "inputMethodPanel_ is nullptr.");
220         auto code = ctxt->inputMethodPanel->HidePanel();
221         if (code == ErrorCode::NO_ERROR) {
222             ctxt->SetState(napi_ok);
223             return;
224         }
225         ctxt->SetErrorCode(code);
226     };
227     // 1 means JsAPI:hide has 1 params at most.
228     AsyncCall asyncCall(env, info, ctxt, 1);
229     return asyncCall.Call(env, exec, "panel.hide");
230 }
231 
ChangeFlag(napi_env env,napi_callback_info info)232 napi_value JsPanel::ChangeFlag(napi_env env, napi_callback_info info)
233 {
234     size_t argc = ARGC_MAX;
235     napi_value argv[ARGC_MAX] = { nullptr };
236     napi_value thisVar = nullptr;
237     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
238     PARAM_CHECK_RETURN(env, argc > 0, " should 1 parameter! ", TYPE_NONE, nullptr);
239     int32_t panelFlag = 0;
240     // 0 means the first param flag<PanelFlag>
241     napi_status status = JsUtils::GetValue(env, argv[0], panelFlag);
242     CHECK_RETURN(status == napi_ok, "get panelFlag failed!", nullptr);
243     auto inputMethodPanel = UnwrapPanel(env, thisVar);
244     auto ret = inputMethodPanel->ChangePanelFlag(PanelFlag(panelFlag));
245     CHECK_RETURN(ret == ErrorCode::NO_ERROR, "ChangePanelFlag failed!", nullptr);
246     return nullptr;
247 }
248 
Subscribe(napi_env env,napi_callback_info info)249 napi_value JsPanel::Subscribe(napi_env env, napi_callback_info info)
250 {
251     IMSA_HILOGD("JsPanel in");
252     size_t argc = ARGC_MAX;
253     napi_value argv[ARGC_MAX] = { nullptr };
254     napi_value thisVar = nullptr;
255     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
256     std::string type;
257     // 2 means least param num.
258     if (argc < 2 || !JsUtil::GetValue(env, argv[0], type)
259         || !EventChecker::IsValidEventType(EventSubscribeModule::PANEL, type)
260         || JsUtil::GetType(env, argv[1]) != napi_function) {
261         IMSA_HILOGE("Subscribe failed, type:%{public}s", type.c_str());
262         return nullptr;
263     }
264     IMSA_HILOGD("Subscribe type:%{public}s", type.c_str());
265     std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance();
266     auto inputMethodPanel = UnwrapPanel(env, thisVar);
267     // 1 means the second param callback.
268     observer->SaveInfo(env, type, argv[1], inputMethodPanel->windowId_);
269     inputMethodPanel->SetPanelStatusListener(observer, type);
270     napi_value result = nullptr;
271     napi_get_undefined(env, &result);
272     return result;
273 }
274 
UnSubscribe(napi_env env,napi_callback_info info)275 napi_value JsPanel::UnSubscribe(napi_env env, napi_callback_info info)
276 {
277     size_t argc = ARGC_MAX;
278     napi_value argv[ARGC_MAX] = { nullptr };
279     napi_value thisVar = nullptr;
280     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
281     std::string type;
282     // 1 means least param num.
283     if (argc < 1 || !JsUtil::GetValue(env, argv[0], type)
284         || !EventChecker::IsValidEventType(EventSubscribeModule::PANEL, type)) {
285         IMSA_HILOGE("UnSubscribe failed, type:%{public}s", type.c_str());
286         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "please check the params", TYPE_NONE);
287         return nullptr;
288     }
289     // If the type of optional parameter is wrong, make it nullptr
290     if (JsUtil::GetType(env, argv[1]) != napi_function) {
291         argv[1] = nullptr;
292     }
293     IMSA_HILOGD("UnSubscribe type:%{public}s", type.c_str());
294     std::shared_ptr<PanelListenerImpl> observer = PanelListenerImpl::GetInstance();
295     auto inputMethodPanel = UnwrapPanel(env, thisVar);
296     observer->RemoveInfo(type, inputMethodPanel->windowId_);
297     inputMethodPanel->ClearPanelListener(type);
298     napi_value result = nullptr;
299     napi_get_null(env, &result);
300     return result;
301 }
302 
UnwrapPanel(napi_env env,napi_value thisVar)303 std::shared_ptr<InputMethodPanel> JsPanel::UnwrapPanel(napi_env env, napi_value thisVar)
304 {
305     void *native = nullptr;
306     napi_status status = napi_unwrap(env, thisVar, &native);
307     CHECK_RETURN((status == napi_ok && native != nullptr), "napi_unwrap failed!", nullptr);
308     auto jsPanel = reinterpret_cast<JsPanel *>(native);
309     if (jsPanel == nullptr) {
310         return nullptr;
311     }
312     auto inputMethodPanel = jsPanel->GetNative();
313     CHECK_RETURN(inputMethodPanel != nullptr, "inputMethodPanel is nullptr", nullptr);
314     return inputMethodPanel;
315 }
316 } // namespace MiscServices
317 } // namespace OHOS