• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> &params)
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