• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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