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