1 /*
2 * Copyright (c) 2022 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_input_device_cooperate_context.h"
17
18 #include <cstddef>
19 #include <cstdint>
20
21 #include "define_multimodal.h"
22 #include "mmi_log.h"
23 #include "napi_constants.h"
24 #include "util_napi.h"
25 #include "util_napi_error.h"
26
27 namespace OHOS {
28 namespace MMI {
29 namespace {
30 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "JsInputDeviceCooperateContext" };
31 constexpr const char *INPUT_DEVICE_CLASS = "multimodalinput_input_device_class";
32 constexpr const char *INPUT_DEVICE_COOPERATE = "multimodal_input_device_cooperate";
33 } // namespace
34
JsInputDeviceCooperateContext()35 JsInputDeviceCooperateContext::JsInputDeviceCooperateContext()
36 : mgr_(std::make_shared<JsInputDeviceCooperateManager>()) {}
37
~JsInputDeviceCooperateContext()38 JsInputDeviceCooperateContext::~JsInputDeviceCooperateContext()
39 {
40 std::lock_guard<std::mutex> guard(mutex_);
41 auto jsInputDeviceMgr = mgr_;
42 mgr_.reset();
43 if (jsInputDeviceMgr != nullptr) {
44 jsInputDeviceMgr->ResetEnv();
45 }
46 }
47
Export(napi_env env,napi_value exports)48 napi_value JsInputDeviceCooperateContext::Export(napi_env env, napi_value exports)
49 {
50 CALL_INFO_TRACE;
51 auto instance = CreateInstance(env);
52 if (instance == nullptr) {
53 MMI_HILOGE("instance is nullptr");
54 return nullptr;
55 }
56 DeclareDeviceCooperateInterface(env, exports);
57 DeclareDeviceCooperateData(env, exports);
58 return exports;
59 }
60
Enable(napi_env env,napi_callback_info info)61 napi_value JsInputDeviceCooperateContext::Enable(napi_env env, napi_callback_info info)
62 {
63 CALL_INFO_TRACE;
64 size_t argc = 2;
65 napi_value argv[2] = {};
66 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
67
68 if (argc == 0) {
69 MMI_HILOGE("Wrong number of parameters");
70 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "enable", "boolean");
71 return nullptr;
72 }
73 if (!UtilNapi::TypeOf(env, argv[0], napi_boolean)) {
74 MMI_HILOGE("Thr first parameter is not boolean");
75 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "enable", "boolean");
76 return nullptr;
77 }
78 bool enable = false;
79 CHKRP(env, napi_get_value_bool(env, argv[0], &enable), GET_BOOL);
80
81 JsInputDeviceCooperateContext *jsDev = JsInputDeviceCooperateContext::GetInstance(env);
82 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceCooperateMgr();
83 if (argc == 1) {
84 return jsInputDeviceMgr->Enable(env, enable);
85 }
86 if (!UtilNapi::TypeOf(env, argv[1], napi_function)) {
87 MMI_HILOGE("The second parameter is not function");
88 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
89 return nullptr;
90 }
91 return jsInputDeviceMgr->Enable(env, enable, argv[1]);
92 }
93
Start(napi_env env,napi_callback_info info)94 napi_value JsInputDeviceCooperateContext::Start(napi_env env, napi_callback_info info)
95 {
96 CALL_INFO_TRACE;
97 size_t argc = 3;
98 napi_value argv[3] = {};
99 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
100
101 if (argc < 2) {
102 MMI_HILOGE("Wrong number of parameters");
103 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "sinkDeviceDescriptor", "string");
104 return nullptr;
105 }
106 if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
107 MMI_HILOGE("Thr first parameter is not boolean");
108 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "sinkDeviceDescriptor", "string");
109 return nullptr;
110 }
111 if (!UtilNapi::TypeOf(env, argv[1], napi_number)) {
112 MMI_HILOGE("The second parameter is not number");
113 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "srcInputDeviceId", "number");
114 return nullptr;
115 }
116 char sinkDeviceDescriptor[MAX_STRING_LEN] = {};
117 int32_t srcInputDeviceId = 0;
118 size_t length = 0;
119 CHKRP(env, napi_get_value_string_utf8(env, argv[0], sinkDeviceDescriptor,
120 sizeof(sinkDeviceDescriptor), &length), GET_STRING);
121 std::string sinkDeviceDescriptor_ = sinkDeviceDescriptor;
122 CHKRP(env, napi_get_value_int32(env, argv[1], &srcInputDeviceId), GET_INT32);
123
124 JsInputDeviceCooperateContext *jsDev = JsInputDeviceCooperateContext::GetInstance(env);
125 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceCooperateMgr();
126 if (argc == 2) {
127 return jsInputDeviceMgr->Start(env, sinkDeviceDescriptor, srcInputDeviceId);
128 }
129 if (!UtilNapi::TypeOf(env, argv[2], napi_function)) {
130 MMI_HILOGE("Thr third parameter is not function");
131 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
132 return nullptr;
133 }
134 return jsInputDeviceMgr->Start(env, std::string(sinkDeviceDescriptor), srcInputDeviceId, argv[2]);
135 }
136
Stop(napi_env env,napi_callback_info info)137 napi_value JsInputDeviceCooperateContext::Stop(napi_env env, napi_callback_info info)
138 {
139 CALL_INFO_TRACE;
140 size_t argc = 1;
141 napi_value argv[1] = {};
142 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
143
144 JsInputDeviceCooperateContext *jsDev = JsInputDeviceCooperateContext::GetInstance(env);
145 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceCooperateMgr();
146 if (argc == 0) {
147 return jsInputDeviceMgr->Stop(env);
148 }
149 if (!UtilNapi::TypeOf(env, argv[0], napi_function)) {
150 MMI_HILOGE("The first parameter is not function");
151 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
152 return nullptr;
153 }
154 return jsInputDeviceMgr->Stop(env, argv[0]);
155 }
156
GetState(napi_env env,napi_callback_info info)157 napi_value JsInputDeviceCooperateContext::GetState(napi_env env, napi_callback_info info)
158 {
159 CALL_INFO_TRACE;
160 size_t argc = 2;
161 napi_value argv[2] = {};
162 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
163
164 if (argc == 0) {
165 MMI_HILOGE("Wrong number of parameters");
166 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "deviceDescriptor", "string");
167 return nullptr;
168 }
169 if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
170 MMI_HILOGE("The first parameter is not string");
171 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "deviceDescriptor", "string");
172 return nullptr;
173 }
174 char deviceDescriptor[MAX_STRING_LEN] = { 0 };
175 size_t length = 0;
176 CHKRP(env, napi_get_value_string_utf8(env, argv[0], deviceDescriptor,
177 sizeof(deviceDescriptor), &length), GET_STRING);
178 std::string deviceDescriptor_ = deviceDescriptor;
179
180 JsInputDeviceCooperateContext *jsDev = JsInputDeviceCooperateContext::GetInstance(env);
181 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceCooperateMgr();
182 if (argc == 1) {
183 return jsInputDeviceMgr->GetState(env, deviceDescriptor_);
184 }
185 if (!UtilNapi::TypeOf(env, argv[1], napi_function)) {
186 MMI_HILOGE("The second parameter is not function");
187 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
188 return nullptr;
189 }
190 return jsInputDeviceMgr->GetState(env, deviceDescriptor_, argv[1]);
191 }
192
On(napi_env env,napi_callback_info info)193 napi_value JsInputDeviceCooperateContext::On(napi_env env, napi_callback_info info)
194 {
195 CALL_INFO_TRACE;
196 size_t argc = 2;
197 napi_value argv[2] = {};
198 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
199
200 if (argc == 0) {
201 MMI_HILOGE("Wrong number of parameters");
202 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
203 return nullptr;
204 }
205 if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
206 MMI_HILOGE("The first parameter is not string");
207 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
208 return nullptr;
209 }
210 char type[MAX_STRING_LEN] = {};
211 size_t length = 0;
212 CHKRP(env, napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &length), GET_STRING);
213 if (std::strcmp(type, "cooperation") != 0) {
214 THROWERR(env, "Register listener failed, the first parameter is invalid");
215 MMI_HILOGE("Register listener failed, the first parameter is invalid");
216 return nullptr;
217 }
218 JsInputDeviceCooperateContext *jsDev = JsInputDeviceCooperateContext::GetInstance(env);
219 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceCooperateMgr();
220 if (!UtilNapi::TypeOf(env, argv[1], napi_function)) {
221 MMI_HILOGE("The seocond parameter is not function");
222 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
223 return nullptr;
224 }
225 jsInputDeviceMgr->RegisterListener(env, type, argv[1]);
226 return nullptr;
227 }
228
Off(napi_env env,napi_callback_info info)229 napi_value JsInputDeviceCooperateContext::Off(napi_env env, napi_callback_info info)
230 {
231 CALL_INFO_TRACE;
232 size_t argc = 2;
233 napi_value argv[2] = {};
234 CHKRP(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr), GET_CB_INFO);
235
236 if (argc == 0) {
237 MMI_HILOGE("Wrong number of parameters");
238 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
239 return nullptr;
240 }
241 if (!UtilNapi::TypeOf(env, argv[0], napi_string)) {
242 MMI_HILOGE("The first parameter is not string");
243 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "type", "string");
244 return nullptr;
245 }
246 char type[MAX_STRING_LEN] = {};
247 size_t length = 0;
248 CHKRP(env, napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &length), GET_STRING);
249 std::string type_ = type;
250
251 JsInputDeviceCooperateContext *jsDev = JsInputDeviceCooperateContext::GetInstance(env);
252 auto jsInputDeviceMgr = jsDev->GetJsInputDeviceCooperateMgr();
253 if (argc == 1) {
254 jsInputDeviceMgr->UnregisterListener(env, type_);
255 return nullptr;
256 }
257 if (!UtilNapi::TypeOf(env, argv[1], napi_function)) {
258 MMI_HILOGE("The second parameter is not function");
259 THROWERR_API9(env, COMMON_PARAMETER_ERROR, "callback", "function");
260 return nullptr;
261 }
262 jsInputDeviceMgr->UnregisterListener(env, type_, argv[1]);
263 return nullptr;
264 }
265
GetJsInputDeviceCooperateMgr()266 std::shared_ptr<JsInputDeviceCooperateManager> JsInputDeviceCooperateContext::GetJsInputDeviceCooperateMgr()
267 {
268 std::lock_guard<std::mutex> guard(mutex_);
269 return mgr_;
270 }
271
CreateInstance(napi_env env)272 napi_value JsInputDeviceCooperateContext::CreateInstance(napi_env env)
273 {
274 CALL_INFO_TRACE;
275 napi_value global = nullptr;
276 CHKRP(env, napi_get_global(env, &global), GET_GLOBAL);
277
278 constexpr char className[] = "JsInputDeviceCooperateContext";
279 napi_value jsClass = nullptr;
280 napi_property_descriptor desc[] = {};
281 napi_status status = napi_define_class(env, className, sizeof(className),
282 JsInputDeviceCooperateContext::JsConstructor, nullptr, sizeof(desc) / sizeof(desc[0]), nullptr, &jsClass);
283 CHKRP(env, status, DEFINE_CLASS);
284
285 status = napi_set_named_property(env, global, INPUT_DEVICE_CLASS, jsClass);
286 CHKRP(env, status, SET_NAMED_PROPERTY);
287
288 napi_value jsInstance = nullptr;
289 CHKRP(env, napi_new_instance(env, jsClass, 0, nullptr, &jsInstance), NEW_INSTANCE);
290 CHKRP(env, napi_set_named_property(env, global, INPUT_DEVICE_COOPERATE, jsInstance),
291 SET_NAMED_PROPERTY);
292
293 JsInputDeviceCooperateContext *jsContext = nullptr;
294 CHKRP(env, napi_unwrap(env, jsInstance, (void**)&jsContext), UNWRAP);
295 CHKPP(jsContext);
296 CHKRP(env, napi_create_reference(env, jsInstance, 1, &(jsContext->contextRef_)), CREATE_REFERENCE);
297
298 uint32_t refCount = 0;
299 status = napi_reference_ref(env, jsContext->contextRef_, &refCount);
300 if (status != napi_ok) {
301 MMI_HILOGE("ref is nullptr");
302 napi_delete_reference(env, jsContext->contextRef_);
303 return nullptr;
304 }
305 return jsInstance;
306 }
307
JsConstructor(napi_env env,napi_callback_info info)308 napi_value JsInputDeviceCooperateContext::JsConstructor(napi_env env, napi_callback_info info)
309 {
310 CALL_INFO_TRACE;
311 napi_value thisVar = nullptr;
312 void *data = nullptr;
313 CHKRP(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data), GET_CB_INFO);
314
315 JsInputDeviceCooperateContext *jsContext = new (std::nothrow) JsInputDeviceCooperateContext();
316 CHKPP(jsContext);
317 napi_status status = napi_wrap(env, thisVar, jsContext, [](napi_env env, void *data, void *hin) {
318 MMI_HILOGI("jsvm ends");
319 JsInputDeviceCooperateContext *context = static_cast<JsInputDeviceCooperateContext*>(data);
320 delete context;
321 }, nullptr, nullptr);
322 if (status != napi_ok) {
323 delete jsContext;
324 MMI_HILOGE("%{public}s failed", std::string(WRAP).c_str());
325 auto infoTemp = std::string(__FUNCTION__) + ": " + std::string(WRAP) + " failed";
326 napi_throw_error(env, nullptr, infoTemp.c_str());
327 return nullptr;
328 }
329 return thisVar;
330 }
331
GetInstance(napi_env env)332 JsInputDeviceCooperateContext *JsInputDeviceCooperateContext::GetInstance(napi_env env)
333 {
334 CALL_INFO_TRACE;
335 napi_value global = nullptr;
336 CHKRP(env, napi_get_global(env, &global), GET_GLOBAL);
337
338 bool result = false;
339 CHKRP(env, napi_has_named_property(env, global, INPUT_DEVICE_COOPERATE, &result), HAS_NAMED_PROPERTY);
340 if (!result) {
341 MMI_HILOGE("multimodal_input_device_cooperate was not found");
342 return nullptr;
343 }
344
345 napi_value object = nullptr;
346 CHKRP(env, napi_get_named_property(env, global, INPUT_DEVICE_COOPERATE, &object), GET_NAMED_PROPERTY);
347 if (object == nullptr) {
348 MMI_HILOGE("object is nullptr");
349 return nullptr;
350 }
351
352 JsInputDeviceCooperateContext *instance = nullptr;
353 CHKRP(env, napi_unwrap(env, object, (void**)&instance), UNWRAP);
354 if (instance == nullptr) {
355 MMI_HILOGE("instance is nullptr");
356 return nullptr;
357 }
358 return instance;
359 }
360
DeclareDeviceCooperateInterface(napi_env env,napi_value exports)361 void JsInputDeviceCooperateContext::DeclareDeviceCooperateInterface(napi_env env, napi_value exports)
362 {
363 napi_value infoStart = nullptr;
364 CHKRV(env, napi_create_int32(env, static_cast<int32_t>(CooperationMessage::INFO_START), &infoStart),
365 CREATE_INT32);
366 napi_value infoSuccess = nullptr;
367 CHKRV(env, napi_create_int32(env, static_cast<int32_t>(CooperationMessage::INFO_SUCCESS), &infoSuccess),
368 CREATE_INT32);
369 napi_value infoFail = nullptr;
370 CHKRV(env, napi_create_int32(env, static_cast<int32_t>(CooperationMessage::INFO_FAIL), &infoFail),
371 CREATE_INT32);
372 napi_value stateOn = nullptr;
373 CHKRV(env, napi_create_int32(env, static_cast<int32_t>(CooperationMessage::STATE_ON), &stateOn),
374 CREATE_INT32);
375 napi_value stateOff = nullptr;
376 CHKRV(env, napi_create_int32(env, static_cast<int32_t>(CooperationMessage::STATE_OFF), &stateOff),
377 CREATE_INT32);
378
379 napi_property_descriptor msg[] = {
380 DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_INFO_START", infoStart),
381 DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_INFO_SUCCESS", infoSuccess),
382 DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_INFO_FAIL", infoFail),
383 DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_STATE_ON", stateOn),
384 DECLARE_NAPI_STATIC_PROPERTY("MSG_COOPERATE_STATE_OFF", stateOff),
385 };
386
387 napi_value eventMsg = nullptr;
388 CHKRV(env, napi_define_class(env, "EventMsg", NAPI_AUTO_LENGTH, EnumClassConstructor, nullptr,
389 sizeof(msg) / sizeof(*msg), msg, &eventMsg), DEFINE_CLASS);
390 CHKRV(env, napi_set_named_property(env, exports, "EventMsg", eventMsg), SET_NAMED_PROPERTY);
391 }
392
DeclareDeviceCooperateData(napi_env env,napi_value exports)393 void JsInputDeviceCooperateContext::DeclareDeviceCooperateData(napi_env env, napi_value exports)
394 {
395 napi_property_descriptor functions[] = {
396 DECLARE_NAPI_STATIC_FUNCTION("enable", Enable),
397 DECLARE_NAPI_STATIC_FUNCTION("start", Start),
398 DECLARE_NAPI_STATIC_FUNCTION("stop", Stop),
399 DECLARE_NAPI_STATIC_FUNCTION("getState", GetState),
400 DECLARE_NAPI_STATIC_FUNCTION("on", On),
401 DECLARE_NAPI_STATIC_FUNCTION("off", Off),
402 };
403 CHKRV(env, napi_define_properties(env, exports,
404 sizeof(functions) / sizeof(*functions), functions), DEFINE_PROPERTIES);
405 }
406
EnumClassConstructor(napi_env env,napi_callback_info info)407 napi_value JsInputDeviceCooperateContext::EnumClassConstructor(napi_env env, napi_callback_info info)
408 {
409 size_t argc = 0;
410 napi_value args[1] = {};
411 napi_value result = nullptr;
412 void *data = nullptr;
413 CHKRP(env, napi_get_cb_info(env, info, &argc, args, &result, &data), GET_CB_INFO);
414 return result;
415 }
416 } // namespace MMI
417 } // namespace OHOS
418