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_input_monitor_manager.h"
17 #include <uv.h>
18 #include "define_multimodal.h"
19
20 namespace OHOS {
21 namespace MMI {
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, MMI_LOG_DOMAIN, "JsInputMonitorManager" };
24 }
25
~JsInputMonitorManager()26 JsInputMonitorManager::~JsInputMonitorManager()
27 {
28 for (const auto &item : monitors_) {
29 item->Stop();
30 }
31 monitors_.clear();
32 RemoveAllEnv();
33 }
34
GetInstance()35 JsInputMonitorManager& JsInputMonitorManager::GetInstance()
36 {
37 static JsInputMonitorManager instance;
38 return instance;
39 }
40
AddMonitor(napi_env jsEnv,napi_value receiver)41 void JsInputMonitorManager::AddMonitor(napi_env jsEnv, napi_value receiver)
42 {
43 MMI_LOGD("Enter");
44 std::lock_guard<std::mutex> guard(mutex_);
45 for (auto& item : monitors_) {
46 if (item->IsMatch(jsEnv, receiver) != RET_ERR) {
47 return;
48 }
49 }
50 std::shared_ptr<JsInputMonitor> monitor = std::make_shared<JsInputMonitor>(jsEnv, receiver, nextId_++);
51 monitors_.push_back(monitor);
52 if (!monitor->Start()) {
53 monitors_.pop_back();
54 }
55 MMI_LOGD("Leave");
56 }
57
RemoveMonitor(napi_env jsEnv,napi_value receiver)58 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv, napi_value receiver)
59 {
60 MMI_LOGD("Enter");
61 std::shared_ptr<JsInputMonitor> monitor = nullptr;
62 {
63 std::lock_guard<std::mutex> guard(mutex_);
64 for (auto it = monitors_.begin(); it != monitors_.end(); ++it) {
65 if ((*it)->IsMatch(jsEnv, receiver) == RET_OK) {
66 monitor = *it;
67 monitors_.erase(it);
68 MMI_LOGD("Found monitor");
69 break;
70 }
71 }
72 }
73 if (monitor != nullptr) {
74 monitor->Stop();
75 }
76 MMI_LOGD("Leave");
77 }
78
RemoveMonitor(napi_env jsEnv)79 void JsInputMonitorManager::RemoveMonitor(napi_env jsEnv)
80 {
81 MMI_LOGD("Enter");
82 std::list<std::shared_ptr<JsInputMonitor>> monitors;
83 {
84 std::lock_guard<std::mutex> guard(mutex_);
85 for (auto it = monitors_.begin(); it != monitors_.end();) {
86 if ((*it)->IsMatch(jsEnv) == RET_OK) {
87 monitors.push_back(*it);
88 monitors_.erase(it++);
89 continue;
90 }
91 ++it;
92 }
93 }
94 for (const auto &item : monitors) {
95 item->Stop();
96 }
97 MMI_LOGD("Leave");
98 }
99
GetMonitor(int32_t id)100 std::shared_ptr<JsInputMonitor> JsInputMonitorManager::GetMonitor(int32_t id) {
101 MMI_LOGD("Enter");
102 std::lock_guard<std::mutex> guard(mutex_);
103 for (auto &item : monitors_) {
104 if (item->GetId() == id) {
105 MMI_LOGD("Leave");
106 return item;
107 }
108 }
109 MMI_LOGD("No monitor found");
110 return nullptr;
111 }
112
AddEnv(napi_env env,napi_callback_info cbInfo)113 bool JsInputMonitorManager::AddEnv(napi_env env, napi_callback_info cbInfo)
114 {
115 MMI_LOGD("Enter");
116 if (IsExisting(env)) {
117 MMI_LOGD("Env is already exists");
118 return true;
119 }
120 napi_value thisVar = nullptr;
121 void *data = nullptr;
122 int32_t *id = new int32_t;
123 *id = 0;
124 napi_get_cb_info(env, cbInfo, nullptr, nullptr, &thisVar, &data);
125 auto status = napi_wrap(env, thisVar, static_cast<void*>(id),
126 [](napi_env env, void *data, void *hint) {
127 MMI_LOGD("napi_wrap enter");
128 int32_t *id = static_cast<int32_t *>(data);
129 delete id;
130 id = nullptr;
131 JSIMM.RemoveMonitor(env);
132 JSIMM.RemoveEnv(env);
133 MMI_LOGD("napi_wrap leave");
134 }, nullptr, nullptr);
135 if (status != napi_ok) {
136 MMI_LOGE("napi_wrap failed");
137 delete id;
138 return false;
139 }
140 napi_ref ref = nullptr;
141 status = napi_create_reference(env, thisVar, 1, &ref);
142 if (status != napi_ok) {
143 MMI_LOGE("napi_create_reference failed");
144 delete id;
145 return false;
146 }
147 envManager_.insert(std::pair<napi_env, napi_ref>(env, ref));
148 MMI_LOGD("Leave");
149 return true;
150 }
151
RemoveEnv(napi_env env)152 void JsInputMonitorManager::RemoveEnv(napi_env env)
153 {
154 MMI_LOGD("Enter");
155 auto it = envManager_.find(env);
156 if (it == envManager_.end()) {
157 MMI_LOGD("No env found");
158 return;
159 }
160 RemoveEnv(it);
161 MMI_LOGD("Leave");
162 }
163
RemoveEnv(std::map<napi_env,napi_ref>::iterator it)164 void JsInputMonitorManager::RemoveEnv(std::map<napi_env, napi_ref>::iterator it)
165 {
166 MMI_LOGD("Enter");
167 uint32_t refCount;
168 auto status = napi_reference_unref(it->first, it->second, &refCount);
169 if (status != napi_ok) {
170 MMI_LOGE("napi_reference_unref failed");
171 return;
172 }
173 envManager_.erase(it);
174 MMI_LOGD("Leave");
175 }
176
RemoveAllEnv()177 void JsInputMonitorManager::RemoveAllEnv()
178 {
179 MMI_LOGD("Enter");
180 for (auto it = envManager_.begin(); it != envManager_.end();) {
181 RemoveEnv(it++);
182 }
183 MMI_LOGD("Leave");
184 }
185
IsExisting(napi_env env)186 bool JsInputMonitorManager::IsExisting(napi_env env)
187 {
188 MMI_LOGD("Enter");
189 auto it = envManager_.find(env);
190 if (it == envManager_.end()) {
191 MMI_LOGD("No env found");
192 return false;
193 }
194 MMI_LOGD("Leave");
195 return true;
196 }
197 } // namespace MMI
198 } // namespace OHOS
199