1 /*
2 * Copyright (c) 2021-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_event_target.h"
17
18 #include "napi_constants.h"
19 #include "util_napi_error.h"
20
21 namespace OHOS {
22 namespace MMI {
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "JsEventTarget" };
25
26 std::mutex mutex_;
27 const std::string ADD_EVENT = "add";
28 const std::string REMOVE_EVENT = "remove";
29 } // namespace
30
JsEventTarget()31 JsEventTarget::JsEventTarget()
32 {
33 CALL_DEBUG_ENTER;
34 auto ret = devListener_.insert({ CHANGED_TYPE, std::vector<std::unique_ptr<JsUtil::CallbackInfo>>() });
35 CK(ret.second, VAL_NOT_EXP);
36 }
37
~JsEventTarget()38 JsEventTarget::~JsEventTarget() {}
39
EmitAddedDeviceEvent(uv_work_t * work,int32_t status)40 void JsEventTarget::EmitAddedDeviceEvent(uv_work_t *work, int32_t status)
41 {
42 CALL_DEBUG_ENTER;
43 std::lock_guard<std::mutex> guard(mutex_);
44 CHKPV(work);
45 if (work->data == nullptr) {
46 JsUtil::DeletePtr<uv_work_t*>(work);
47 MMI_HILOGE("Check data is null");
48 return;
49 }
50 auto temp = static_cast<std::unique_ptr<JsUtil::CallbackInfo>*>(work->data);
51 JsUtil::DeletePtr<uv_work_t*>(work);
52 auto addEvent = devListener_.find(CHANGED_TYPE);
53 if (addEvent == devListener_.end()) {
54 MMI_HILOGE("Find change event failed");
55 return;
56 }
57
58 for (const auto &item : addEvent->second) {
59 CHKPC(item->env);
60 if (item->ref != (*temp)->ref) {
61 continue;
62 }
63 napi_handle_scope scope = nullptr;
64 napi_open_handle_scope(item->env, &scope);
65 if (scope == nullptr) {
66 MMI_HILOGE("scope is nullptr");
67 return;
68 }
69 napi_value eventType = nullptr;
70 CHKRV_SCOPE(item->env, napi_create_string_utf8(item->env, ADD_EVENT.c_str(), NAPI_AUTO_LENGTH, &eventType),
71 CREATE_STRING_UTF8, scope);
72 napi_value deviceId = nullptr;
73 CHKRV_SCOPE(item->env, napi_create_int32(item->env, item->data.deviceId, &deviceId), CREATE_INT32, scope);
74 napi_value object = nullptr;
75 CHKRV_SCOPE(item->env, napi_create_object(item->env, &object), CREATE_OBJECT, scope);
76 CHKRV_SCOPE(item->env, napi_set_named_property(item->env, object, "type", eventType),
77 SET_NAMED_PROPERTY, scope);
78 CHKRV_SCOPE(item->env, napi_set_named_property(item->env, object, "deviceId", deviceId),
79 SET_NAMED_PROPERTY, scope);
80 napi_value handler = nullptr;
81 CHKRV_SCOPE(item->env, napi_get_reference_value(item->env, item->ref, &handler), GET_REFERENCE, scope);
82 napi_value ret = nullptr;
83 CHKRV_SCOPE(item->env, napi_call_function(item->env, nullptr, handler, 1, &object, &ret),
84 CALL_FUNCTION, scope);
85 napi_close_handle_scope(item->env, scope);
86 }
87 }
88
EmitRemoveDeviceEvent(uv_work_t * work,int32_t status)89 void JsEventTarget::EmitRemoveDeviceEvent(uv_work_t *work, int32_t status)
90 {
91 CALL_DEBUG_ENTER;
92 std::lock_guard<std::mutex> guard(mutex_);
93 CHKPV(work);
94 if (work->data == nullptr) {
95 JsUtil::DeletePtr<uv_work_t*>(work);
96 MMI_HILOGE("Check data is null");
97 return;
98 }
99 auto temp = static_cast<std::unique_ptr<JsUtil::CallbackInfo>*>(work->data);
100 JsUtil::DeletePtr<uv_work_t*>(work);
101 auto removeEvent = devListener_.find(CHANGED_TYPE);
102 if (removeEvent == devListener_.end()) {
103 MMI_HILOGE("Find change event failed");
104 return;
105 }
106
107 for (const auto &item : removeEvent->second) {
108 CHKPC(item->env);
109 if (item->ref != (*temp)->ref) {
110 continue;
111 }
112 napi_handle_scope scope = nullptr;
113 napi_open_handle_scope(item->env, &scope);
114 if (scope == nullptr) {
115 MMI_HILOGE("scope is nullptr");
116 return;
117 }
118 napi_value eventType = nullptr;
119 CHKRV_SCOPE(item->env, napi_create_string_utf8(item->env, REMOVE_EVENT.c_str(), NAPI_AUTO_LENGTH,
120 &eventType),
121 CREATE_STRING_UTF8, scope);
122
123 napi_value deviceId = nullptr;
124 CHKRV_SCOPE(item->env, napi_create_int32(item->env, item->data.deviceId, &deviceId),
125 CREATE_INT32, scope);
126
127 napi_value object = nullptr;
128 CHKRV_SCOPE(item->env, napi_create_object(item->env, &object), CREATE_OBJECT, scope);
129 CHKRV_SCOPE(item->env, napi_set_named_property(item->env, object, "type", eventType),
130 SET_NAMED_PROPERTY, scope);
131 CHKRV_SCOPE(item->env, napi_set_named_property(item->env, object, "deviceId", deviceId),
132 SET_NAMED_PROPERTY, scope);
133
134 napi_value handler = nullptr;
135 CHKRV_SCOPE(item->env, napi_get_reference_value(item->env, item->ref, &handler), GET_REFERENCE, scope);
136
137 napi_value ret = nullptr;
138 CHKRV_SCOPE(item->env, napi_call_function(item->env, nullptr, handler, 1, &object, &ret),
139 CALL_FUNCTION, scope);
140 napi_close_handle_scope(item->env, scope);
141 }
142 }
143
OnDeviceAdded(int32_t deviceId,const std::string & type)144 void JsEventTarget::OnDeviceAdded(int32_t deviceId, const std::string &type)
145 {
146 CALL_DEBUG_ENTER;
147 std::lock_guard<std::mutex> guard(mutex_);
148 auto changeEvent = devListener_.find(CHANGED_TYPE);
149 if (changeEvent == devListener_.end()) {
150 MMI_HILOGE("Find %{public}s failed", CHANGED_TYPE.c_str());
151 return;
152 }
153
154 for (auto &item : changeEvent->second) {
155 CHKPC(item);
156 CHKPC(item->env);
157 uv_loop_s *loop = nullptr;
158 CHKRV(item->env, napi_get_uv_event_loop(item->env, &loop), GET_UV_LOOP);
159 uv_work_t *work = new (std::nothrow) uv_work_t;
160 CHKPV(work);
161 item->data.deviceId = deviceId;
162 work->data = static_cast<void*>(&item);
163 int32_t ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, EmitAddedDeviceEvent);
164 if (ret != 0) {
165 MMI_HILOGE("uv_queue_work failed");
166 JsUtil::DeletePtr<uv_work_t*>(work);
167 return;
168 }
169 }
170 }
171
OnDeviceRemoved(int32_t deviceId,const std::string & type)172 void JsEventTarget::OnDeviceRemoved(int32_t deviceId, const std::string &type)
173 {
174 CALL_DEBUG_ENTER;
175 std::lock_guard<std::mutex> guard(mutex_);
176 auto changeEvent = devListener_.find(CHANGED_TYPE);
177 if (changeEvent == devListener_.end()) {
178 MMI_HILOGE("Find %{public}s failed", CHANGED_TYPE.c_str());
179 return;
180 }
181 for (auto &item : changeEvent->second) {
182 CHKPC(item);
183 CHKPC(item->env);
184 uv_loop_s *loop = nullptr;
185 CHKRV(item->env, napi_get_uv_event_loop(item->env, &loop), GET_UV_LOOP);
186 uv_work_t *work = new (std::nothrow) uv_work_t;
187 CHKPV(work);
188 item->data.deviceId = deviceId;
189 work->data = static_cast<void*>(&item);
190 int32_t ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, EmitRemoveDeviceEvent);
191 if (ret != 0) {
192 MMI_HILOGE("uv_queue_work failed");
193 JsUtil::DeletePtr<uv_work_t*>(work);
194 return;
195 }
196 }
197 }
198
CallIdsAsyncWork(uv_work_t * work,int32_t status)199 void JsEventTarget::CallIdsAsyncWork(uv_work_t *work, int32_t status)
200 {
201 CALL_DEBUG_ENTER;
202 CHKPV(work);
203 if (work->data == nullptr) {
204 JsUtil::DeletePtr<uv_work_t*>(work);
205 MMI_HILOGE("Check data is null");
206 return;
207 }
208 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
209 CHKPV(cb);
210 CHKPV(cb->env);
211
212 napi_handle_scope scope = nullptr;
213 napi_open_handle_scope(cb->env, &scope);
214 if (scope == nullptr) {
215 MMI_HILOGE("scope is nullptr");
216 return;
217 }
218 napi_value arr[2];
219 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &arr[0]), GET_UNDEFINED, scope);
220 CHKRV_SCOPE(cb->env, napi_create_array(cb->env, &arr[1]), CREATE_ARRAY, scope);
221 uint32_t index = 0;
222 napi_value value = nullptr;
223 for (const auto &item : cb->data.ids) {
224 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, item, &value), CREATE_INT32, scope);
225 CHKRV_SCOPE(cb->env, napi_set_element(cb->env, arr[1], index, value), SET_ELEMENT, scope);
226 ++index;
227 }
228
229 napi_value handler = nullptr;
230 CHKRV_SCOPE(cb->env, napi_get_reference_value(cb->env, cb->ref, &handler), GET_REFERENCE, scope);
231 napi_value result = nullptr;
232 CHKRV_SCOPE(cb->env, napi_call_function(cb->env, nullptr, handler, 2, arr, &result), CALL_FUNCTION, scope);
233 napi_close_handle_scope(cb->env, scope);
234 JsUtil::DeleteCallbackInfo(std::move(cb));
235 }
236
CallIdsPromiseWork(uv_work_t * work,int32_t status)237 void JsEventTarget::CallIdsPromiseWork(uv_work_t *work, int32_t status)
238 {
239 CALL_DEBUG_ENTER;
240 CHKPV(work);
241 if (work->data == nullptr) {
242 JsUtil::DeletePtr<uv_work_t*>(work);
243 MMI_HILOGE("Check data is null");
244 return;
245 }
246 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
247 CHKPV(cb);
248 CHKPV(cb->env);
249
250 napi_handle_scope scope = nullptr;
251 napi_open_handle_scope(cb->env, &scope);
252 if (scope == nullptr) {
253 MMI_HILOGE("scope is nullptr");
254 return;
255 }
256 napi_value arr = nullptr;
257 CHKRV_SCOPE(cb->env, napi_create_array(cb->env, &arr), CREATE_ARRAY, scope);
258 uint32_t index = 0;
259 napi_value value = nullptr;
260 for (const auto &item : cb->data.ids) {
261 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, item, &value), CREATE_INT32, scope);
262 CHKRV_SCOPE(cb->env, napi_set_element(cb->env, arr, index, value), SET_ELEMENT, scope);
263 ++index;
264 }
265 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, arr), RESOLVE_DEFERRED, scope);
266 napi_close_handle_scope(cb->env, scope);
267 JsUtil::DeleteCallbackInfo(std::move(cb));
268 }
269
EmitJsIds(int32_t userData,std::vector<int32_t> & ids)270 void JsEventTarget::EmitJsIds(int32_t userData, std::vector<int32_t> &ids)
271 {
272 CALL_DEBUG_ENTER;
273 std::lock_guard<std::mutex> guard(mutex_);
274 auto iter = callback_.find(userData);
275 if (iter == callback_.end()) {
276 MMI_HILOGE("Failed to search for userData");
277 return;
278 }
279 CHKPV(iter->second);
280 if (iter->second->env == nullptr) {
281 callback_.erase(iter);
282 MMI_HILOGE("The env is nullptr");
283 return;
284 }
285
286 iter->second->data.ids = ids;
287 iter->second->errCode = RET_OK;
288 uv_loop_s *loop = nullptr;
289 CHKRV(iter->second->env, napi_get_uv_event_loop(iter->second->env, &loop), GET_UV_LOOP);
290 uv_work_t *work = new (std::nothrow) uv_work_t;
291 CHKPV(work);
292 int32_t *uData = new (std::nothrow) int32_t(userData);
293 if ((uData) == nullptr) {
294 JsUtil::DeletePtr<uv_work_t*>(work);
295 MMI_HILOGE("Check uData is null");
296 return;
297 }
298 work->data = static_cast<void*>(uData);
299 int32_t ret;
300 if (iter->second->isApi9) {
301 if (iter->second->ref == nullptr) {
302 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallDevListPromiseWork);
303 } else {
304 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallDevListAsyncWork);
305 }
306 } else {
307 if (iter->second->ref == nullptr) {
308 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallIdsPromiseWork);
309 } else {
310 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallIdsAsyncWork);
311 }
312 }
313 if (ret != 0) {
314 MMI_HILOGE("uv_queue_work failed");
315 JsUtil::DeletePtr<uv_work_t*>(work);
316 JsUtil::DeletePtr<int32_t*>(uData);
317 }
318 }
319
CallDevAsyncWork(uv_work_t * work,int32_t status)320 void JsEventTarget::CallDevAsyncWork(uv_work_t *work, int32_t status)
321 {
322 CALL_DEBUG_ENTER;
323 CHKPV(work);
324 if (work->data == nullptr) {
325 JsUtil::DeletePtr<uv_work_t*>(work);
326 MMI_HILOGE("Check data is null");
327 return;
328 }
329 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
330 CHKPV(cb);
331 CHKPV(cb->env);
332 napi_handle_scope scope = nullptr;
333 napi_open_handle_scope(cb->env, &scope);
334 if (scope == nullptr) {
335 MMI_HILOGE("scope is nullptr");
336 return;
337 }
338 napi_value object[2];
339 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &object[0]), GET_UNDEFINED, scope);
340 object[1] = JsUtil::GetDeviceInfo(cb);
341 napi_value handler = nullptr;
342 CHKRV_SCOPE(cb->env, napi_get_reference_value(cb->env, cb->ref, &handler), GET_REFERENCE, scope);
343 napi_value result = nullptr;
344 CHKRV_SCOPE(cb->env, napi_call_function(cb->env, nullptr, handler, 2, object, &result), CALL_FUNCTION,
345 scope);
346 napi_close_handle_scope(cb->env, scope);
347 JsUtil::DeleteCallbackInfo(std::move(cb));
348 }
349
CallDevPromiseWork(uv_work_t * work,int32_t status)350 void JsEventTarget::CallDevPromiseWork(uv_work_t *work, int32_t status)
351 {
352 CALL_DEBUG_ENTER;
353 CHKPV(work);
354 if (work->data == nullptr) {
355 JsUtil::DeletePtr<uv_work_t*>(work);
356 MMI_HILOGE("Check data is null");
357 return;
358 }
359 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
360 CHKPV(cb);
361 CHKPV(cb->env);
362 napi_handle_scope scope = nullptr;
363 napi_open_handle_scope(cb->env, &scope);
364 if (scope == nullptr) {
365 MMI_HILOGE("scope is nullptr");
366 return;
367 }
368 napi_value object = JsUtil::GetDeviceInfo(cb);
369 if (object == nullptr) {
370 MMI_HILOGE("Check object is null");
371 napi_close_handle_scope(cb->env, scope);
372 return;
373 }
374 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, object), RESOLVE_DEFERRED, scope);
375 napi_close_handle_scope(cb->env, scope);
376 JsUtil::DeleteCallbackInfo(std::move(cb));
377 }
378
EmitJsDev(int32_t userData,std::shared_ptr<InputDevice> device)379 void JsEventTarget::EmitJsDev(int32_t userData, std::shared_ptr<InputDevice> device)
380 {
381 CALL_DEBUG_ENTER;
382 std::lock_guard<std::mutex> guard(mutex_);
383 CHKPV(device);
384 auto iter = callback_.find(userData);
385 if (iter == callback_.end()) {
386 MMI_HILOGE("Failed to search for userData");
387 return;
388 }
389 CHKPV(iter->second);
390 if (iter->second->env == nullptr) {
391 callback_.erase(iter);
392 MMI_HILOGE("The env is nullptr");
393 return;
394 }
395
396 iter->second->data.device = device;
397 iter->second->errCode = RET_OK;
398 uv_loop_s *loop = nullptr;
399 CHKRV(iter->second->env, napi_get_uv_event_loop(iter->second->env, &loop), GET_UV_LOOP);
400 uv_work_t *work = new (std::nothrow) uv_work_t;
401 CHKPV(work);
402 int32_t *uData = new (std::nothrow) int32_t(userData);
403 CHKPV(uData);
404 work->data = static_cast<void*>(uData);
405 int32_t ret;
406 if (iter->second->isApi9) {
407 if (iter->second->ref == nullptr) {
408 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallDevInfoPromiseWork);
409 } else {
410 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallDevInfoAsyncWork);
411 }
412 } else {
413 if (iter->second->ref == nullptr) {
414 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallDevPromiseWork);
415 } else {
416 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallDevAsyncWork);
417 }
418 }
419 if (ret != 0) {
420 MMI_HILOGE("uv_queue_work failed");
421 JsUtil::DeletePtr<uv_work_t*>(work);
422 JsUtil::DeletePtr<int32_t*>(uData);
423 return;
424 }
425 }
426
CallKeystrokeAbilityPromise(uv_work_t * work,int32_t status)427 void JsEventTarget::CallKeystrokeAbilityPromise(uv_work_t *work, int32_t status)
428 {
429 CALL_DEBUG_ENTER;
430 CHKPV(work);
431 if (work->data == nullptr) {
432 JsUtil::DeletePtr<uv_work_t*>(work);
433 MMI_HILOGE("Check data is null");
434 return;
435 }
436 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
437 CHKPV(cb);
438 CHKPV(cb->env);
439
440 napi_handle_scope scope = nullptr;
441 napi_open_handle_scope(cb->env, &scope);
442 CHKPV(scope);
443 napi_value callResult = nullptr;
444 if (cb->errCode != RET_OK) {
445 if (cb->errCode == RET_ERR) {
446 napi_close_handle_scope(cb->env, scope);
447 MMI_HILOGE("Other errors");
448 return;
449 }
450 NapiError codeMsg;
451 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
452 napi_close_handle_scope(cb->env, scope);
453 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
454 return;
455 }
456 callResult = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
457 CHKRV_SCOPE(cb->env, napi_reject_deferred(cb->env, cb->deferred, callResult), REJECT_DEFERRED, scope);
458 } else {
459 CHKRV_SCOPE(cb->env, napi_create_array(cb->env, &callResult), CREATE_ARRAY, scope);
460 for (size_t i = 0; i < cb->data.keystrokeAbility.size(); ++i) {
461 napi_value ret = nullptr;
462 napi_value isSupport = nullptr;
463 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, cb->data.keystrokeAbility[i] ? 1 : 0, &ret),
464 CREATE_INT32, scope);
465 CHKRV_SCOPE(cb->env, napi_coerce_to_bool(cb->env, ret, &isSupport), COERCE_TO_BOOL, scope);
466 CHKRV_SCOPE(cb->env, napi_set_element(cb->env, callResult, static_cast<uint32_t>(i), isSupport),
467 SET_ELEMENT, scope);
468 }
469 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, callResult), RESOLVE_DEFERRED, scope);
470 }
471 napi_close_handle_scope(cb->env, scope);
472 JsUtil::DeleteCallbackInfo(std::move(cb));
473 }
474
CallKeystrokeAbilityAsync(uv_work_t * work,int32_t status)475 void JsEventTarget::CallKeystrokeAbilityAsync(uv_work_t *work, int32_t status)
476 {
477 CALL_DEBUG_ENTER;
478 CHKPV(work);
479 if (work->data == nullptr) {
480 JsUtil::DeletePtr<uv_work_t*>(work);
481 MMI_HILOGE("Check data is null");
482 return;
483 }
484 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
485 CHKPV(cb);
486 CHKPV(cb->env);
487
488 napi_handle_scope scope = nullptr;
489 napi_open_handle_scope(cb->env, &scope);
490 CHKPV(scope);
491 napi_value callResult[2] = { 0 };
492 if (cb->errCode != RET_OK) {
493 if (cb->errCode == RET_ERR) {
494 napi_close_handle_scope(cb->env, scope);
495 MMI_HILOGE("Other errors");
496 return;
497 }
498 NapiError codeMsg;
499 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
500 napi_close_handle_scope(cb->env, scope);
501 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
502 return;
503 }
504 callResult[0] = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
505 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[1]), GET_UNDEFINED, scope);
506 } else {
507 CHKRV_SCOPE(cb->env, napi_create_array(cb->env, &callResult[1]), CREATE_ARRAY, scope);
508 for (size_t i = 0; i < cb->data.keystrokeAbility.size(); ++i) {
509 napi_value ret = nullptr;
510 napi_value isSupport = nullptr;
511 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, cb->data.keystrokeAbility[i] ? 1 : 0, &ret),
512 CREATE_INT32, scope);
513 CHKRV_SCOPE(cb->env, napi_coerce_to_bool(cb->env, ret, &isSupport), COERCE_TO_BOOL, scope);
514 CHKRV_SCOPE(cb->env, napi_set_element(cb->env, callResult[1], static_cast<uint32_t>(i), isSupport),
515 SET_ELEMENT, scope);
516 }
517 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[0]), GET_UNDEFINED, scope);
518 }
519 napi_value handler = nullptr;
520 CHKRV_SCOPE(cb->env, napi_get_reference_value(cb->env, cb->ref, &handler),
521 GET_REFERENCE, scope);
522 napi_value result = nullptr;
523 CHKRV_SCOPE(cb->env, napi_call_function(cb->env, nullptr, handler, 2, callResult, &result),
524 CALL_FUNCTION, scope);
525 napi_close_handle_scope(cb->env, scope);
526 JsUtil::DeleteCallbackInfo(std::move(cb));
527 }
528
EmitSupportKeys(int32_t userData,std::vector<bool> & keystrokeAbility)529 void JsEventTarget::EmitSupportKeys(int32_t userData, std::vector<bool> &keystrokeAbility)
530 {
531 CALL_DEBUG_ENTER;
532 std::lock_guard<std::mutex> guard(mutex_);
533 auto iter = callback_.find(userData);
534 if (iter == callback_.end()) {
535 MMI_HILOGE("Failed to search for userData");
536 return;
537 }
538 CHKPV(iter->second);
539 if (iter->second->env == nullptr) {
540 callback_.erase(iter);
541 MMI_HILOGE("The env is nullptr");
542 return;
543 }
544
545 iter->second->data.keystrokeAbility = keystrokeAbility;
546 iter->second->errCode = RET_OK;
547 uv_loop_s *loop = nullptr;
548 CHKRV(iter->second->env, napi_get_uv_event_loop(iter->second->env, &loop), GET_UV_LOOP);
549 uv_work_t *work = new (std::nothrow) uv_work_t;
550 CHKPV(work);
551 int32_t *uData = new (std::nothrow) int32_t(userData);
552 CHKPV(uData);
553 work->data = static_cast<void*>(uData);
554 int32_t ret;
555 if (iter->second->ref == nullptr) {
556 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallKeystrokeAbilityPromise);
557 } else {
558 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallKeystrokeAbilityAsync);
559 }
560 if (ret != 0) {
561 MMI_HILOGE("uv_queue_work failed");
562 JsUtil::DeletePtr<uv_work_t*>(work);
563 JsUtil::DeletePtr<int32_t*>(uData);
564 return;
565 }
566 }
567
EmitJsKeyboardType(int32_t userData,int32_t keyboardType)568 void JsEventTarget::EmitJsKeyboardType(int32_t userData, int32_t keyboardType)
569 {
570 CALL_DEBUG_ENTER;
571 std::lock_guard<std::mutex> guard(mutex_);
572 auto iter = callback_.find(userData);
573 if (iter == callback_.end()) {
574 MMI_HILOGE("Failed to search for userData");
575 return;
576 }
577 CHKPV(iter->second);
578 if (iter->second->env == nullptr) {
579 callback_.erase(iter);
580 MMI_HILOGE("The env is nullptr");
581 return;
582 }
583 iter->second->data.keyboardType = keyboardType;
584 iter->second->errCode = RET_OK;
585 uv_loop_s *loop = nullptr;
586 CHKRV(iter->second->env, napi_get_uv_event_loop(iter->second->env, &loop), GET_UV_LOOP);
587
588 uv_work_t *work = new (std::nothrow) uv_work_t;
589 CHKPV(work);
590 int32_t *uData = new (std::nothrow) int32_t(userData);
591 CHKPV(uData);
592 work->data = static_cast<void*>(uData);
593 int32_t ret = 0;
594 if (iter->second->ref == nullptr) {
595 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallKeyboardTypePromise);
596 } else {
597 ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, CallKeyboardTypeAsync);
598 }
599 if (ret != 0) {
600 MMI_HILOGE("uv_queue_work failed");
601 JsUtil::DeletePtr<uv_work_t*>(work);
602 JsUtil::DeletePtr<int32_t*>(uData);
603 return;
604 }
605 }
606
CallKeyboardTypeAsync(uv_work_t * work,int32_t status)607 void JsEventTarget::CallKeyboardTypeAsync(uv_work_t *work, int32_t status)
608 {
609 CALL_DEBUG_ENTER;
610 CHKPV(work);
611 if (work->data == nullptr) {
612 JsUtil::DeletePtr<uv_work_t*>(work);
613 MMI_HILOGE("Check data is null");
614 return;
615 }
616 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
617 CHKPV(cb);
618 CHKPV(cb->env);
619
620 napi_handle_scope scope = nullptr;
621 napi_open_handle_scope(cb->env, &scope);
622 CHKPV(scope);
623
624 napi_value callResult[2] = { 0 };
625 if (cb->errCode != RET_OK) {
626 if (cb->errCode == RET_ERR) {
627 napi_close_handle_scope(cb->env, scope);
628 MMI_HILOGE("Other errors");
629 return;
630 }
631 NapiError codeMsg;
632 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
633 napi_close_handle_scope(cb->env, scope);
634 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
635 return;
636 }
637 callResult[0] = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
638 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[1]), GET_UNDEFINED, scope);
639 } else {
640 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, cb->data.keyboardType, &callResult[1]), CREATE_INT32, scope);
641 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[0]), GET_UNDEFINED, scope);
642 }
643 napi_value handler = nullptr;
644 CHKRV_SCOPE(cb->env, napi_get_reference_value(cb->env, cb->ref, &handler), GET_REFERENCE, scope);
645 napi_value result = nullptr;
646 CHKRV_SCOPE(cb->env, napi_call_function(cb->env, nullptr, handler, 2, callResult, &result),
647 CALL_FUNCTION, scope);
648 napi_close_handle_scope(cb->env, scope);
649 JsUtil::DeleteCallbackInfo(std::move(cb));
650 }
651
CallKeyboardTypePromise(uv_work_t * work,int32_t status)652 void JsEventTarget::CallKeyboardTypePromise(uv_work_t *work, int32_t status)
653 {
654 CALL_DEBUG_ENTER;
655 CHKPV(work);
656 if (work->data == nullptr) {
657 JsUtil::DeletePtr<uv_work_t*>(work);
658 MMI_HILOGE("Check data is null");
659 return;
660 }
661 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
662 CHKPV(cb);
663 CHKPV(cb->env);
664
665 napi_handle_scope scope = nullptr;
666 napi_open_handle_scope(cb->env, &scope);
667 CHKPV(scope);
668
669 napi_value callResult;
670 if (cb->errCode != RET_OK) {
671 if (cb->errCode == RET_ERR) {
672 napi_close_handle_scope(cb->env, scope);
673 MMI_HILOGE("Other errors");
674 return;
675 }
676 NapiError codeMsg;
677 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
678 napi_close_handle_scope(cb->env, scope);
679 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
680 return;
681 }
682 callResult = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
683 CHKRV_SCOPE(cb->env, napi_reject_deferred(cb->env, cb->deferred, callResult), REJECT_DEFERRED, scope);
684 } else {
685 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, cb->data.keyboardType, &callResult), CREATE_INT32, scope);
686 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, callResult), RESOLVE_DEFERRED, scope);
687 }
688 napi_close_handle_scope(cb->env, scope);
689 JsUtil::DeleteCallbackInfo(std::move(cb));
690 }
691
CallDevListAsyncWork(uv_work_t * work,int32_t status)692 void JsEventTarget::CallDevListAsyncWork(uv_work_t *work, int32_t status)
693 {
694 CALL_DEBUG_ENTER;
695 CHKPV(work);
696 if (work->data == nullptr) {
697 JsUtil::DeletePtr<uv_work_t*>(work);
698 MMI_HILOGE("Check data is null");
699 return;
700 }
701 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
702 CHKPV(cb);
703 CHKPV(cb->env);
704 napi_handle_scope scope = nullptr;
705 napi_open_handle_scope(cb->env, &scope);
706 CHKPV(scope);
707
708 napi_value callResult[2] = { 0 };
709 if (cb->errCode != RET_OK) {
710 if (cb->errCode == RET_ERR) {
711 napi_close_handle_scope(cb->env, scope);
712 MMI_HILOGE("Other errors");
713 return;
714 }
715 NapiError codeMsg;
716 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
717 napi_close_handle_scope(cb->env, scope);
718 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
719 return;
720 }
721 callResult[0] = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
722 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[1]), GET_UNDEFINED, scope);
723 } else {
724 CHKRV_SCOPE(cb->env, napi_create_array(cb->env, &callResult[1]), CREATE_ARRAY, scope);
725 uint32_t index = 0;
726 napi_value value = nullptr;
727 for (const auto &item : cb->data.ids) {
728 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, item, &value), CREATE_INT32, scope);
729 CHKRV_SCOPE(cb->env, napi_set_element(cb->env, callResult[1], index, value), SET_ELEMENT, scope);
730 ++index;
731 }
732 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[0]), GET_UNDEFINED, scope);
733 }
734 napi_value handler = nullptr;
735 CHKRV_SCOPE(cb->env, napi_get_reference_value(cb->env, cb->ref, &handler), GET_REFERENCE, scope);
736 napi_value result = nullptr;
737 CHKRV_SCOPE(cb->env, napi_call_function(cb->env, nullptr, handler, 2, callResult, &result),
738 CALL_FUNCTION, scope);
739 napi_close_handle_scope(cb->env, scope);
740 JsUtil::DeleteCallbackInfo(std::move(cb));
741 }
742
CallDevListPromiseWork(uv_work_t * work,int32_t status)743 void JsEventTarget::CallDevListPromiseWork(uv_work_t *work, int32_t status)
744 {
745 CALL_DEBUG_ENTER;
746 CHKPV(work);
747 if (work->data == nullptr) {
748 JsUtil::DeletePtr<uv_work_t*>(work);
749 MMI_HILOGE("Check data is null");
750 return;
751 }
752 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
753 CHKPV(cb);
754 CHKPV(cb->env);
755 napi_handle_scope scope = nullptr;
756 napi_open_handle_scope(cb->env, &scope);
757 CHKPV(scope);
758 napi_value callResult = nullptr;
759 if (cb->errCode != RET_OK) {
760 if (cb->errCode == RET_ERR) {
761 napi_close_handle_scope(cb->env, scope);
762 MMI_HILOGE("Other errors");
763 return;
764 }
765 NapiError codeMsg;
766 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
767 napi_close_handle_scope(cb->env, scope);
768 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
769 return;
770 }
771 callResult = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
772 CHKRV_SCOPE(cb->env, napi_reject_deferred(cb->env, cb->deferred, callResult), REJECT_DEFERRED, scope);
773 } else {
774 CHKRV_SCOPE(cb->env, napi_create_array(cb->env, &callResult), CREATE_ARRAY, scope);
775 uint32_t index = 0;
776 napi_value value = nullptr;
777 for (const auto &item : cb->data.ids) {
778 CHKRV_SCOPE(cb->env, napi_create_int32(cb->env, item, &value), CREATE_INT32, scope);
779 CHKRV_SCOPE(cb->env, napi_set_element(cb->env, callResult, index, value), SET_ELEMENT, scope);
780 ++index;
781 }
782 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, callResult), RESOLVE_DEFERRED, scope);
783 }
784 napi_close_handle_scope(cb->env, scope);
785 JsUtil::DeleteCallbackInfo(std::move(cb));
786 }
787
CallDevInfoPromiseWork(uv_work_t * work,int32_t status)788 void JsEventTarget::CallDevInfoPromiseWork(uv_work_t *work, int32_t status)
789 {
790 CALL_DEBUG_ENTER;
791 CHKPV(work);
792 if (work->data == nullptr) {
793 JsUtil::DeletePtr<uv_work_t*>(work);
794 MMI_HILOGE("Check data is null");
795 return;
796 }
797 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
798 CHKPV(cb);
799 CHKPV(cb->env);
800 napi_handle_scope scope = nullptr;
801 napi_open_handle_scope(cb->env, &scope);
802 CHKPV(scope);
803 napi_value callResult = nullptr;
804 if (cb->errCode != RET_OK) {
805 if (cb->errCode == RET_ERR) {
806 napi_close_handle_scope(cb->env, scope);
807 MMI_HILOGE("Other errors");
808 return;
809 }
810 NapiError codeMsg;
811 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
812 napi_close_handle_scope(cb->env, scope);
813 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
814 return;
815 }
816 callResult = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
817 CHKRV_SCOPE(cb->env, napi_reject_deferred(cb->env, cb->deferred, callResult), REJECT_DEFERRED, scope);
818 } else {
819 callResult = JsUtil::GetDeviceInfo(cb);
820 if (callResult == nullptr) {
821 MMI_HILOGE("Check callResult is null");
822 napi_close_handle_scope(cb->env, scope);
823 return;
824 }
825 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, callResult), RESOLVE_DEFERRED, scope);
826 }
827 napi_close_handle_scope(cb->env, scope);
828 JsUtil::DeleteCallbackInfo(std::move(cb));
829 }
830
CallDevInfoAsyncWork(uv_work_t * work,int32_t status)831 void JsEventTarget::CallDevInfoAsyncWork(uv_work_t *work, int32_t status)
832 {
833 CALL_DEBUG_ENTER;
834 CHKPV(work);
835 if (work->data == nullptr) {
836 JsUtil::DeletePtr<uv_work_t*>(work);
837 MMI_HILOGE("Check data is null");
838 return;
839 }
840 std::unique_ptr<JsUtil::CallbackInfo> cb = GetCallbackInfo(work);
841 CHKPV(cb);
842 CHKPV(cb->env);
843 napi_handle_scope scope = nullptr;
844 napi_open_handle_scope(cb->env, &scope);
845 CHKPV(scope);
846 napi_value callResult[2] = { 0 };
847 if (cb->errCode != RET_OK) {
848 if (cb->errCode == RET_ERR) {
849 napi_close_handle_scope(cb->env, scope);
850 MMI_HILOGE("Other errors");
851 return;
852 }
853 NapiError codeMsg;
854 if (!UtilNapiError::GetApiError(cb->errCode, codeMsg)) {
855 napi_close_handle_scope(cb->env, scope);
856 MMI_HILOGE("Error code %{public}d not found", cb->errCode);
857 return;
858 }
859 callResult[0] = GreateBusinessError(cb->env, cb->errCode, codeMsg.msg);
860 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[1]), GET_UNDEFINED, scope);
861 } else {
862 callResult[1] = JsUtil::GetDeviceInfo(cb);
863 CHKRV_SCOPE(cb->env, napi_get_undefined(cb->env, &callResult[0]), GET_UNDEFINED, scope);
864 }
865 napi_value handler = nullptr;
866 CHKRV_SCOPE(cb->env, napi_get_reference_value(cb->env, cb->ref, &handler), GET_REFERENCE, scope);
867 napi_value result = nullptr;
868 CHKRV_SCOPE(cb->env, napi_call_function(cb->env, nullptr, handler, 2, callResult, &result), CALL_FUNCTION,
869 scope);
870 napi_close_handle_scope(cb->env, scope);
871 JsUtil::DeleteCallbackInfo(std::move(cb));
872 }
873
AddListener(napi_env env,const std::string & type,napi_value handle)874 void JsEventTarget::AddListener(napi_env env, const std::string &type, napi_value handle)
875 {
876 CALL_DEBUG_ENTER;
877 std::lock_guard<std::mutex> guard(mutex_);
878 auto iter = devListener_.find(type);
879 if (iter == devListener_.end()) {
880 MMI_HILOGE("Find %{public}s failed", type.c_str());
881 return;
882 }
883
884 for (const auto &temp : iter->second) {
885 CHKPC(temp);
886 if (temp->env != env) {
887 continue;
888 }
889 if (JsUtil::IsSameHandle(env, handle, temp->ref)) {
890 MMI_HILOGW("The handle already exists");
891 return;
892 }
893 }
894 napi_ref ref = nullptr;
895 CHKRV(env, napi_create_reference(env, handle, 1, &ref), CREATE_REFERENCE);
896 auto monitor = std::make_unique<JsUtil::CallbackInfo>();
897 monitor->env = env;
898 monitor->ref = ref;
899 iter->second.push_back(std::move(monitor));
900 if (!isListeningProcess_) {
901 isListeningProcess_ = true;
902 InputMgr->RegisterDevListener("change", shared_from_this());
903 }
904 }
905
RemoveListener(napi_env env,const std::string & type,napi_value handle)906 void JsEventTarget::RemoveListener(napi_env env, const std::string &type, napi_value handle)
907 {
908 CALL_DEBUG_ENTER;
909 std::lock_guard<std::mutex> guard(mutex_);
910 auto iter = devListener_.find(type);
911 if (iter == devListener_.end()) {
912 MMI_HILOGE("Find %{public}s failed", type.c_str());
913 return;
914 }
915 if (handle == nullptr) {
916 iter->second.clear();
917 goto monitorLabel;
918 }
919 for (auto it = iter->second.begin(); it != iter->second.end(); ++it) {
920 if ((*it)->env != env) {
921 continue;
922 }
923 if (JsUtil::IsSameHandle(env, handle, (*it)->ref)) {
924 MMI_HILOGD("Succeeded in removing monitor");
925 JsUtil::DeleteCallbackInfo(std::move(*it));
926 iter->second.erase(it);
927 goto monitorLabel;
928 }
929 }
930
931 monitorLabel:
932 if (isListeningProcess_ && iter->second.empty()) {
933 isListeningProcess_ = false;
934 InputMgr->UnregisterDevListener("change", shared_from_this());
935 }
936 }
937
CreateCallbackInfo(napi_env env,napi_value handle,const int32_t userData,bool isApi9)938 napi_value JsEventTarget::CreateCallbackInfo(napi_env env, napi_value handle, const int32_t userData, bool isApi9)
939 {
940 CALL_DEBUG_ENTER;
941 std::lock_guard<std::mutex> guard(mutex_);
942 auto cb = std::make_unique<JsUtil::CallbackInfo>();
943 cb->env = env;
944 cb->isApi9 = isApi9;
945 napi_value promise = nullptr;
946 if (handle == nullptr) {
947 CHKRP(env, napi_create_promise(env, &cb->deferred, &promise), CREATE_PROMISE);
948 } else {
949 CHKRP(env, napi_create_reference(env, handle, 1, &cb->ref), CREATE_REFERENCE);
950 }
951 callback_.emplace(userData, std::move(cb));
952 return promise;
953 }
954
GreateBusinessError(napi_env env,int32_t errCode,std::string errMessage)955 napi_value JsEventTarget::GreateBusinessError(napi_env env, int32_t errCode, std::string errMessage)
956 {
957 CALL_DEBUG_ENTER;
958 napi_value result = nullptr;
959 napi_value resultCode = nullptr;
960 napi_value resultMessage = nullptr;
961 CHKRP(env, napi_create_int32(env, errCode, &resultCode), CREATE_INT32);
962 CHKRP(env, napi_create_string_utf8(env, errMessage.data(), NAPI_AUTO_LENGTH, &resultMessage), CREATE_STRING_UTF8);
963 CHKRP(env, napi_create_error(env, nullptr, resultMessage, &result), CREATE_ERROR);
964 CHKRP(env, napi_set_named_property(env, result, ERR_CODE.c_str(), resultCode), SET_NAMED_PROPERTY);
965 return result;
966 }
967
GetCallbackInfo(uv_work_t * work)968 std::unique_ptr<JsUtil::CallbackInfo> JsEventTarget::GetCallbackInfo(uv_work_t *work)
969 {
970 std::lock_guard<std::mutex> guard(mutex_);
971 int32_t *uData = static_cast<int32_t*>(work->data);
972 int32_t userData = *uData;
973 JsUtil::DeletePtr<uv_work_t*>(work);
974 JsUtil::DeletePtr<int32_t*>(uData);
975
976 auto iter = callback_.find(userData);
977 if (iter == callback_.end()) {
978 MMI_HILOGE("Find userData failed");
979 return nullptr;
980 }
981 auto cb = std::move(iter->second);
982 callback_.erase(iter);
983 return cb;
984 }
985
RemoveCallbackInfo(napi_env env,napi_value handle,int32_t userData)986 void JsEventTarget::RemoveCallbackInfo(napi_env env, napi_value handle, int32_t userData)
987 {
988 CALL_DEBUG_ENTER;
989 std::lock_guard<std::mutex> guard(mutex_);
990 auto iter = callback_.find(userData);
991 if (iter != callback_.end()) {
992 auto cb = std::move(iter->second);
993 JsUtil::DeleteCallbackInfo(std::move(cb));
994 callback_.erase(iter);
995 }
996 }
997
ResetEnv()998 void JsEventTarget::ResetEnv()
999 {
1000 CALL_DEBUG_ENTER;
1001 std::lock_guard<std::mutex> guard(mutex_);
1002 callback_.clear();
1003 devListener_.clear();
1004 InputMgr->UnregisterDevListener("change", shared_from_this());
1005 }
1006 } // namespace MMI
1007 } // namespace OHOS