• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_register_util.h"
17 
18 #include <cinttypes>
19 
20 #include <uv.h>
21 
22 #include "error_multimodal.h"
23 #include "napi_constants.h"
24 #include "util_napi_error.h"
25 #include "util_napi.h"
26 
27 namespace OHOS {
28 namespace MMI {
29 namespace {
30 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, MMI_LOG_DOMAIN, "JSRegisterUtil" };
31 } // namespace
32 
SetNamedProperty(const napi_env & env,napi_value & object,const std::string & name,int32_t value)33 void SetNamedProperty(const napi_env &env, napi_value &object, const std::string &name, int32_t value)
34 {
35     MMI_HILOGD("%{public}s=%{public}d", name.c_str(), value);
36     napi_value napiValue;
37     CHKRV(env, napi_create_int32(env, value, &napiValue), CREATE_INT32);
38     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), napiValue));
39 }
40 
SetNamedProperty(const napi_env & env,napi_value & object,const std::string & name,std::string value)41 void SetNamedProperty(const napi_env &env, napi_value &object, const std::string &name, std::string value)
42 {
43     MMI_HILOGD("%{public}s=%{public}s", name.c_str(), value.c_str());
44     napi_value napiValue;
45     CHKRV(env, napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &napiValue), CREATE_STRING_UTF8);
46     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, object, name.c_str(), napiValue));
47 }
48 
GetNamedPropertyBool(const napi_env & env,const napi_value & object,const std::string & name,bool & ret)49 bool GetNamedPropertyBool(const napi_env &env, const napi_value &object, const std::string &name, bool &ret)
50 {
51     napi_value napiValue = {};
52     napi_get_named_property(env, object, name.c_str(), &napiValue);
53     napi_valuetype tmpType = napi_undefined;
54 
55     CHKRF(env, napi_typeof(env, napiValue, &tmpType), TYPEOF);
56     if (tmpType != napi_boolean) {
57         MMI_HILOGE("The value is not bool");
58         THROWERR_API9(env, COMMON_PARAMETER_ERROR, name.c_str(), "bool");
59         return false;
60     }
61     CHKRF(env, napi_get_value_bool(env, napiValue, &ret), GET_BOOL);
62     MMI_HILOGD("%{public}s=%{public}d", name.c_str(), ret);
63     return true;
64 }
65 
GetNamedPropertyInt32(const napi_env & env,const napi_value & object,const std::string & name)66 std::optional<int32_t> GetNamedPropertyInt32(const napi_env &env, const napi_value &object, const std::string &name)
67 {
68     napi_value napiValue = {};
69     napi_get_named_property(env, object, name.c_str(), &napiValue);
70     napi_valuetype tmpType = napi_undefined;
71     if (napi_typeof(env, napiValue, &tmpType) != napi_ok) {
72         MMI_HILOGE("Call napi_typeof failed");
73         return std::nullopt;
74     }
75     if (tmpType != napi_number) {
76         MMI_HILOGE("The value is not number");
77         THROWERR_API9(env, COMMON_PARAMETER_ERROR, name.c_str(), "number");
78         return std::nullopt;
79     }
80     int32_t ret;
81     if (napi_get_value_int32(env, napiValue, &ret) != napi_ok) {
82         MMI_HILOGE("Call napi_get_value_int32 failed");
83         return std::nullopt;
84     }
85     MMI_HILOGD("%{public}s=%{public}d", name.c_str(), ret);
86     return std::make_optional(ret);
87 }
88 
GetPreKeys(const napi_env & env,const napi_value & value,std::set<int32_t> & params)89 napi_value GetPreKeys(const napi_env &env, const napi_value &value, std::set<int32_t> &params)
90 {
91     CALL_DEBUG_ENTER;
92     uint32_t arrayLength = 0;
93     CHKRP(env, napi_get_array_length(env, value, &arrayLength), GET_ARRAY_LENGTH);
94     for (uint32_t i = 0; i < arrayLength; i++) {
95         napi_value napiElement;
96         CHKRP(env, napi_get_element(env, value, i, &napiElement), GET_ELEMENT);
97         napi_valuetype valuetype;
98         CHKRP(env, napi_typeof(env, napiElement, &valuetype), TYPEOF);
99         if (valuetype != napi_number) {
100             MMI_HILOGE("PreKeys Wrong argument type, Number expected");
101             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "element of preKeys must be number");
102             return nullptr;
103         }
104         int32_t value = 0;
105         CHKRP(env, napi_get_value_int32(env, napiElement, &value), GET_INT32);
106         if (value < 0) {
107             MMI_HILOGE("preKey:%{public}d is less 0, can not process", value);
108             THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "element of preKeys must be greater than or equal to 0");
109             return nullptr;
110         }
111         MMI_HILOGD("Get int array number:%{public}d", value);
112         if (!params.insert(value).second) {
113             MMI_HILOGE("Params insert value failed");
114             return nullptr;
115         }
116     }
117     napi_value ret;
118     CHKRP(env, napi_create_int32(env, RET_OK, &ret), CREATE_INT32);
119     return ret;
120 }
121 
GetPreSubscribeId(Callbacks & callbacks,KeyEventMonitorInfo * event)122 int32_t GetPreSubscribeId(Callbacks &callbacks, KeyEventMonitorInfo *event)
123 {
124     CHKPR(event, ERROR_NULL_POINTER);
125     auto it = callbacks.find(event->eventType);
126     if (it == callbacks.end() || it->second.empty()) {
127         MMI_HILOGE("The callbacks is empty");
128         return JS_CALLBACK_EVENT_FAILED;
129     }
130     CHKPR(it->second.front(), ERROR_NULL_POINTER);
131     return it->second.front()->subscribeId;
132 }
133 
AddEventCallback(const napi_env & env,Callbacks & callbacks,KeyEventMonitorInfo * event)134 int32_t AddEventCallback(const napi_env &env, Callbacks &callbacks, KeyEventMonitorInfo *event)
135 {
136     CALL_DEBUG_ENTER;
137     CHKPR(event, ERROR_NULL_POINTER);
138     std::lock_guard guard(sCallBacksMutex_);
139     if (callbacks.find(event->eventType) == callbacks.end()) {
140         MMI_HILOGD("No callback in %{public}s", event->eventType.c_str());
141         callbacks[event->eventType] = {};
142     }
143     napi_value handler1 = nullptr;
144     napi_status status = napi_get_reference_value(env, event->callback[0], &handler1);
145     if (status != napi_ok) {
146         MMI_HILOGE("Handler1 get reference value failed");
147         return JS_CALLBACK_EVENT_FAILED;
148     }
149     auto it = callbacks.find(event->eventType);
150     for (const auto &iter : it->second) {
151         napi_value handler2 = nullptr;
152         status = napi_get_reference_value(env, (*iter).callback[0], &handler2);
153         if (status != napi_ok) {
154             MMI_HILOGE("Handler2 get reference value failed");
155             return JS_CALLBACK_EVENT_FAILED;
156         }
157         bool isEqual = false;
158         status = napi_strict_equals(env, handler1, handler2, &isEqual);
159         if (status != napi_ok) {
160             MMI_HILOGE("Compare two handler failed");
161             return JS_CALLBACK_EVENT_FAILED;
162         }
163         if (isEqual) {
164             MMI_HILOGE("Callback already exist");
165             return JS_CALLBACK_EVENT_FAILED;
166         }
167     }
168     it->second.push_back(event);
169     return JS_CALLBACK_EVENT_SUCCESS;
170 }
171 
DelEventCallback(const napi_env & env,Callbacks & callbacks,KeyEventMonitorInfo * event,int32_t & subscribeId)172 int32_t DelEventCallback(const napi_env &env, Callbacks &callbacks,
173     KeyEventMonitorInfo *event, int32_t &subscribeId)
174 {
175     CALL_DEBUG_ENTER;
176     CHKPR(event, ERROR_NULL_POINTER);
177     std::lock_guard guard(sCallBacksMutex_);
178     if (callbacks.count(event->eventType) <= 0) {
179         MMI_HILOGE("Callback doesn't exists");
180         return JS_CALLBACK_EVENT_FAILED;
181     }
182     auto &info = callbacks[event->eventType];
183     MMI_HILOGD("EventType:%{public}s, keyEventMonitorInfos:%{public}zu",
184         event->eventType.c_str(), info.size());
185     napi_value handler1 = nullptr;
186     napi_status status;
187     if (event->callback[0] != nullptr) {
188         status = napi_get_reference_value(env, event->callback[0], &handler1);
189         if (status != napi_ok) {
190             MMI_HILOGE("Handler1 get reference value failed");
191             return JS_CALLBACK_EVENT_FAILED;
192         }
193     }
194     for (auto iter = info.begin(); iter != info.end();) {
195         if (*iter == nullptr) {
196             info.erase(iter++);
197             continue;
198         }
199         if (handler1 != nullptr) {
200             napi_value handler2 = nullptr;
201             status = napi_get_reference_value(env, (*iter)->callback[0], &handler2);
202             if (status != napi_ok) {
203                 MMI_HILOGE("Handler2 get reference value failed");
204                 return JS_CALLBACK_EVENT_FAILED;
205             }
206             bool isEquals = false;
207             status = napi_strict_equals(env, handler1, handler2, &isEquals);
208             if (status != napi_ok) {
209                 MMI_HILOGE("Compare two handler failed");
210                 return JS_CALLBACK_EVENT_FAILED;
211             }
212             if (isEquals) {
213                 status = napi_delete_reference(env, (*iter)->callback[0]);
214                 if (status != napi_ok) {
215                     MMI_HILOGE("Delete reference failed");
216                     return JS_CALLBACK_EVENT_FAILED;
217                 }
218                 KeyEventMonitorInfo *monitorInfo = *iter;
219                 info.erase(iter++);
220                 if (info.empty()) {
221                     subscribeId = monitorInfo->subscribeId;
222                 }
223                 delete monitorInfo;
224                 monitorInfo = nullptr;
225                 MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
226                 return JS_CALLBACK_EVENT_SUCCESS;
227             }
228             ++iter;
229             continue;
230         }
231         status = napi_delete_reference(env, (*iter)->callback[0]);
232         if (status != napi_ok) {
233             MMI_HILOGE("Delete reference failed");
234             napi_throw_error(env, nullptr, "Delete reference failed");
235             return JS_CALLBACK_EVENT_FAILED;
236         }
237         KeyEventMonitorInfo *monitorInfo = *iter;
238         info.erase(iter++);
239         if (info.empty()) {
240             subscribeId = monitorInfo->subscribeId;
241         }
242         delete monitorInfo;
243         monitorInfo = nullptr;
244         MMI_HILOGD("Callback has deleted, size:%{public}zu", info.size());
245     }
246     MMI_HILOGD("Callback size:%{public}zu", info.size());
247     return JS_CALLBACK_EVENT_SUCCESS;
248 }
249 
AsyncWorkFn(const napi_env & env,KeyEventMonitorInfo * event,napi_value & result)250 static void AsyncWorkFn(const napi_env &env, KeyEventMonitorInfo *event, napi_value &result)
251 {
252     CHKPV(event);
253     CHKPV(event->keyOption);
254     MMI_HILOGD("Status > 0 enter");
255     CHKRV(env, napi_create_object(env, &result), CREATE_OBJECT);
256     napi_value arr;
257     CHKRV(env, napi_create_array(env, &arr), CREATE_ARRAY);
258     std::set<int32_t> preKeys = event->keyOption->GetPreKeys();
259     int32_t i = 0;
260     napi_value value;
261     for (const auto &preKey : preKeys) {
262         CHKRV(env, napi_create_int32(env, preKey, &value), CREATE_INT32);
263         CHKRV(env, napi_set_element(env, arr, i, value), SET_ELEMENT);
264         ++i;
265     }
266     std::string preKeysStr = "preKeys";
267     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, result, preKeysStr.c_str(), arr));
268     MMI::SetNamedProperty(env, result, "finalKey", event->keyOption->GetFinalKey());
269     MMI::SetNamedProperty(env, result, "isFinalKeyDown", event->keyOption->IsFinalKeyDown());
270     MMI::SetNamedProperty(env, result, "finalKeyDownDuration", event->keyOption->GetFinalKeyDownDuration());
271 }
272 
273 struct KeyEventMonitorInfoWorker {
274     napi_env env { nullptr };
275     KeyEventMonitorInfo *reportEvent { nullptr };
276 };
277 
UvQueueWorkAsyncCallback(uv_work_t * work,int32_t status)278 void UvQueueWorkAsyncCallback(uv_work_t *work, int32_t status)
279 {
280     CALL_DEBUG_ENTER;
281     CHKPV(work);
282     if (work->data == nullptr) {
283         MMI_HILOGE("Check data is null");
284         delete work;
285         work = nullptr;
286         return;
287     }
288     (void)status;
289     KeyEventMonitorInfoWorker *dataWorker = static_cast<KeyEventMonitorInfoWorker *>(work->data);
290     delete work;
291     work = nullptr;
292     KeyEventMonitorInfo *event = dataWorker->reportEvent;
293     napi_env env = dataWorker->env;
294     delete dataWorker;
295     dataWorker = nullptr;
296     CHKPV(event);
297     napi_handle_scope scope = nullptr;
298     napi_open_handle_scope(env, &scope);
299     if (scope == nullptr) {
300         MMI_HILOGE("Scope is nullptr");
301         return;
302     }
303     napi_value callback = nullptr;
304     CHKRV_SCOPE(env, napi_get_reference_value(env, event->callback[0], &callback), GET_REFERENCE_VALUE, scope);
305     napi_value result = nullptr;
306     AsyncWorkFn(env, event, result);
307     napi_value callResult = nullptr;
308     CHKRV_SCOPE(env, napi_call_function(env, nullptr, callback, 1, &result, &callResult), CALL_FUNCTION, scope);
309     napi_close_handle_scope(env, scope);
310 }
311 
EmitAsyncCallbackWork(KeyEventMonitorInfo * reportEvent)312 void EmitAsyncCallbackWork(KeyEventMonitorInfo *reportEvent)
313 {
314     CALL_DEBUG_ENTER;
315     CHKPV(reportEvent);
316     uv_loop_s *loop = nullptr;
317     CHKRV(reportEvent->env, napi_get_uv_event_loop(reportEvent->env, &loop), GET_UV_LOOP);
318     uv_work_t *work = new (std::nothrow) uv_work_t;
319     CHKPV(work);
320     KeyEventMonitorInfoWorker *dataWorker = new (std::nothrow) KeyEventMonitorInfoWorker();
321     CHKPV(dataWorker);
322 
323     dataWorker->env = reportEvent->env;
324     dataWorker->reportEvent = reportEvent;
325     work->data = static_cast<void *>(dataWorker);
326 
327     int32_t ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvQueueWorkAsyncCallback);
328     if (ret != 0) {
329         delete dataWorker;
330         delete work;
331     }
332 }
333 } // namespace MMI
334 } // namespace OHOS