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