1 /*
2 * Copyright (C) 2022-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 "napi_accessibility_extension.h"
17
18 #include <uv.h>
19 #include "accessible_ability_client.h"
20 #include "ability_info.h"
21 #include "hilog_wrapper.h"
22 #include "js_runtime.h"
23 #include "js_runtime_utils.h"
24 #include "napi_accessibility_event_info.h"
25 #include "napi_accessibility_extension_context.h"
26 #include "accessibility_utils.h"
27 #include "napi/native_api.h"
28 #include "napi/native_node_api.h"
29 #include "napi_accessibility_element.h"
30 #include "api_reporter_helper.h"
31
32 using namespace OHOS::AbilityRuntime;
33 using namespace OHOS::AccessibilityNapi;
34
35 namespace OHOS {
36 namespace Accessibility {
37 namespace {
38 constexpr int64_t VIRTUAL_COMPONENT_ID = -1;
39 template <typename T>
DeleteAndNullify(T * & ptr)40 void DeleteAndNullify(T*& ptr)
41 {
42 if (ptr) {
43 delete ptr;
44 ptr = nullptr;
45 }
46 }
47 }
Create(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)48 NAccessibilityExtension* NAccessibilityExtension::Create(const std::unique_ptr<AbilityRuntime::Runtime>& runtime)
49 {
50 HILOG_INFO();
51 return new(std::nothrow) NAccessibilityExtension(static_cast<AbilityRuntime::JsRuntime&>(*runtime));
52 }
53
NAccessibilityExtension(AbilityRuntime::JsRuntime & jsRuntime)54 NAccessibilityExtension::NAccessibilityExtension(AbilityRuntime::JsRuntime& jsRuntime) : jsRuntime_(jsRuntime)
55 {
56 listener_ = std::make_shared<AbilityListener>(*this);
57
58 HandleScope handleScope(jsRuntime_);
59 env_ = jsRuntime_.GetNapiEnv();
60 }
61
~NAccessibilityExtension()62 NAccessibilityExtension::~NAccessibilityExtension()
63 {
64 jsRuntime_.FreeNativeReference(std::move(jsObj_));
65 }
66
OpenScope(napi_env env)67 napi_handle_scope OpenScope(napi_env env)
68 {
69 napi_handle_scope scope = nullptr;
70 NAPI_CALL(env, napi_open_handle_scope(env, &scope));
71 return scope;
72 }
73
Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord> & record,const std::shared_ptr<AppExecFwk::OHOSApplication> & application,std::shared_ptr<AppExecFwk::AbilityHandler> & handler,const sptr<IRemoteObject> & token)74 void NAccessibilityExtension::Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord> &record,
75 const std::shared_ptr<AppExecFwk::OHOSApplication> &application,
76 std::shared_ptr<AppExecFwk::AbilityHandler> &handler, const sptr<IRemoteObject> &token)
77 {
78 HILOG_INFO();
79 AccessibilityExtension::Init(record, application, handler, token);
80 std::string srcPath = "";
81 std::string moduleName = "";
82 if (!GetSrcPathAndModuleName(srcPath, moduleName)) {
83 return;
84 }
85 jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
86 abilityInfo_->compileMode == CompileMode::ES_MODULE);
87 if (!jsObj_) {
88 HILOG_ERROR("Failed to get jsObj_");
89 return;
90 }
91 napi_value obj = jsObj_->GetNapiValue();
92 if (!obj) {
93 HILOG_ERROR("Failed to get NAccessibilityExtension object");
94 return;
95 }
96
97 auto context = GetContext();
98 if (!context) {
99 HILOG_ERROR("Failed to get context");
100 return;
101 }
102 napi_value contextObj = CreateJsAccessibilityExtensionContext(env_, context);
103 auto shellContextRef = jsRuntime_.LoadSystemModule("application.AccessibilityExtensionContext", &contextObj, 1);
104 if (!shellContextRef) {
105 HILOG_ERROR("shellContextRef is nullptr.");
106 return;
107 }
108 contextObj = shellContextRef->GetNapiValue();
109 context->Bind(jsRuntime_, shellContextRef.release());
110 napi_set_named_property(env_, obj, "context", contextObj);
111
112 if (!contextObj) {
113 HILOG_ERROR("Failed to get accessibility extension native object");
114 return;
115 }
116 auto contextPtr = new std::weak_ptr<AbilityRuntime::Context>(context);
117 napi_status sts = napi_wrap(env_, contextObj, contextPtr,
118 [](napi_env env, void* data, void*) {
119 delete static_cast<std::weak_ptr<AbilityRuntime::Context>*>(data);
120 }, nullptr, nullptr);
121 if (sts != napi_ok) {
122 delete contextPtr;
123 contextPtr = nullptr;
124 HILOG_ERROR("failed to wrap JS object");
125 }
126 NAccessibilityElement::DefineJSAccessibilityElement(env_);
127 }
128
GetSrcPathAndModuleName(std::string & srcPath,std::string & moduleName)129 bool NAccessibilityExtension::GetSrcPathAndModuleName(std::string& srcPath, std::string& moduleName)
130 {
131 if (!Extension::abilityInfo_) {
132 HILOG_ERROR("abilityInfo_ is nullptr");
133 return false;
134 }
135 if (!Extension::abilityInfo_->isModuleJson) {
136 srcPath.append(Extension::abilityInfo_->package);
137 srcPath.append("/assets/js/");
138 if (!Extension::abilityInfo_->srcPath.empty()) {
139 srcPath.append(Extension::abilityInfo_->srcPath);
140 }
141 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
142 } else if (!Extension::abilityInfo_->srcEntrance.empty()) {
143 srcPath.append(Extension::abilityInfo_->moduleName + "/");
144 srcPath.append(Extension::abilityInfo_->srcEntrance);
145 srcPath.erase(srcPath.rfind('.'));
146 srcPath.append(".abc");
147 } else {
148 HILOG_ERROR("Failed to get srcPath");
149 return false;
150 }
151 moduleName = Extension::abilityInfo_->moduleName;
152 moduleName.append("::").append(abilityInfo_->name);
153 HILOG_INFO("moduleName:%{public}s, srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
154 return true;
155 }
156
OnConnect(const AAFwk::Want & want)157 sptr<IRemoteObject> NAccessibilityExtension::OnConnect(const AAFwk::Want &want)
158 {
159 HILOG_INFO();
160 Extension::OnConnect(want);
161 sptr<AccessibleAbilityClient> aaClient = AccessibleAbilityClient::GetInstance();
162 if (!aaClient) {
163 HILOG_ERROR("aaClient is nullptr");
164 return nullptr;
165 }
166 aaClient->RegisterAbilityListener(listener_);
167 return aaClient->GetRemoteObject();
168 }
169
OnAbilityConnected()170 void NAccessibilityExtension::OnAbilityConnected()
171 {
172 HILOG_INFO();
173 #ifdef ACCESSIBILITY_EMULATOR_DEFINED
174 ApiReportHelper reporter("NAccessibilityExtension.OnAbilityConnected");
175 #endif // ACCESSIBILITY_EMULATOR_DEFINED
176 uv_loop_s* loop = nullptr;
177 napi_get_uv_event_loop(env_, &loop);
178 if (loop == nullptr) {
179 HILOG_ERROR("loop is nullptr.");
180 return;
181 }
182 ExtensionCallbackInfo *callbackInfo = new(std::nothrow) ExtensionCallbackInfo();
183 if (!callbackInfo) {
184 HILOG_ERROR("Failed to create callbackInfo.");
185 return;
186 }
187 callbackInfo->extension_ = this;
188 uv_work_t *work = new(std::nothrow) uv_work_t;
189 if (!work) {
190 HILOG_ERROR("Failed to create data.");
191 delete callbackInfo;
192 callbackInfo = nullptr;
193 return;
194 }
195 work->data = static_cast<void*>(callbackInfo);
196
197 int ret = uv_queue_work_with_qos(
198 loop,
199 work,
200 [](uv_work_t *work) {},
201 [](uv_work_t *work, int status) {
202 ExtensionCallbackInfo *data = static_cast<ExtensionCallbackInfo*>(work->data);
203 data->extension_->CallObjectMethod("onConnect");
204 data->extension_->CallObjectMethod("onAccessibilityConnect");
205 delete data;
206 data = nullptr;
207 delete work;
208 work = nullptr;
209 },
210 uv_qos_user_initiated);
211 if (ret) {
212 HILOG_ERROR("Failed to execute OnAbilityConnected work queue");
213 delete callbackInfo;
214 callbackInfo = nullptr;
215 delete work;
216 work = nullptr;
217 }
218 HILOG_INFO("end.");
219 }
220
OnAbilityDisconnected()221 void NAccessibilityExtension::OnAbilityDisconnected()
222 {
223 HILOG_INFO();
224 #ifdef ACCESSIBILITY_EMULATOR_DEFINED
225 ApiReportHelper reporter("NAccessibilityExtension.OnAbilityDisconnected");
226 #endif // ACCESSIBILITY_EMULATOR_DEFINED
227 uv_loop_s* loop = nullptr;
228 napi_get_uv_event_loop(env_, &loop);
229 if (loop == nullptr) {
230 HILOG_ERROR("loop is nullptr.");
231 return;
232 }
233 ExtensionCallbackInfo *callbackInfo = new(std::nothrow) ExtensionCallbackInfo();
234 if (!callbackInfo) {
235 HILOG_ERROR("Failed to create callbackInfo.");
236 return;
237 }
238 callbackInfo->extension_ = this;
239 uv_work_t *work = new(std::nothrow) uv_work_t;
240 if (!work) {
241 HILOG_ERROR("Failed to create data.");
242 delete callbackInfo;
243 callbackInfo = nullptr;
244 return;
245 }
246 work->data = static_cast<void*>(callbackInfo);
247 ffrt::future syncFuture = callbackInfo->syncPromise_.get_future();
248
249 int ret = uv_queue_work_with_qos(
250 loop,
251 work,
252 [](uv_work_t *work) {},
253 [](uv_work_t *work, int status) {
254 ExtensionCallbackInfo *data = static_cast<ExtensionCallbackInfo*>(work->data);
255 data->extension_->CallObjectMethod("onDisconnect");
256 data->extension_->CallObjectMethod("onAccessibilityDisconnect");
257 data->syncPromise_.set_value();
258 delete data;
259 data = nullptr;
260 delete work;
261 work = nullptr;
262 },
263 uv_qos_user_initiated);
264 if (ret) {
265 HILOG_ERROR("Failed to execute OnAbilityDisconnected work queue");
266 callbackInfo->syncPromise_.set_value();
267 delete callbackInfo;
268 callbackInfo = nullptr;
269 delete work;
270 work = nullptr;
271 }
272 syncFuture.get();
273 HILOG_INFO("end.");
274 }
275
GetElement(const AccessibilityEventInfo & eventInfo)276 std::shared_ptr<AccessibilityElement> NAccessibilityExtension::GetElement(const AccessibilityEventInfo& eventInfo)
277 {
278 HILOG_DEBUG();
279
280 sptr<AccessibleAbilityClient> aaClient = AccessibleAbilityClient::GetInstance();
281 if (!aaClient) {
282 return nullptr;
283 }
284 int64_t componentId = eventInfo.GetAccessibilityId();
285 int32_t windowId = eventInfo.GetWindowId();
286 std::shared_ptr<AccessibilityElement> element = nullptr;
287 HILOG_DEBUG("GetElement componentId: %{public}" PRId64 ", windowId: %{public}d, eventType: %{public}d",
288 componentId, windowId, eventInfo.GetEventType());
289 if (componentId >= 0) {
290 std::shared_ptr<AccessibilityElementInfo> elementInfo =
291 std::make_shared<AccessibilityElementInfo>(eventInfo.GetElementInfo());
292 element = std::make_shared<AccessibilityElement>(elementInfo);
293 } else if (windowId > 0) {
294 std::shared_ptr<AccessibilityWindowInfo> windowInfo = std::make_shared<AccessibilityWindowInfo>();
295 if (aaClient->GetWindow(windowId, *windowInfo) == RET_OK) {
296 element = std::make_shared<AccessibilityElement>(windowInfo);
297 }
298 } else {
299 std::shared_ptr<AccessibilityElementInfo> elementInfo = std::make_shared<AccessibilityElementInfo>();
300 std::string inspectorKey = eventInfo.GetInspectorKey();
301 RetError ret = RET_ERR_FAILED;
302 AccessibilityElementInfo accessibilityElementInfo;
303 if ((eventInfo.GetEventType() == TYPE_VIEW_REQUEST_FOCUS_FOR_ACCESSIBILITY ||
304 eventInfo.GetEventType() == TYPE_VIEW_REQUEST_FOCUS_FOR_ACCESSIBILITY_NOT_INTERRUPT) &&
305 inspectorKey != "") {
306 ret = aaClient->SearchElementInfoByInspectorKey(inspectorKey, accessibilityElementInfo);
307 }
308 if (ret == RET_OK) {
309 elementInfo = std::make_shared<AccessibilityElementInfo>(accessibilityElementInfo);
310 elementInfo->SetBundleName(eventInfo.GetBundleName());
311 elementInfo->SetTriggerAction(eventInfo.GetTriggerAction());
312 } else {
313 CreateElementInfoByEventInfo(eventInfo, elementInfo);
314 }
315 element = std::make_shared<AccessibilityElement>(elementInfo);
316 }
317 return element;
318 }
319
CreateElementInfoByEventInfo(const AccessibilityEventInfo & eventInfo,const std::shared_ptr<AccessibilityElementInfo> & elementInfo)320 void NAccessibilityExtension::CreateElementInfoByEventInfo(const AccessibilityEventInfo& eventInfo,
321 const std::shared_ptr<AccessibilityElementInfo> &elementInfo)
322 {
323 HILOG_DEBUG();
324 if (!elementInfo) {
325 HILOG_ERROR("elementInfo is nullptr");
326 return;
327 }
328 if (elementInfo->GetAccessibilityId() < 0) {
329 elementInfo->SetComponentId(VIRTUAL_COMPONENT_ID);
330 }
331 elementInfo->SetBundleName(eventInfo.GetBundleName());
332 elementInfo->SetComponentType(eventInfo.GetComponentType());
333 elementInfo->SetPageId(eventInfo.GetPageId());
334 elementInfo->SetDescriptionInfo(eventInfo.GetDescription());
335 elementInfo->SetTriggerAction(eventInfo.GetTriggerAction());
336 elementInfo->SetTextMovementStep(eventInfo.GetTextMovementStep());
337 elementInfo->SetContentList(eventInfo.GetContentList());
338 elementInfo->SetLatestContent(eventInfo.GetLatestContent());
339 elementInfo->SetBeginIndex(eventInfo.GetBeginIndex());
340 elementInfo->SetCurrentIndex(eventInfo.GetCurrentIndex());
341 elementInfo->SetEndIndex(eventInfo.GetEndIndex());
342 elementInfo->SetItemCounts(eventInfo.GetItemCounts());
343 }
344
ConvertAccessibilityElementToJS(napi_env env,napi_value objEvent,napi_value objEventInfo,const std::shared_ptr<AccessibilityElement> & element)345 void ConvertAccessibilityElementToJS(napi_env env, napi_value objEvent, napi_value objEventInfo,
346 const std::shared_ptr<AccessibilityElement>& element)
347 {
348 HILOG_DEBUG();
349 if (!element) {
350 HILOG_DEBUG("No element information.");
351 return;
352 }
353 AccessibilityElement* pAccessibilityElement = new(std::nothrow) AccessibilityElement(*element);
354 if (!pAccessibilityElement) {
355 HILOG_ERROR("Failed to create AccessibilityElement.");
356 return;
357 }
358 auto closeScope = [env](napi_handle_scope scope) { napi_close_handle_scope(env, scope); };
359 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scopes(OpenScope(env), closeScope);
360 napi_value nTargetObject = nullptr;
361 napi_value constructor = nullptr;
362 napi_get_reference_value(env, NAccessibilityElement::consRef_, &constructor);
363 napi_new_instance(env, constructor, 0, nullptr, &nTargetObject);
364 // Bind js object to a Native object
365 napi_status sts = napi_wrap(
366 env,
367 nTargetObject,
368 pAccessibilityElement,
369 [](napi_env env, void* data, void* hint) {
370 AccessibilityElement* info = static_cast<AccessibilityElement*>(data);
371 delete info;
372 info = nullptr;
373 },
374 nullptr,
375 nullptr);
376 if (sts != napi_ok) {
377 delete pAccessibilityElement;
378 pAccessibilityElement = nullptr;
379 HILOG_ERROR("failed to wrap JS object");
380 }
381 HILOG_DEBUG("napi_wrap status: %{public}d", (int)sts);
382 napi_set_named_property(env, objEventInfo, "target", nTargetObject);
383 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, objEvent, "target", nTargetObject));
384 }
385
SetNapiEventInfoIntProperty(napi_env env,const char * property,int64_t value,napi_value & napiEventInfo)386 napi_status SetNapiEventInfoIntProperty(napi_env env, const char *property, int64_t value, napi_value &napiEventInfo)
387 {
388 if (property == nullptr) {
389 HILOG_ERROR("property is null");
390 return napi_invalid_arg;
391 }
392 napi_value nValue = nullptr;
393 napi_status status = napi_create_int64(env, value, &nValue);
394 if (status != napi_ok) {
395 return status;
396 }
397 return napi_set_named_property(env, napiEventInfo, property, nValue);
398 }
399
SetEventInfoStrProperty(napi_env env,const char * property,std::string & value,napi_value & napiEventInfo)400 napi_status SetEventInfoStrProperty(napi_env env, const char *property, std::string &value, napi_value &napiEventInfo)
401 {
402 if (property == nullptr) {
403 HILOG_ERROR("property is null");
404 return napi_invalid_arg;
405 }
406 napi_value nValue = nullptr;
407 napi_status status = napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &nValue);
408 if (status != napi_ok) {
409 HILOG_ERROR();
410 return status;
411 }
412 return napi_set_named_property(env, napiEventInfo, property, nValue);
413 }
414
GetEventExtraInfo(const AccessibilityEventInfo & eventInfo)415 std::string NAccessibilityExtension::GetEventExtraInfo(const AccessibilityEventInfo& eventInfo)
416 {
417 std::map<std::string, std::string> mapValIsStr = eventInfo.GetExtraEvent().GetExtraEventInfoValueStr();
418 nlohmann::json extraInfoValue;
419 for (auto &iterStr : mapValIsStr) {
420 extraInfoValue[iterStr.first] = iterStr.second;
421 }
422 HILOG_DEBUG("GetEventExtraInfo extraInfoValue is [%{public}s]", extraInfoValue.dump().c_str());
423 return extraInfoValue.dump().c_str();
424 }
425
OnAccessibilityEventExec(uv_work_t * work,uv_loop_t * loop)426 int NAccessibilityExtension::OnAccessibilityEventExec(uv_work_t *work, uv_loop_t *loop)
427 {
428 if (loop == nullptr || work == nullptr) {
429 return RET_ERR_FAILED;
430 }
431 int ret = uv_queue_work_with_qos(
432 loop,
433 work,
434 [](uv_work_t *work) {},
435 [](uv_work_t *work, int status) {
436 AccessibilityEventTypeCallbackInfo *data = static_cast<AccessibilityEventTypeCallbackInfo*>(work->data);
437 napi_env env = data->env_;
438 auto closeScope = [env](napi_handle_scope scope) {
439 napi_close_handle_scope(env, scope);
440 };
441 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scopes(OpenScope(data->env_), closeScope);
442 napi_value napiEvent = nullptr;
443 napi_value napiEventInfo = nullptr;
444 napi_create_object(data->env_, &napiEvent);
445 napi_create_object(data->env_, &napiEventInfo);
446
447 do {
448 if (SetEventInfoStrProperty(data->env_, "eventType", data->eventType_, napiEvent) != napi_ok) {
449 GET_AND_THROW_LAST_ERROR((data->env_));
450 break;
451 }
452 if (SetNapiEventInfoIntProperty(data->env_, "eventType",
453 static_cast<int64_t>(data->AccessibilityEventType_), napiEventInfo) != napi_ok) {
454 GET_AND_THROW_LAST_ERROR((data->env_));
455 break;
456 }
457 if (SetNapiEventInfoIntProperty(data->env_, "timeStamp", data->timeStamp_, napiEvent) != napi_ok) {
458 GET_AND_THROW_LAST_ERROR((data->env_));
459 break;
460 }
461 if (SetNapiEventInfoIntProperty(data->env_, "timestamp", data->timeStamp_, napiEventInfo) != napi_ok) {
462 GET_AND_THROW_LAST_ERROR((data->env_));
463 break;
464 }
465 if (SetNapiEventInfoIntProperty(data->env_, "elementId", data->elementId_, napiEvent) != napi_ok) {
466 GET_AND_THROW_LAST_ERROR((data->env_));
467 break;
468 }
469 if (SetEventInfoStrProperty(data->env_, "textAnnouncedForAccessibility",
470 data->textAnnouncedForAccessibility_, napiEvent) != napi_ok) {
471 GET_AND_THROW_LAST_ERROR((data->env_));
472 break;
473 }
474 if (SetEventInfoStrProperty(data->env_, "extraInfo", data->extraInfo_, napiEvent) != napi_ok) {
475 GET_AND_THROW_LAST_ERROR((data->env_));
476 break;
477 }
478 if (SetEventInfoStrProperty(data->env_, "extraInfo", data->extraInfo_, napiEventInfo) != napi_ok) {
479 GET_AND_THROW_LAST_ERROR((data->env_));
480 break;
481 }
482
483 ConvertAccessibilityElementToJS(data->env_, napiEvent, napiEventInfo, data->element_);
484 napi_value eventArgv[] = {napiEvent};
485 data->extension_->CallObjectMethod("onAccessibilityEvent", eventArgv, 1);
486 napi_value eventInfoArgv[] = {napiEventInfo};
487 data->extension_->CallObjectMethod("onAccessibilityEventInfo", eventInfoArgv, 1);
488 } while (0);
489 if (data != nullptr) {
490 delete data;
491 data = nullptr;
492 }
493 if (work != nullptr) {
494 delete work;
495 work = nullptr;
496 }
497 },
498 uv_qos_user_initiated);
499 return ret;
500 }
501
OnAccessibilityEvent(const AccessibilityEventInfo & eventInfo)502 void NAccessibilityExtension::OnAccessibilityEvent(const AccessibilityEventInfo& eventInfo)
503 {
504 HILOG_INFO();
505 std::string strType = "";
506 ConvertEventTypeToString(eventInfo, strType);
507 if (strType.empty()) {
508 HILOG_DEBUG("eventType is invalid.");
509 return;
510 }
511 uv_loop_s* loop = nullptr;
512 napi_get_uv_event_loop(env_, &loop);
513 AccessibilityEventTypeCallbackInfo *callbackInfo = new(std::nothrow) AccessibilityEventTypeCallbackInfo();
514 if (!callbackInfo) {
515 HILOG_ERROR("Failed to create callbackInfo.");
516 return;
517 }
518 std::shared_ptr<AccessibilityElement> element = GetElement(eventInfo);
519 callbackInfo->env_ = env_;
520 callbackInfo->extension_ = this;
521 callbackInfo->eventType_ = strType;
522 callbackInfo->AccessibilityEventType_ = CovertStringToAccessibilityEventType(eventInfo, strType);
523 callbackInfo->timeStamp_ = eventInfo.GetTimeStamp();
524 callbackInfo->element_ = element;
525 callbackInfo->elementId_ = eventInfo.GetRequestFocusElementId();
526 callbackInfo->textAnnouncedForAccessibility_ = eventInfo.GetTextAnnouncedForAccessibility();
527 callbackInfo->extraInfo_ = GetEventExtraInfo(eventInfo);
528 uv_work_t *work = new(std::nothrow) uv_work_t;
529 if (!work) {
530 HILOG_ERROR("Failed to create data.");
531 delete callbackInfo;
532 callbackInfo = nullptr;
533 return;
534 }
535 work->data = static_cast<void*>(callbackInfo);
536
537 if (OnAccessibilityEventExec(work, loop)) {
538 HILOG_ERROR("Failed to execute OnAccessibilityEvent work queue");
539 delete callbackInfo;
540 callbackInfo = nullptr;
541 delete work;
542 work = nullptr;
543 }
544 }
545
OnKeyPressEventExec(uv_work_t * work,uv_loop_t * loop)546 int NAccessibilityExtension::OnKeyPressEventExec(uv_work_t *work, uv_loop_t *loop)
547 {
548 if (loop == nullptr || work == nullptr) {
549 HILOG_ERROR("loop or work is nullptr.");
550 return RET_ERR_FAILED;
551 }
552 int ret = uv_queue_work_with_qos(
553 loop,
554 work,
555 [](uv_work_t *work) {},
556 [](uv_work_t *work, int status) {
557 KeyEventCallbackInfo *data = static_cast<KeyEventCallbackInfo*>(work->data);
558 napi_env env = data->env_;
559 auto closeScope = [env](napi_handle_scope scope) {
560 napi_close_handle_scope(env, scope);
561 };
562 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scopes(
563 OpenScope(data->env_), closeScope);
564 napi_value napiEventInfo = nullptr;
565 if (napi_create_object(data->env_, &napiEventInfo) != napi_ok) {
566 HILOG_ERROR("Create keyEvent object failed.");
567 data->syncPromise_.set_value(false);
568 DeleteAndNullify(data);
569 DeleteAndNullify(work);
570 return;
571 }
572 ConvertKeyEventToJS(data->env_, napiEventInfo, data->keyEvent_);
573 napi_value argv[] = {napiEventInfo};
574 napi_value nativeResult = data->extension_->CallObjectMethod("onKeyEvent", argv, 1);
575 napi_value accessibilityNativeResult =
576 data->extension_->CallObjectMethod("onAccessibilityKeyEvent", argv, 1);
577
578 // Unwrap result
579 bool result = false;
580 bool accessibilityResult = false;
581 if (!ConvertFromJsValue(data->env_, nativeResult, result) &&
582 !ConvertFromJsValue(data->env_, accessibilityNativeResult, accessibilityResult)) {
583 HILOG_ERROR("ConvertFromJsValue failed");
584 data->syncPromise_.set_value(false);
585 DeleteAndNullify(data);
586 DeleteAndNullify(work);
587 return;
588 }
589 HILOG_INFO("OnKeyPressEvent result = %{public}d", result);
590 data->syncPromise_.set_value(result);
591 DeleteAndNullify(data);
592 DeleteAndNullify(work);
593 },
594 uv_qos_user_initiated);
595 return ret;
596 }
597
OnKeyPressEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent)598 bool NAccessibilityExtension::OnKeyPressEvent(const std::shared_ptr<MMI::KeyEvent> &keyEvent)
599 {
600 HILOG_INFO();
601 uv_loop_s* loop = nullptr;
602 napi_get_uv_event_loop(env_, &loop);
603 KeyEventCallbackInfo *callbackInfo = new(std::nothrow) KeyEventCallbackInfo();
604 if (!callbackInfo) {
605 HILOG_ERROR("Failed to create callbackInfo.");
606 return false;
607 }
608 callbackInfo->env_ = env_;
609 callbackInfo->keyEvent_ = MMI::KeyEvent::Clone(keyEvent);
610 callbackInfo->extension_ = this;
611 uv_work_t *work = new(std::nothrow) uv_work_t;
612 if (!work) {
613 HILOG_ERROR("Failed to create data.");
614 delete callbackInfo;
615 callbackInfo = nullptr;
616 return false;
617 }
618 work->data = static_cast<void*>(callbackInfo);
619 ffrt::future syncFuture = callbackInfo->syncPromise_.get_future();
620
621 if (OnKeyPressEventExec(work, loop)) {
622 HILOG_ERROR("Failed to execute OnKeyPressEvent work queue");
623 callbackInfo->syncPromise_.set_value(false);
624 delete callbackInfo;
625 callbackInfo = nullptr;
626 delete work;
627 work = nullptr;
628 }
629 bool callbackResult = syncFuture.get();
630 HILOG_INFO("OnKeyPressEvent callbackResult = %{public}d", callbackResult);
631 return callbackResult;
632 }
633
OnKeyPressEventCompleteCallback(uv_work_t * work,int status)634 void NAccessibilityExtension::OnKeyPressEventCompleteCallback(uv_work_t* work, int status)
635 {
636 KeyEventCallbackInfo *data = static_cast<KeyEventCallbackInfo*>(work->data);
637 napi_env env = data->env_;
638 auto closeScope = [env](napi_handle_scope scope) {
639 napi_close_handle_scope(env, scope);
640 };
641 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scopes(OpenScope(data->env_), closeScope);
642 napi_value napiEventInfo = nullptr;
643 if (napi_create_object(data->env_, &napiEventInfo) != napi_ok) {
644 HILOG_ERROR("Create keyEvent object failed.");
645 data->syncPromise_.set_value(false);
646 delete data;
647 data = nullptr;
648 delete work;
649 work = nullptr;
650 return;
651 }
652 ConvertKeyEventToJS(data->env_, napiEventInfo, data->keyEvent_);
653 napi_value argv[] = {napiEventInfo};
654 napi_value napiResult = data->extension_->CallObjectMethod("onKeyEvent", argv, 1);
655 napi_value accessibilityNativeResult = data->extension_->CallObjectMethod("onAccessibilityKeyEvent", argv, 1);
656
657 // Unwrap result
658 bool result = false;
659 bool accessibilityResult = false;
660 if (!ConvertFromJsValue(data->env_, napiResult, result) &&
661 !ConvertFromJsValue(data->env_, accessibilityNativeResult, accessibilityResult)) {
662 HILOG_ERROR("ConvertFromJsValue failed");
663 data->syncPromise_.set_value(false);
664 delete data;
665 data = nullptr;
666 delete work;
667 work = nullptr;
668 return;
669 }
670 HILOG_INFO("OnKeyPressEvent result = %{public}d", result);
671 data->syncPromise_.set_value(result);
672 delete data;
673 data = nullptr;
674 delete work;
675 work = nullptr;
676 }
677
CallObjectMethod(const char * name,napi_value * argv,size_t argc)678 napi_value NAccessibilityExtension::CallObjectMethod(const char* name, napi_value* argv, size_t argc)
679 {
680 HILOG_INFO("name:%{public}s", name);
681 if (!jsObj_) {
682 HILOG_ERROR("jsObj_ is nullptr");
683 return nullptr;
684 }
685
686 napi_value obj = jsObj_->GetNapiValue();
687 if (!obj) {
688 HILOG_ERROR("Failed to get AccessibilityExtension object");
689 return nullptr;
690 }
691
692 napi_value method = nullptr;
693 if (napi_get_named_property(env_, obj, name, &method) != napi_ok) {
694 HILOG_ERROR("Failed to get '%{public}s' from AccessibilityExtension object", name);
695 return nullptr;
696 }
697
698 napi_value result = nullptr;
699 if (napi_call_function(env_, obj, method, argc, argv, &result) != napi_ok) {
700 HILOG_ERROR("call function failed");
701 return nullptr;
702 }
703
704 return result;
705 }
706 } // namespace Accessibility
707 } // namespace OHOS