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