1 /*
2 * Copyright (c) 2021-2024 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_register_util.h"
17
18 #include "input_manager.h"
19 #include "napi_constants.h"
20 #include "util_napi_error.h"
21
22 #undef MMI_LOG_TAG
23 #define MMI_LOG_TAG "JSRegisterUtil"
24
25 namespace OHOS {
26 namespace MMI {
27
TypeOf(napi_env env,napi_value value,napi_valuetype type)28 bool TypeOf(napi_env env, napi_value value, napi_valuetype type)
29 {
30 napi_valuetype valueType = napi_undefined;
31 CHKRF(napi_typeof(env, value, &valueType), TYPEOF);
32 if (valueType != type) {
33 return false;
34 }
35 return true;
36 }
37
SetNamedProperty(const napi_env & env,napi_value & object,const std::string & name,int32_t value)38 void SetNamedProperty(const napi_env &env, napi_value &object, const std::string &name, int32_t value)
39 {
40 MMI_HILOGD("%{public}s=%{public}d", name.c_str(), value);
41 napi_value napiValue;
42 CHKRV(napi_create_int32(env, value, &napiValue), CREATE_INT32);
43 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), napiValue));
44 }
45
SetNamedProperty(const napi_env & env,napi_value & object,const std::string & name,uint32_t value)46 void SetNamedProperty(const napi_env &env, napi_value &object, const std::string &name, uint32_t value)
47 {
48 napi_value napiValue;
49 CHKRV(napi_create_uint32(env, value, &napiValue), CREATE_UINT32);
50 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), napiValue));
51 }
52
SetNamedProperty(const napi_env & env,napi_value & object,const std::string & name,int64_t value)53 void SetNamedProperty(const napi_env &env, napi_value &object, const std::string &name, int64_t value)
54 {
55 napi_value napiValue;
56 CHKRV(napi_create_int64(env, value, &napiValue), CREATE_INT64);
57 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), napiValue));
58 }
59
SetNamedProperty(const napi_env & env,napi_value & object,const std::string & name,std::string value)60 void SetNamedProperty(const napi_env &env, napi_value &object, const std::string &name, std::string value)
61 {
62 MMI_HILOGD("%{public}s=%{public}s", name.c_str(), value.c_str());
63 napi_value napiValue;
64 CHKRV(napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &napiValue), CREATE_STRING_UTF8);
65 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), napiValue));
66 }
67
GetNamedPropertyBool(const napi_env & env,const napi_value & object,const std::string & name,bool & ret)68 bool GetNamedPropertyBool(const napi_env &env, const napi_value &object, const std::string &name, bool &ret)
69 {
70 napi_value napiValue = {};
71 bool exist = false;
72 napi_status status = napi_has_named_property(env, object, name.c_str(), &exist);
73 if (status != napi_ok || !exist) {
74 MMI_HILOGD("Can not find %{public}s property", name.c_str());
75 return false;
76 }
77 napi_get_named_property(env, object, name.c_str(), &napiValue);
78 napi_valuetype tmpType = napi_undefined;
79
80 CHKRF(napi_typeof(env, napiValue, &tmpType), TYPEOF);
81 if (tmpType != napi_boolean) {
82 MMI_HILOGE("The value is not bool");
83 THROWERR_API9(env, COMMON_PARAMETER_ERROR, name.c_str(), "bool");
84 return false;
85 }
86 CHKRF(napi_get_value_bool(env, napiValue, &ret), GET_VALUE_BOOL);
87 MMI_HILOGD("%{public}s=%{public}d", name.c_str(), ret);
88 return true;
89 }
90
GetNamedPropertyInt32(const napi_env & env,const napi_value & object,const std::string & name)91 std::optional<int32_t> GetNamedPropertyInt32(const napi_env &env, const napi_value &object, const std::string &name)
92 {
93 napi_value napiValue = {};
94 bool exist = false;
95 napi_status status = napi_has_named_property(env, object, name.c_str(), &exist);
96 if (status != napi_ok || !exist) {
97 MMI_HILOGD("Can not find %{public}s property", name.c_str());
98 return std::nullopt;
99 }
100 napi_get_named_property(env, object, name.c_str(), &napiValue);
101 napi_valuetype tmpType = napi_undefined;
102 if (napi_typeof(env, napiValue, &tmpType) != napi_ok) {
103 MMI_HILOGE("Call napi_typeof failed");
104 return std::nullopt;
105 }
106 if (tmpType != napi_number) {
107 MMI_HILOGE("The value is not number");
108 THROWERR_API9(env, COMMON_PARAMETER_ERROR, name.c_str(), "number");
109 return std::nullopt;
110 }
111 int32_t ret = 0;
112 if (napi_get_value_int32(env, napiValue, &ret) != napi_ok) {
113 MMI_HILOGE("Call napi_get_value_int32 failed");
114 return std::nullopt;
115 }
116 MMI_HILOGD("%{public}s=%{public}d", name.c_str(), ret);
117 return std::make_optional(ret);
118 }
119
GetPreKeys(const napi_env & env,const napi_value & value,std::set<int32_t> & params)120 napi_value GetPreKeys(const napi_env &env, const napi_value &value, std::set<int32_t> ¶ms)
121 {
122 CALL_DEBUG_ENTER;
123 uint32_t arrayLength = 0;
124 CHKRP(napi_get_array_length(env, value, &arrayLength), GET_ARRAY_LENGTH);
125 for (uint32_t i = 0; i < arrayLength; i++) {
126 napi_value napiElement;
127 CHKRP(napi_get_element(env, value, i, &napiElement), GET_ELEMENT);
128 napi_valuetype valuetype;
129 CHKRP(napi_typeof(env, napiElement, &valuetype), TYPEOF);
130 if (valuetype != napi_number) {
131 MMI_HILOGE("PreKeys Wrong argument type, Number expected");
132 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "element of preKeys must be number");
133 return nullptr;
134 }
135 int32_t value = 0;
136 CHKRP(napi_get_value_int32(env, napiElement, &value), GET_VALUE_INT32);
137 if (value < 0) {
138 MMI_HILOGE("preKey:%{public}d is less 0, can not process", value);
139 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "element of preKeys must be greater than or equal to 0");
140 return nullptr;
141 }
142 MMI_HILOGD("Get int array number:%{public}d", value);
143 if (!params.insert(value).second) {
144 MMI_HILOGE("Params insert value failed");
145 return nullptr;
146 }
147 }
148 napi_value ret;
149 CHKRP(napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
150 return ret;
151 }
152
GetPreSubscribeId(Callbacks & callbacks,sptr<KeyEventMonitorInfo> event)153 int32_t GetPreSubscribeId(Callbacks &callbacks, sptr<KeyEventMonitorInfo> event)
154 {
155 CHKPR(event, ERROR_NULL_POINTER);
156 std::lock_guard guard(sCallBacksMutex);
157 auto it = callbacks.find(event->eventType);
158 if (it == callbacks.end() || it->second.empty()) {
159 MMI_HILOGE("The callbacks is empty");
160 return JS_CALLBACK_EVENT_FAILED;
161 }
162 CHKPR(it->second.front(), ERROR_NULL_POINTER);
163 return it->second.front()->subscribeId;
164 }
165
DelEventCallbackRef(const napi_env & env,std::list<sptr<KeyEventMonitorInfo>> & info,napi_value handler,int32_t & subscribeId)166 int32_t DelEventCallbackRef(const napi_env &env, std::list<sptr<KeyEventMonitorInfo>> &info,
167 napi_value handler, int32_t &subscribeId)
168 {
169 CALL_DEBUG_ENTER;
170 for (auto iter = info.begin(); iter != info.end();) {
171 if (*iter == nullptr) {
172 info.erase(iter++);
173 continue;
174 }
175 if (env != (*iter)->env) {
176 MMI_HILOGW("env mismatching");
177 continue;
178 }
179 if (handler != nullptr) {
180 napi_value iterHandler = nullptr;
181 CHKRR(napi_get_reference_value(env, (*iter)->callback, &iterHandler),
182 GET_REFERENCE_VALUE, JS_CALLBACK_EVENT_FAILED);
183 bool isEquals = false;
184 CHKRR(napi_strict_equals(env, handler, iterHandler, &isEquals), STRICT_EQUALS, JS_CALLBACK_EVENT_FAILED);
185 if (isEquals) {
186 sptr<KeyEventMonitorInfo> monitorInfo = *iter;
187 info.erase(iter++);
188 if (info.empty()) {
189 subscribeId = monitorInfo->subscribeId;
190 }
191 MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
192 return JS_CALLBACK_EVENT_SUCCESS;
193 }
194 ++iter;
195 continue;
196 }
197 sptr<KeyEventMonitorInfo> monitorInfo = *iter;
198 info.erase(iter++);
199 if (info.empty()) {
200 subscribeId = monitorInfo->subscribeId;
201 }
202 MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
203 }
204 MMI_HILOGD("Callback size:%{public}zu", info.size());
205 return JS_CALLBACK_EVENT_SUCCESS;
206 }
207
AddEventCallback(const napi_env & env,Callbacks & callbacks,sptr<KeyEventMonitorInfo> event)208 int32_t AddEventCallback(const napi_env &env, Callbacks &callbacks, sptr<KeyEventMonitorInfo> event)
209 {
210 CALL_DEBUG_ENTER;
211 std::lock_guard guard(sCallBacksMutex);
212 CHKPR(event, ERROR_NULL_POINTER);
213 if (callbacks.find(event->eventType) == callbacks.end()) {
214 MMI_HILOGD("No callback in %{public}s", event->eventType.c_str());
215 callbacks[event->eventType] = {};
216 }
217 napi_value handler1 = nullptr;
218 napi_status status = napi_get_reference_value(env, event->callback, &handler1);
219 if (status != napi_ok) {
220 MMI_HILOGE("Handler1 get reference value failed");
221 return JS_CALLBACK_EVENT_FAILED;
222 }
223 auto it = callbacks.find(event->eventType);
224 for (const auto &iter: it->second) {
225 napi_value handler2 = nullptr;
226 if (iter->env != env) {
227 MMI_HILOGW("env mismatching");
228 continue;
229 }
230 status = napi_get_reference_value(env, iter->callback, &handler2);
231 if (status != napi_ok) {
232 MMI_HILOGE("Handler2 get reference value failed");
233 return JS_CALLBACK_EVENT_FAILED;
234 }
235 bool isEqual = false;
236 status = napi_strict_equals(env, handler1, handler2, &isEqual);
237 if (status != napi_ok) {
238 MMI_HILOGE("Compare two handler failed");
239 return JS_CALLBACK_EVENT_FAILED;
240 }
241 if (isEqual) {
242 MMI_HILOGE("Callback already exist");
243 return JS_CALLBACK_EVENT_FAILED;
244 }
245 }
246 it->second.push_back(event);
247 return JS_CALLBACK_EVENT_SUCCESS;
248 }
249
DelEventCallback(const napi_env & env,Callbacks & callbacks,sptr<KeyEventMonitorInfo> event,int32_t & subscribeId)250 int32_t DelEventCallback(const napi_env &env, Callbacks &callbacks, sptr<KeyEventMonitorInfo> event,
251 int32_t &subscribeId)
252 {
253 CALL_DEBUG_ENTER;
254 std::lock_guard guard(sCallBacksMutex);
255 CHKPR(event, ERROR_NULL_POINTER);
256 if (callbacks.count(event->eventType) <= 0) {
257 MMI_HILOGE("Callback doesn't exists");
258 return JS_CALLBACK_EVENT_FAILED;
259 }
260 auto &info = callbacks[event->eventType];
261 MMI_HILOGD("EventType:%{private}s, keyEventMonitorInfos:%{public}zu", event->eventType.c_str(), info.size());
262 napi_value eventHandler = nullptr;
263 if (event->callback != nullptr) {
264 CHKRR(napi_get_reference_value(env, event->callback, &eventHandler), GET_REFERENCE_VALUE,
265 JS_CALLBACK_EVENT_FAILED);
266 }
267 return DelEventCallbackRef(env, info, eventHandler, subscribeId);
268 }
269
AsyncWorkFn(const napi_env & env,std::shared_ptr<KeyOption> keyOption,napi_value & result,std::string keyType)270 static void AsyncWorkFn(const napi_env &env, std::shared_ptr<KeyOption> keyOption, napi_value &result,
271 std::string keyType)
272 {
273 CHKPV(keyOption);
274 MMI_HILOGD("Status > 0 enter");
275 CHKRV(napi_create_object(env, &result), CREATE_OBJECT);
276 napi_value arr;
277 CHKRV(napi_create_array(env, &arr), CREATE_ARRAY);
278 std::set <int32_t> preKeys = keyOption->GetPreKeys();
279 int32_t i = 0;
280 napi_value value;
281 for (const auto &preKey: preKeys) {
282 CHKRV(napi_create_int32(env, preKey, &value), CREATE_INT32);
283 CHKRV(napi_set_element(env, arr, i, value), SET_ELEMENT);
284 ++i;
285 }
286 std::string preKeysStr = "preKeys";
287 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, preKeysStr.c_str(), arr));
288 MMI::SetNamedProperty(env, result, "finalKey", keyOption->GetFinalKey());
289 if (keyType == SUBSCRIBE_TYPE) {
290 MMI::SetNamedProperty(env, result, "isFinalKeyDown", keyOption->IsFinalKeyDown());
291 MMI::SetNamedProperty(env, result, "finalKeyDownDuration", keyOption->GetFinalKeyDownDuration());
292 }
293 MMI::SetNamedProperty(env, result, "isRepeat", static_cast<int32_t>(keyOption->IsRepeat()));
294 }
295
UvQueueWorkAsyncCallback(sptr<KeyEventMonitorInfo> dataWorker)296 void UvQueueWorkAsyncCallback(sptr<KeyEventMonitorInfo> dataWorker)
297 {
298 CALL_DEBUG_ENTER;
299 CHKPV(dataWorker);
300 std::lock_guard<std::mutex> lock(dataWorker->envMutex_);
301 CHKPV(dataWorker->env);
302 napi_handle_scope scope = nullptr;
303 napi_open_handle_scope(dataWorker->env, &scope);
304 CHKPV(scope);
305 napi_value callback = nullptr;
306 MMI_HILOGD("Deliver uv work from %{public}d", GetPid());
307 if (dataWorker->callback == nullptr) {
308 MMI_HILOGE("dataWorker->callback is nullptr");
309 napi_close_handle_scope(dataWorker->env, scope);
310 return;
311 }
312 if ((napi_get_reference_value(dataWorker->env, dataWorker->callback, &callback)) != napi_ok) {
313 MMI_HILOGE("%{public}s failed", std::string(GET_REFERENCE_VALUE).c_str());
314 napi_close_handle_scope(dataWorker->env, scope);
315 return;
316 }
317 napi_value result = nullptr;
318 AsyncWorkFn(dataWorker->env, dataWorker->keyOption, result, dataWorker->name);
319 napi_value callResult = nullptr;
320 if ((napi_call_function(dataWorker->env, nullptr, callback, 1, &result, &callResult)) != napi_ok) {
321 MMI_HILOGE("%{public}s failed", std::string(CALL_FUNCTION).c_str());
322 napi_close_handle_scope(dataWorker->env, scope);
323 return;
324 }
325 napi_close_handle_scope(dataWorker->env, scope);
326 }
327
EmitAsyncCallbackWork(sptr<KeyEventMonitorInfo> reportEvent)328 void EmitAsyncCallbackWork(sptr<KeyEventMonitorInfo> reportEvent)
329 {
330 CALL_DEBUG_ENTER;
331 CHKPV(reportEvent);
332 std::lock_guard<std::mutex> lock(reportEvent->envMutex_);
333 auto task = [reportEvent] () { UvQueueWorkAsyncCallback(reportEvent); };
334 CHKPV(reportEvent->env);
335 int32_t ret = napi_send_event(reportEvent->env, task, napi_eprio_vip);
336 if (ret != 0) {
337 MMI_HILOGE("napi_send_event failed");
338 return;
339 }
340 }
341
ConvertHotkeyToNapiValue(napi_env env,std::unique_ptr<KeyOption> & keyOption)342 napi_value ConvertHotkeyToNapiValue(napi_env env, std::unique_ptr<KeyOption> &keyOption)
343 {
344 napi_value obj = nullptr;
345 CHKRP(napi_create_object(env, &obj), CREATE_OBJECT);
346 napi_value preKeysArray = nullptr;
347 CHKRP(napi_create_array(env, &preKeysArray), CREATE_ARRAY);
348 int32_t index = 0;
349 std::set<int32_t> preKeys = keyOption->GetPreKeys();
350 for (auto key : preKeys) {
351 napi_value keyVal = nullptr;
352 CHKRP(napi_create_int32(env, key, &keyVal), CREATE_INT32);
353 CHKRP(napi_set_element(env, preKeysArray, index++, keyVal), SET_ELEMENT);
354 }
355 CHKRP(napi_set_named_property(env, obj, "preKeys", preKeysArray), SET_NAMED_PROPERTY);
356 napi_value finalKeyVal = nullptr;
357 CHKRP(napi_create_int32(env, keyOption->GetFinalKey(), &finalKeyVal), CREATE_INT32);
358 CHKRP(napi_set_named_property(env, obj, "finalKey", finalKeyVal), SET_NAMED_PROPERTY);
359 return obj;
360 }
361
ConvertHotkeysToNapiArray(sptr<CallbackInfo> cb)362 napi_value ConvertHotkeysToNapiArray(sptr<CallbackInfo> cb)
363 {
364 napi_value keyOptionArray = nullptr;
365 CHKRP(napi_create_array(cb->env, &keyOptionArray), CREATE_ARRAY);
366 if (cb->errCode != RET_OK) {
367 MMI_HILOGE("Get Hotkeys failed, errCode:%{public}d", cb->errCode);
368 return keyOptionArray;
369 }
370 for (size_t i = 0; i < cb->keyOptions.size(); ++i) {
371 napi_value obj = ConvertHotkeyToNapiValue(cb->env, cb->keyOptions[i]);
372 if (obj == nullptr) {
373 MMI_HILOGE("ConvertHotkeyToNapiValue fail");
374 return keyOptionArray;
375 }
376 CHKRP(napi_set_element(cb->env, keyOptionArray, i, obj), SET_ELEMENT);
377 }
378 return keyOptionArray;
379 }
380
GreateBusinessError(napi_env env,int32_t errCode,std::string errMessage)381 napi_value GreateBusinessError(napi_env env, int32_t errCode, std::string errMessage)
382 {
383 CALL_DEBUG_ENTER;
384 napi_value result = nullptr;
385 napi_value resultCode = nullptr;
386 napi_value resultMessage = nullptr;
387 CHKRP(napi_create_int32(env, errCode, &resultCode), CREATE_INT32);
388 CHKRP(napi_create_string_utf8(env, errMessage.data(), NAPI_AUTO_LENGTH, &resultMessage), CREATE_STRING_UTF8);
389 CHKRP(napi_create_error(env, nullptr, resultMessage, &result), CREATE_ERROR);
390 CHKRP(napi_set_named_property(env, result, ERR_CODE.c_str(), resultCode), SET_NAMED_PROPERTY);
391 return result;
392 }
393
CallHotkeyPromiseWork(uv_work_t * work,int32_t status)394 void CallHotkeyPromiseWork(uv_work_t *work, int32_t status)
395 {
396 CALL_DEBUG_ENTER;
397 CHKPV(work);
398 if (work->data == nullptr) {
399 DeletePtr<uv_work_t *>(work);
400 MMI_HILOGE("Check data is nullptr");
401 return;
402 }
403 sptr<CallbackInfo> cb(static_cast<CallbackInfo *>(work->data));
404 DeletePtr<uv_work_t *>(work);
405 cb->DecStrongRef(nullptr);
406 CHKPV(cb->env);
407 napi_handle_scope scope = nullptr;
408 napi_open_handle_scope(cb->env, &scope);
409 CHKPV(scope);
410 napi_value callResult = ConvertHotkeysToNapiArray(cb);
411 if (callResult == nullptr) {
412 MMI_HILOGE("Check callResult is nullptr");
413 napi_close_handle_scope(cb->env, scope);
414 return;
415 }
416 CHKRV_SCOPE(cb->env, napi_resolve_deferred(cb->env, cb->deferred, callResult), RESOLVE_DEFERRED, scope);
417 napi_close_handle_scope(cb->env, scope);
418 }
419
EmitSystemHotkey(sptr<CallbackInfo> cb)420 void EmitSystemHotkey(sptr<CallbackInfo> cb)
421 {
422 CALL_DEBUG_ENTER;
423 CHKPV(cb);
424 CHKPV(cb->env);
425 uv_loop_s *loop = nullptr;
426 CHKRV(napi_get_uv_event_loop(cb->env, &loop), GET_UV_EVENT_LOOP);
427 uv_work_t *work = new (std::nothrow) uv_work_t;
428 CHKPV(work);
429 cb->IncStrongRef(nullptr);
430 work->data = cb.GetRefPtr();
431 int32_t ret = 0;
432 ret = uv_queue_work_with_qos(
433 loop, work,
434 [](uv_work_t *work) {
435 MMI_HILOGD("uv_queue_work CallHotkeyPromiseWork callback function is called");
436 }, CallHotkeyPromiseWork, uv_qos_user_initiated);
437 if (ret != 0) {
438 MMI_HILOGE("uv_queue_work_with_qos failed");
439 cb->DecStrongRef(nullptr);
440 DeletePtr<uv_work_t *>(work);
441 }
442 }
443
GetSystemHotkey(napi_env env,napi_value handle)444 napi_value GetSystemHotkey(napi_env env, napi_value handle)
445 {
446 CALL_DEBUG_ENTER;
447 sptr<CallbackInfo> cb = new (std::nothrow) CallbackInfo();
448 CHKPP(cb);
449 cb->env = env;
450 napi_value promise = nullptr;
451 CHKRP(napi_create_promise(env, &cb->deferred, &promise), CREATE_PROMISE);
452 std::vector<std::unique_ptr<KeyOption>> keyOptions;
453 int32_t count = 0;
454 cb->errCode = InputManager::GetInstance()->GetAllSystemHotkeys(keyOptions, count);
455 cb->keyOptions = std::move(keyOptions);
456 EmitSystemHotkey(cb);
457 return promise;
458 }
459 } // namespace MMI
460 } // namespace OHOS
461