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