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_input_monitor_manager.h"
17
18 #include <uv.h>
19
20 #include "define_multimodal.h"
21 #include "napi_constants.h"
22 #include "util_napi_error.h"
23
24 #undef MMI_LOG_TAG
25 #define MMI_LOG_TAG "JsInputMonitorManager"
26
27 namespace OHOS {
28 namespace MMI {
29 namespace {
30 constexpr int32_t MONITOR_REGISTER_EXCEED_MAX { 4100001 };
31 } // namespace
32
GetInstance()33 JsInputMonitorManager& JsInputMonitorManager::GetInstance()
34 {
35 static JsInputMonitorManager instance;
36 return instance;
37 }
38
AddMonitor(napi_env jsEnv,const std::string & typeName,std::vector<Rect> hotRectArea,int32_t rectTotal,napi_value callback,const int32_t fingers)39 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, const std::string &typeName,
40 std::vector<Rect> hotRectArea, int32_t rectTotal, napi_value callback, const int32_t fingers)
41 {
42 CALL_DEBUG_ENTER;
43 std::lock_guard<std::mutex> guard(mutex_);
44 for (const auto &item : monitors_) {
45 if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
46 MMI_HILOGW("Add js monitor failed");
47 return;
48 }
49 }
50 auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, hotRectArea,
51 rectTotal, callback, nextId_++, fingers);
52 int32_t ret = monitor->Start(typeName);
53 if (ret < 0) {
54 MMI_HILOGE("js monitor startup failed");
55 ThrowError(jsEnv, ret);
56 return;
57 }
58 monitors_.push_back(monitor);
59 }
60
AddMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)61 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, const std::string &typeName,
62 napi_value callback, const int32_t fingers)
63 {
64 CALL_DEBUG_ENTER;
65 std::lock_guard<std::mutex> guard(mutex_);
66 for (const auto &item : monitors_) {
67 if ((item != nullptr) && (item->IsMatch(jsEnv, callback) != RET_ERR)) {
68 MMI_HILOGW("Add js monitor failed");
69 return;
70 }
71 }
72 auto monitor = std::make_shared<JsInputMonitor>(jsEnv, typeName, callback, nextId_++, fingers);
73 int32_t ret = monitor->Start(typeName);
74 if (ret < 0) {
75 MMI_HILOGE("js monitor startup failed");
76 ThrowError(jsEnv, ret);
77 return;
78 }
79 monitors_.push_back(monitor);
80 }
81
RemoveMonitor(napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)82 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, const std::string &typeName, napi_value callback,
83 const int32_t fingers)
84 {
85 CALL_DEBUG_ENTER;
86 std::shared_ptr<JsInputMonitor> monitor = nullptr;
87 do {
88 std::lock_guard<std::mutex> guard(mutex_);
89 for (auto it = monitors_.begin(); it != monitors_.end();) {
90 if ((*it) == nullptr) {
91 monitors_.erase(it++);
92 continue;
93 }
94 if (IsFindJsInputMonitor(*it, jsEnv, typeName, callback, fingers)) {
95 monitor = *it;
96 monitors_.erase(it++);
97 MMI_HILOGD("Found monitor");
98 break;
99 }
100 ++it;
101 }
102 } while (0);
103 if (monitor != nullptr) {
104 monitor->Stop();
105 }
106 }
107
RemoveMonitor(napi_env jsEnv,const std::string & typeName,const int32_t fingers)108 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, const std::string &typeName, const int32_t fingers)
109 {
110 CALL_DEBUG_ENTER;
111 std::list<std::shared_ptr<JsInputMonitor>> monitors;
112 do {
113 std::lock_guard<std::mutex> guard(mutex_);
114 for (auto it = monitors_.begin(); it != monitors_.end();) {
115 if ((*it) == nullptr) {
116 monitors_.erase(it++);
117 continue;
118 }
119 if (IsFindJsInputMonitor(*it, jsEnv, typeName, fingers)) {
120 monitors.push_back(*it);
121 monitors_.erase(it++);
122 continue;
123 }
124 ++it;
125 }
126 } while (0);
127
128 for (const auto &item : monitors) {
129 if (item != nullptr) {
130 item->Stop();
131 }
132 }
133 }
134
RemoveMonitor(napi_env jsEnv)135 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv)
136 {
137 CALL_DEBUG_ENTER;
138 std::list<std::shared_ptr<JsInputMonitor>> monitors;
139 do {
140 std::lock_guard<std::mutex> guard(mutex_);
141 for (auto it = monitors_.begin(); it != monitors_.end();) {
142 if ((*it) == nullptr) {
143 monitors_.erase(it++);
144 continue;
145 }
146 if ((*it)->IsMatch(jsEnv) == RET_OK) {
147 monitors.push_back(*it);
148 monitors_.erase(it++);
149 continue;
150 }
151 ++it;
152 }
153 } while (0);
154
155 for (const auto &item : monitors) {
156 if (item != nullptr) {
157 item->Stop();
158 }
159 }
160 }
161
OnPointerEventByMonitorId(int32_t id,int32_t fingers,std::shared_ptr<PointerEvent> pointEvent)162 void JsInputMonitorManager::OnPointerEventByMonitorId(int32_t id, int32_t fingers,
163 std::shared_ptr<PointerEvent> pointEvent)
164 {
165 CALL_DEBUG_ENTER;
166 std::lock_guard<std::mutex> guard(mutex_);
167 for (const auto &item : monitors_) {
168 if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
169 item->OnPointerEvent(pointEvent);
170 }
171 }
172 }
173
GetMonitor(int32_t id,int32_t fingers)174 const std::shared_ptr<JsInputMonitor> JsInputMonitorManager::GetMonitor(int32_t id, int32_t fingers)
175 {
176 CALL_DEBUG_ENTER;
177 std::lock_guard<std::mutex> guard(mutex_);
178 for (const auto &item : monitors_) {
179 if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
180 return item;
181 }
182 }
183 MMI_HILOGD("No monitor found");
184 return nullptr;
185 }
186
GetMonitorTypeName(int32_t id,int32_t fingers)187 std::string JsInputMonitorManager::GetMonitorTypeName(int32_t id, int32_t fingers)
188 {
189 CALL_DEBUG_ENTER;
190 std::lock_guard<std::mutex> guard(mutex_);
191 for (const auto &item : monitors_) {
192 if ((item != nullptr) && (item->GetId() == id && item->GetFingers() == fingers)) {
193 return item->GetTypeName();
194 }
195 }
196 MMI_HILOGD("No monitor found");
197 return "";
198 }
199
AddEnv(napi_env env,napi_callback_info cbInfo)200 bool JsInputMonitorManager::AddEnv(napi_env env, napi_callback_info cbInfo)
201 {
202 CALL_DEBUG_ENTER;
203 if (IsExisting(env)) {
204 MMI_HILOGD("Env is already existent");
205 return true;
206 }
207 napi_value thisVar = nullptr;
208 void *data = nullptr;
209 int32_t *id = new (std::nothrow) int32_t;
210 CHKPF(id);
211 *id = 0;
212 if (napi_get_cb_info(env, cbInfo, nullptr, nullptr, &thisVar, &data) != napi_ok) {
213 MMI_HILOGE("GET_CB_INFO failed");
214 auto infoTemp = std::string("AddEnv GET_CB_INFO failed");
215 napi_throw_error(env, nullptr, infoTemp.c_str());
216 delete id;
217 return false;
218 }
219 auto status = napi_wrap(env, thisVar, static_cast<void*>(id),
220 [](napi_env env, void *data, void *hint) {
221 MMI_HILOGD("napi_wrap enter");
222 int32_t *id = static_cast<int32_t *>(data);
223 delete id;
224 id = nullptr;
225 JS_INPUT_MONITOR_MGR.RemoveMonitor(env);
226 JS_INPUT_MONITOR_MGR.RemoveEnv(env);
227 MMI_HILOGD("napi_wrap leave");
228 }, nullptr, nullptr);
229 if (status != napi_ok) {
230 MMI_HILOGE("napi_wrap failed");
231 delete id;
232 return false;
233 }
234 napi_ref ref = nullptr;
235 status = napi_create_reference(env, thisVar, 1, &ref);
236 if (status != napi_ok) {
237 MMI_HILOGE("napi_create_reference failed");
238 return false;
239 }
240 std::lock_guard<std::mutex> lock(envMutex_);
241 auto iter = envManager_.insert(std::pair<napi_env, napi_ref>(env, ref));
242 if (!iter.second) {
243 MMI_HILOGE("Insert value failed");
244 return false;
245 }
246 return true;
247 }
248
RemoveEnv(napi_env env)249 void JsInputMonitorManager::RemoveEnv(napi_env env)
250 {
251 CALL_DEBUG_ENTER;
252 std::lock_guard<std::mutex> lock(envMutex_);
253 auto it = envManager_.find(env);
254 if (it == envManager_.end()) {
255 MMI_HILOGD("No env found");
256 return;
257 }
258 RemoveEnv(it);
259 }
260
RemoveEnv(std::map<napi_env,napi_ref>::iterator it)261 void JsInputMonitorManager::RemoveEnv(std::map<napi_env, napi_ref>::iterator it)
262 {
263 CALL_DEBUG_ENTER;
264 uint32_t refCount = 0;
265 CHKRV(napi_reference_unref(it->first, it->second, &refCount), REFERENCE_UNREF);
266 envManager_.erase(it);
267 }
268
RemoveAllEnv()269 void JsInputMonitorManager::RemoveAllEnv()
270 {
271 CALL_DEBUG_ENTER;
272 std::lock_guard<std::mutex> lock(envMutex_);
273 for (auto it = envManager_.begin(); it != envManager_.end();) {
274 RemoveEnv(it++);
275 }
276 }
277
IsExisting(napi_env env)278 bool JsInputMonitorManager::IsExisting(napi_env env)
279 {
280 CALL_DEBUG_ENTER;
281 std::lock_guard<std::mutex> lock(envMutex_);
282 auto it = envManager_.find(env);
283 if (it == envManager_.end()) {
284 MMI_HILOGD("No env found");
285 return false;
286 }
287
288 return true;
289 }
290
ThrowError(napi_env env,int32_t code)291 void JsInputMonitorManager::ThrowError(napi_env env, int32_t code)
292 {
293 int32_t errorCode = -code;
294 if (errorCode == MONITOR_REGISTER_EXCEED_MAX) {
295 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Maximum number of listeners exceeded for a single process");
296 } else if (errorCode == COMMON_PERMISSION_CHECK_ERROR) {
297 THROWERR_API9(env, COMMON_PERMISSION_CHECK_ERROR, "monitor", "ohos.permission.INPUT_MONITORING");
298 } else {
299 MMI_HILOGE("Add monitor failed");
300 }
301 }
302
GetHotRectAreaList(napi_env env,napi_value rectNapiValue,uint32_t rectListLength)303 std::vector<Rect> JsInputMonitorManager::GetHotRectAreaList(napi_env env,
304 napi_value rectNapiValue, uint32_t rectListLength)
305 {
306 std::vector<Rect> hotRectAreaList;
307 for (uint32_t i = 0; i < rectListLength; i++) {
308 napi_value napiElement;
309 CHKRR(napi_get_element(env, rectNapiValue, i, &napiElement), GET_ELEMENT, hotRectAreaList);
310 Rect rectItem;
311 napi_value napiX = nullptr;
312 CHKRR(napi_get_named_property(env, napiElement, "left", &napiX), GET_NAMED_PROPERTY, hotRectAreaList);
313 if (napiX == nullptr) {
314 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "left not found");
315 return hotRectAreaList;
316 }
317 int32_t rectX = -1;
318 CHKRR(napi_get_value_int32(env, napiX, &rectX), GET_VALUE_INT32, hotRectAreaList);
319 rectItem.x = rectX;
320 napi_value napiY = nullptr;
321 CHKRR(napi_get_named_property(env, napiElement, "top", &napiY), GET_NAMED_PROPERTY, hotRectAreaList);
322 if (napiY == nullptr) {
323 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "top not found");
324 return hotRectAreaList;
325 }
326 int32_t rectY = -1;
327 CHKRR(napi_get_value_int32(env, napiY, &rectY), GET_VALUE_INT32, hotRectAreaList);
328 rectItem.y = rectY;
329 napi_value napiWidth = nullptr;
330 CHKRR(napi_get_named_property(env, napiElement, "width", &napiWidth), GET_NAMED_PROPERTY, hotRectAreaList);
331 if (napiWidth == nullptr) {
332 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "width not found");
333 return hotRectAreaList;
334 }
335 int32_t rectWidth = -1;
336 CHKRR(napi_get_value_int32(env, napiWidth, &rectWidth), GET_VALUE_INT32, hotRectAreaList);
337 rectItem.width = rectWidth;
338 napi_value napiHeight = nullptr;
339 CHKRR(napi_get_named_property(env, napiElement, "height", &napiHeight), GET_NAMED_PROPERTY, hotRectAreaList);
340 if (napiHeight == nullptr) {
341 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "height not found");
342 return hotRectAreaList;
343 }
344 int32_t rectHeight = -1;
345 CHKRR(napi_get_value_int32(env, napiHeight, &rectHeight), GET_VALUE_INT32, hotRectAreaList);
346 rectItem.height = rectHeight;
347 if (rectX < 0 || rectY < 0 || rectHeight < 0 || rectWidth < 0) {
348 THROWERR_CUSTOM(env, COMMON_PARAMETER_ERROR, "Rect parameter can't be negative");
349 return hotRectAreaList;
350 }
351 hotRectAreaList.push_back(rectItem);
352 }
353 return hotRectAreaList;
354 }
355
IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,napi_env jsEnv,const std::string & typeName,napi_value callback,const int32_t fingers)356 bool JsInputMonitorManager::IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,
357 napi_env jsEnv, const std::string &typeName, napi_value callback, const int32_t fingers)
358 {
359 if ((monitor->GetTypeName() == typeName) && (monitor->GetFingers() == fingers)) {
360 if (monitor->IsMatch(jsEnv, callback) == RET_OK) {
361 return true;
362 }
363 }
364 return false;
365 }
366
IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,napi_env jsEnv,const std::string & typeName,const int32_t fingers)367 bool JsInputMonitorManager::IsFindJsInputMonitor(const std::shared_ptr<JsInputMonitor> monitor,
368 napi_env jsEnv, const std::string &typeName, const int32_t fingers)
369 {
370 if ((monitor->GetTypeName() == typeName) && (monitor->GetFingers() == fingers)) {
371 if (monitor->IsMatch(jsEnv) == RET_OK) {
372 return true;
373 }
374 }
375 return false;
376 }
377 } // namespace MMI
378 } // namespace OHOS
379