1 /*
2 * Copyright (c) 2025 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 "ani_event_target.h"
17 #include "ani_util.h"
18 #include "bytrace_adapter.h"
19
20 #undef MMI_LOG_TAG
21 #define MMI_LOG_TAG "AniEventTarget"
22
23 namespace OHOS {
24 namespace MMI {
25 namespace {
26 constexpr int32_t INPUT_PARAMETER_MIDDLE { 2 };
27
28 std::mutex mutex_;
29 const std::string ADD_EVENT = "add";
30 const std::string REMOVE_EVENT = "remove";
31 const std::string CHANGED_TYPE = "change";
32 constexpr int32_t ANI_SCOPE_SIZE = 16;
33
34 struct DeviceItem {
35 int32_t deviceId;
36 void *item;
37 };
38
39 } // namespace
40
AniEventTarget()41 AniEventTarget::AniEventTarget()
42 {
43 CALL_DEBUG_ENTER;
44 std::lock_guard<std::mutex> lock(mutex_);
45 auto ret = devListener_.insert({ CHANGED_TYPE, std::vector<std::unique_ptr<AniUtil::CallbackInfo>>() });
46 CK(ret.second, VAL_NOT_EXP);
47 GetMainEventHandler();
48 }
49
~AniEventTarget()50 AniEventTarget::~AniEventTarget()
51 {
52 CALL_DEBUG_ENTER;
53 handler_ = nullptr;
54 }
55
GetMainEventHandler()56 void AniEventTarget::GetMainEventHandler()
57 {
58 CALL_DEBUG_ENTER;
59 auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
60 handler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
61 }
62
EmitCallbackWork(ani_env * env,const std::shared_ptr<AniUtil::ReportData> & reportData,const std::string & type)63 bool AniEventTarget::EmitCallbackWork(ani_env *env, const std::shared_ptr<AniUtil::ReportData> &reportData,
64 const std::string &type)
65 {
66 CALL_DEBUG_ENTER;
67 AniLocalScopeGuard aniLocalScopeGuard(env, ANI_SCOPE_SIZE);
68 if (!aniLocalScopeGuard.IsStatusOK()) {
69 MMI_HILOGE("%{public}s: CreateLocalScope failed", __func__);
70 return false;
71 }
72 std::vector<ani_ref> args;
73 const char *nsName = "L@ohos/multimodalInput/inputDevice/inputDevice;";
74 const char *className = "LDeviceListenerImpl;";
75 auto obj = AniUtil::CreateAniObject(env, nsName, className);
76 if (obj == nullptr) {
77 MMI_HILOGE("%{public}s: CreateAniObject DeviceListenerObj failed", __func__);
78 return false;
79 }
80 ani_string stringValue = AniUtil::StdStringToANIString(env, type);
81 if (ANI_OK != env->Object_SetPropertyByName_Ref(obj, "type", stringValue)) {
82 MMI_HILOGE("%{public}s: Object_SetPropertyByName_Ref failed", __func__);
83 return false;
84 }
85
86 if (ANI_OK != env->Object_SetPropertyByName_Double(obj, "deviceId", reportData->deviceId)) {
87 MMI_HILOGE("%{public}s: SetPropertyByName deviceId:%{public}d failed", __func__, reportData->deviceId);
88 return false;
89 }
90
91 MMI_HILOGE("%{public}s: type:%{public}s, deviceId:%{public}d", __func__, type.c_str(), reportData->deviceId);
92 args.push_back(obj);
93
94 auto fnObj = reinterpret_cast<ani_fn_object>(reportData->ref);
95 if (AniUtil::IsInstanceOf(env, "Lstd/core/Function1;", fnObj) == 0) {
96 MMI_HILOGE("%{public}s: fnObj is not instance Of function", __func__);
97 return false;
98 }
99
100 ani_ref result;
101 if (ANI_OK != env->FunctionalObject_Call(fnObj, 1, args.data(), &result)) {
102 MMI_HILOGE("%{public}s: FunctionalObject_Call failed", __func__);
103 return false;
104 }
105 MMI_HILOGD("FunctionalObject_Call success");
106 return true;
107 }
108
EmitAddedDeviceEvent(const std::shared_ptr<AniUtil::ReportData> & reportData)109 void AniEventTarget::EmitAddedDeviceEvent(const std::shared_ptr<AniUtil::ReportData> &reportData)
110 {
111 CALL_DEBUG_ENTER;
112 std::lock_guard<std::mutex> guard(mutex_);
113 auto addEvent = devListener_.find(CHANGED_TYPE);
114 if (addEvent == devListener_.end()) {
115 MMI_HILOGE("%{public}s: Find change event failed", __func__);
116 return;
117 }
118 CHKPV(reportData);
119 for (const auto &item : addEvent->second) {
120 CHKPC(item->env_);
121 if (item->callback_ != reportData->ref) {
122 continue;
123 }
124
125 if (!EmitCallbackWork(item->env_, reportData, ADD_EVENT)) {
126 continue;
127 }
128
129 BytraceAdapter::StartDevListener(ADD_EVENT, reportData->deviceId);
130 MMI_HILOGI("Report device change task, event type:%{public}s, deviceid:%{public}d",
131 ADD_EVENT.c_str(), reportData->deviceId);
132 BytraceAdapter::StopDevListener();
133 }
134 }
135
EmitRemoveDeviceEvent(const std::shared_ptr<AniUtil::ReportData> & reportData)136 void AniEventTarget::EmitRemoveDeviceEvent(const std::shared_ptr<AniUtil::ReportData> &reportData)
137 {
138 CALL_DEBUG_ENTER;
139 std::lock_guard<std::mutex> guard(mutex_);
140 auto removeEvent = devListener_.find(CHANGED_TYPE);
141 if (removeEvent == devListener_.end()) {
142 MMI_HILOGE("%{public}s: Find change event failed", __func__);
143 return;
144 }
145 CHKPV(reportData);
146 for (const auto &item : removeEvent->second) {
147 CHKPC(item->env_);
148 if (item->callback_ != reportData->ref) {
149 continue;
150 }
151
152 if (!EmitCallbackWork(item->env_, reportData, REMOVE_EVENT)) {
153 continue;
154 }
155
156 BytraceAdapter::StartDevListener(REMOVE_EVENT, reportData->deviceId);
157 MMI_HILOGI("Report device change task, event type:%{public}s, deviceid:%{public}d",
158 REMOVE_EVENT.c_str(), reportData->deviceId);
159 BytraceAdapter::StopDevListener();
160 }
161 }
162
PostMainThreadTask(const std::function<void ()> task)163 void AniEventTarget::PostMainThreadTask(const std::function<void()> task)
164 {
165 if (!handler_) {
166 auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
167 if (!runner) {
168 MMI_HILOGE("get main event runner failed!");
169 return;
170 }
171 handler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
172 }
173 bool ret = handler_->PostTask(task, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {});
174 MMI_HILOGI("%{public}s: PostTask %{public}s", __func__, (ret? "success" : "failed"));
175 }
176
OnDeviceAdded(int32_t deviceId,const std::string & type)177 void AniEventTarget::OnDeviceAdded(int32_t deviceId, const std::string &type)
178 {
179 CALL_DEBUG_ENTER;
180 std::lock_guard<std::mutex> guard(mutex_);
181 auto changeEvent = devListener_.find(CHANGED_TYPE);
182 if (changeEvent == devListener_.end()) {
183 MMI_HILOGE("%{public}s: Find %{public}s failed", __func__, CHANGED_TYPE.c_str());
184 return;
185 }
186
187 for (auto &item : changeEvent->second) {
188 CHKPC(item);
189 CHKPC(item->env_);
190 auto reportData = std::make_shared<AniUtil::ReportData>();
191 if (reportData == nullptr) {
192 MMI_HILOGE("%{public}s: Memory allocation failed", __func__);
193 return;
194 }
195 reportData->deviceId = deviceId;
196 reportData->ref = item->callback_;
197 auto task = [reportData, this] () { EmitAddedDeviceEvent(reportData); };
198 PostMainThreadTask(task);
199 }
200 }
201
OnDeviceRemoved(int32_t deviceId,const std::string & type)202 void AniEventTarget::OnDeviceRemoved(int32_t deviceId, const std::string &type)
203 {
204 CALL_DEBUG_ENTER;
205 std::lock_guard<std::mutex> guard(mutex_);
206 auto changeEvent = devListener_.find(CHANGED_TYPE);
207 if (changeEvent == devListener_.end()) {
208 MMI_HILOGE("%{public}s: Find %{public}s failed", __func__, CHANGED_TYPE.c_str());
209 return;
210 }
211 for (auto &item : changeEvent->second) {
212 CHKPC(item);
213 CHKPC(item->env_);
214 std::shared_ptr<AniUtil::ReportData> reportData = std::make_shared<AniUtil::ReportData>();
215 if (reportData == nullptr) {
216 MMI_HILOGE("%{public}s: Memory allocation failed", __func__);
217 return;
218 }
219 reportData->deviceId = deviceId;
220 reportData->ref = item->callback_;
221 auto task = [reportData, this] () { EmitRemoveDeviceEvent(reportData); };
222 PostMainThreadTask(task);
223 }
224 }
225
AddListener(ani_env * env,const std::string & type,ani_object handle)226 void AniEventTarget::AddListener(ani_env *env, const std::string &type, ani_object handle)
227 {
228 CALL_DEBUG_ENTER;
229 std::lock_guard<std::mutex> guard(mutex_);
230 auto it = devListener_.find(type);
231 if (it == devListener_.end()) {
232 MMI_HILOGE("%{public}s: Find %{public}s failed", __func__, type.c_str());
233 return;
234 }
235
236 auto monitor = std::make_unique<AniUtil::CallbackInfo>();
237 monitor->env_ = env;
238 if (!monitor->SetCallback(handle)) {
239 return;
240 }
241
242 for (const auto &iter : it->second) {
243 CHKPC(iter);
244 if (AniUtil::IsSameHandle(env, monitor->callback_, iter->env_, iter->callback_)) {
245 MMI_HILOGW("The handle already exists");
246 return;
247 }
248 }
249
250 it->second.push_back(std::move(monitor));
251 if (!isListeningProcess_) {
252 isListeningProcess_ = true;
253 InputManager::GetInstance()->RegisterDevListener("change", shared_from_this());
254 }
255 }
256
ResetEnv()257 void AniEventTarget::ResetEnv()
258 {
259 CALL_DEBUG_ENTER;
260 std::lock_guard<std::mutex> guard(mutex_);
261 devListener_.clear();
262 InputManager::GetInstance()->UnregisterDevListener("change", shared_from_this());
263 }
264 } // namespace MMI
265 } // namespace OHOS
266