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