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_context.h"
17
18 #include <uv.h>
19 #include "display_manager.h"
20 #include "js_extension_context.h"
21 #include "js_runtime_utils.h"
22 #include "hilog_wrapper.h"
23 #include "napi_accessibility_element.h"
24 #include "accessibility_utils.h"
25 #include "napi_common_want.h"
26 #include "napi_common_start_options.h"
27 #include "api_reporter_helper.h"
28
29 using namespace OHOS::AbilityRuntime;
30 using namespace OHOS::AccessibilityNapi;
31
32 namespace OHOS {
33 namespace Accessibility {
34 namespace {
ConvertAccessibilityWindowInfoToJS(napi_env env,napi_value result,const AccessibilityWindowInfo & accessibilityWindowInfo)35 static void ConvertAccessibilityWindowInfoToJS(
36 napi_env env, napi_value result, const AccessibilityWindowInfo& accessibilityWindowInfo)
37 {
38 // Bind js object to a Native object
39 std::shared_ptr<AccessibilityWindowInfo> windowInfo =
40 std::make_shared<AccessibilityWindowInfo>(accessibilityWindowInfo);
41 AccessibilityElement* pAccessibilityElement = new(std::nothrow) AccessibilityElement(windowInfo);
42 if (pAccessibilityElement == nullptr) {
43 HILOG_ERROR("Failed to create work.");
44 return;
45 }
46
47 napi_status sts = napi_wrap(
48 env,
49 result,
50 pAccessibilityElement,
51 [](napi_env env, void* data, void* hint) {
52 AccessibilityElement* info = static_cast<AccessibilityElement*>(data);
53 delete info;
54 info = nullptr;
55 },
56 nullptr,
57 nullptr);
58 if (sts != napi_ok) {
59 delete pAccessibilityElement;
60 pAccessibilityElement = nullptr;
61 HILOG_ERROR("failed to wrap JS object");
62 }
63 HILOG_DEBUG("napi_wrap status: %{public}d", (int)sts);
64 }
65
ConvertAccessibilityWindowInfosToJS(napi_env env,napi_value result,const std::vector<AccessibilityWindowInfo> & accessibilityWindowInfos)66 static void ConvertAccessibilityWindowInfosToJS(
67 napi_env env, napi_value result, const std::vector<AccessibilityWindowInfo>& accessibilityWindowInfos)
68 {
69 HILOG_DEBUG();
70 size_t idx = 0;
71
72 if (accessibilityWindowInfos.empty()) {
73 return;
74 }
75 napi_value constructor = nullptr;
76 napi_get_reference_value(env, NAccessibilityElement::consRef_, &constructor);
77
78 for (const auto& windowInfo : accessibilityWindowInfos) {
79 napi_value obj = nullptr;
80 napi_new_instance(env, constructor, 0, nullptr, &obj);
81 ConvertAccessibilityWindowInfoToJS(env, obj, windowInfo);
82 napi_set_element(env, result, idx, obj);
83 idx++;
84 }
85 }
86
IsNapiFunction(napi_env env,napi_value param)87 static bool IsNapiFunction(napi_env env, napi_value param)
88 {
89 napi_valuetype valueType = napi_null;
90 napi_status status = napi_typeof(env, param, &valueType);
91 if (status != napi_ok) {
92 HILOG_ERROR("napi_typeof error and status is %{public}d", status);
93 return false;
94 }
95
96 if (valueType != napi_function) {
97 HILOG_ERROR("SubscribeState args[PARAM1] format is wrong");
98 return false;
99 }
100 return true;
101 }
102
IsNapiBool(napi_env env,napi_value param)103 static bool IsNapiBool(napi_env env, napi_value param)
104 {
105 napi_valuetype valuetype = napi_null;
106 napi_status status = napi_typeof(env, param, &valuetype);
107 if (status != napi_ok) {
108 HILOG_ERROR("napi_typeof error and status is %{public}d", status);
109 return false;
110 }
111
112 if (valuetype != napi_boolean) {
113 HILOG_ERROR("Wrong argument type. Boolean expected.");
114 return false;
115 }
116 return true;
117 }
118
IsNapiNumber(napi_env env,napi_value param)119 static bool IsNapiNumber(napi_env env, napi_value param)
120 {
121 napi_valuetype valuetype = napi_null;
122 napi_status status = napi_typeof(env, param, &valuetype);
123 if (status != napi_ok) {
124 HILOG_ERROR("napi_typeof error and status is %{public}d", status);
125 return false;
126 }
127
128 if (valuetype != napi_number) {
129 HILOG_ERROR("Wrong argument type. uint32 expected.");
130 return false;
131 }
132 return true;
133 }
134
GetLastParamForTwo(napi_env env,NapiCallbackInfo & info,napi_value & lastParam,bool & isAccessibilityFocus)135 static void GetLastParamForTwo(napi_env env, NapiCallbackInfo& info, napi_value& lastParam,
136 bool& isAccessibilityFocus)
137 {
138 if (info.argv[PARAM0] != nullptr && info.argv[PARAM1] != nullptr &&
139 IsNapiBool(env, info.argv[PARAM0]) && IsNapiFunction(env, info.argv[PARAM1])) {
140 lastParam = ConvertFromJsValue(env, info.argv[PARAM0], isAccessibilityFocus) ?
141 info.argv[PARAM1] : nullptr;
142 } else if (info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) {
143 HILOG_INFO("argc is more than two, use callback: situation 1");
144 lastParam = info.argv[PARAM1];
145 } else if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
146 HILOG_INFO("argc is more than two, use callback: situation 2");
147 lastParam = info.argv[PARAM0];
148 } else if (info.argv[PARAM0] != nullptr && IsNapiBool(env, info.argv[PARAM0])) {
149 HILOG_INFO("argc is more than two, use promise: situation 3");
150 lastParam = nullptr;
151 ConvertFromJsValue(env, info.argv[PARAM0], isAccessibilityFocus);
152 } else {
153 lastParam = nullptr;
154 HILOG_INFO("argc is more than two, use promise");
155 }
156 }
157
CheckStartAbilityInputParam(napi_env env,NapiCallbackInfo & info,AAFwk::Want & want)158 static bool CheckStartAbilityInputParam(napi_env env, NapiCallbackInfo& info,
159 AAFwk::Want& want)
160 {
161 if (info.argc < ARGS_SIZE_ONE) {
162 return false;
163 }
164 if (!AppExecFwk::UnwrapWant(env, info.argv[PARAM0], want)) {
165 return false;
166 }
167 if (!want.HasParameter(Want::PARAM_BACK_TO_OTHER_MISSION_STACK)) {
168 want.SetParam(Want::PARAM_BACK_TO_OTHER_MISSION_STACK, true);
169 }
170 return true;
171 }
172
173 class NAccessibilityExtensionContext final {
174 public:
NAccessibilityExtensionContext(const std::shared_ptr<AccessibilityExtensionContext> & context)175 explicit NAccessibilityExtensionContext(
176 const std::shared_ptr<AccessibilityExtensionContext>& context) : context_(context) {}
177 ~NAccessibilityExtensionContext() = default;
178
Finalizer(napi_env env,void * data,void * hint)179 static void Finalizer(napi_env env, void* data, void* hint)
180 {
181 HILOG_INFO();
182 std::unique_ptr<NAccessibilityExtensionContext>(static_cast<NAccessibilityExtensionContext*>(data));
183 }
184
SetTargetBundleName(napi_env env,napi_callback_info info)185 static napi_value SetTargetBundleName(napi_env env, napi_callback_info info)
186 {
187 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnSetTargetBundleName);
188 }
189
GetFocusElement(napi_env env,napi_callback_info info)190 static napi_value GetFocusElement(napi_env env, napi_callback_info info)
191 {
192 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGetFocusElement);
193 }
194
GetWindowRootElement(napi_env env,napi_callback_info info)195 static napi_value GetWindowRootElement(napi_env env, napi_callback_info info)
196 {
197 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGetWindowRootElement);
198 }
199
GetWindows(napi_env env,napi_callback_info info)200 static napi_value GetWindows(napi_env env, napi_callback_info info)
201 {
202 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGetWindows);
203 }
204
InjectGesture(napi_env env,napi_callback_info info)205 static napi_value InjectGesture(napi_env env, napi_callback_info info)
206 {
207 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGestureInject);
208 }
209
InjectGestureSync(napi_env env,napi_callback_info info)210 static napi_value InjectGestureSync(napi_env env, napi_callback_info info)
211 {
212 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGestureInjectSync);
213 }
214
StartAbility(napi_env env,napi_callback_info info)215 static napi_value StartAbility(napi_env env, napi_callback_info info)
216 {
217 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnStartAbility);
218 }
219
EnableScreenCurtain(napi_env env,napi_callback_info info)220 static napi_value EnableScreenCurtain(napi_env env, napi_callback_info info)
221 {
222 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnEnableScreenCurtain);
223 }
224
GetElements(napi_env env,napi_callback_info info)225 static napi_value GetElements(napi_env env, napi_callback_info info)
226 {
227 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGetElements);
228 }
229
GetDefaultFocusedElementIds(napi_env env,napi_callback_info info)230 static napi_value GetDefaultFocusedElementIds(napi_env env, napi_callback_info info)
231 {
232 GET_NAPI_INFO_AND_CALL(env, info, NAccessibilityExtensionContext, OnGetDefaultFocusedElementIds);
233 }
234
235 private:
236 std::weak_ptr<AccessibilityExtensionContext> context_;
237
OnSetTargetBundleName(napi_env env,NapiCallbackInfo & info)238 napi_value OnSetTargetBundleName(napi_env env, NapiCallbackInfo& info)
239 {
240 HILOG_INFO();
241 NAccessibilityErrorCode errCode = NAccessibilityErrorCode::ACCESSIBILITY_OK;
242 if (info.argc < ARGS_SIZE_ONE) {
243 HILOG_ERROR("Not enough params");
244 errCode = NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM;
245 }
246
247 std::vector<std::string> targetBundleNames;
248 if (errCode == NAccessibilityErrorCode::ACCESSIBILITY_OK) {
249 if (ConvertJSToStringVec(env, info.argv[PARAM0], targetBundleNames)) {
250 HILOG_INFO("targetBundleNames's size = %{public}zu", targetBundleNames.size());
251 } else {
252 errCode = NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM;
253 }
254 }
255
256 if (errCode == NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM) {
257 HILOG_ERROR("invalid param");
258 napi_throw(env, CreateJsError(env,
259 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
260 ERROR_MESSAGE_PARAMETER_ERROR));
261 return CreateJsUndefined(env);
262 }
263
264 return SetTargetBundleNameCompleteTask(env, targetBundleNames, info);
265 }
266
SetTargetBundleNameCompleteTask(napi_env env,std::vector<std::string> targetBundleNames,NapiCallbackInfo & info)267 napi_value SetTargetBundleNameCompleteTask(napi_env env, std::vector<std::string> targetBundleNames,
268 NapiCallbackInfo& info)
269 {
270 auto ret = std::make_shared<RetError>(RET_OK);
271 NapiAsyncTask::ExecuteCallback execute = [weak = context_, targetBundleNames, ret] () {
272 HILOG_INFO("SetTargetBundleName begin");
273 auto context = weak.lock();
274 if (!context) {
275 HILOG_ERROR("context is released");
276 *ret = RET_ERR_FAILED;
277 return;
278 }
279
280 *ret = context->SetTargetBundleName(targetBundleNames);
281 };
282 NapiAsyncTask::CompleteCallback complete =
283 [ret](napi_env env, NapiAsyncTask& task, int32_t status) {
284 if (*ret == RET_OK) {
285 task.Resolve(env, CreateJsUndefined(env));
286 } else {
287 HILOG_ERROR("set target bundle name failed. ret: %{public}d.", *ret);
288 task.Reject(env, CreateJsError(env,
289 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_SYSTEM_ABNORMALITY),
290 ERROR_MESSAGE_SYSTEM_ABNORMALITY));
291 }
292 };
293
294 napi_value lastParam = (info.argc == ARGS_SIZE_ONE) ? nullptr :
295 ((info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) ? info.argv[PARAM1] : nullptr);
296 napi_value result = nullptr;
297 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::OnSetTargetBundleName",
298 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
299 return result;
300 }
301
OnGetFocusElement(napi_env env,NapiCallbackInfo & info)302 napi_value OnGetFocusElement(napi_env env, NapiCallbackInfo& info)
303 {
304 HILOG_INFO();
305 bool isAccessibilityFocus = false;
306 napi_value lastParam = nullptr;
307 if (info.argc >= ARGS_SIZE_TWO) {
308 GetLastParamForTwo(env, info, lastParam, isAccessibilityFocus);
309 } else if (info.argc == ARGS_SIZE_ONE) {
310 if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
311 lastParam = info.argv[PARAM0];
312 } else {
313 if (info.argv[PARAM0] != nullptr && IsNapiBool(env, info.argv[PARAM0])) {
314 ConvertFromJsValue(env, info.argv[PARAM0], isAccessibilityFocus);
315 }
316 lastParam = nullptr;
317 HILOG_INFO("argc is one, use promise");
318 }
319 } else {
320 lastParam = nullptr;
321 HILOG_INFO("argc is others, use promise");
322 }
323
324 int32_t focus = isAccessibilityFocus ? FOCUS_TYPE_ACCESSIBILITY : FOCUS_TYPE_INPUT;
325 HILOG_DEBUG("focus type is [%{public}d]", focus);
326 return GetFoucusElementCompleteTask(env, focus, lastParam);
327 }
328
GetFoucusElementCompleteTask(napi_env env,int32_t focus,napi_value lastParam)329 napi_value GetFoucusElementCompleteTask(napi_env env, int32_t focus, napi_value lastParam)
330 {
331 auto elementInfo = std::make_shared<OHOS::Accessibility::AccessibilityElementInfo>();
332 auto ret = std::make_shared<RetError>(RET_OK);
333 NapiAsyncTask::ExecuteCallback execute = [weak = context_, elementInfo, focus, ret] () {
334 HILOG_INFO("GetFoucusElement begin");
335 auto context = weak.lock();
336 if (!context) {
337 HILOG_ERROR("context is released");
338 *ret = RET_ERR_FAILED;
339 return;
340 }
341
342 *ret = context->GetFocus(focus, *elementInfo);
343 };
344 NapiAsyncTask::CompleteCallback complete =
345 [ret, elementInfo](napi_env env, NapiAsyncTask& task, int32_t status) {
346 if (*ret == RET_OK) {
347 napi_value constructor = nullptr;
348 napi_get_reference_value(env, NAccessibilityElement::consRef_, &constructor);
349 napi_value napiElementInfo = nullptr;
350 napi_new_instance(env, constructor, 0, nullptr, &napiElementInfo);
351 NAccessibilityElement::ConvertElementInfoToJS(env, napiElementInfo, *elementInfo);
352 task.Resolve(env, napiElementInfo);
353 } else {
354 HILOG_ERROR("Get focus elementInfo failed. ret: %{public}d", *ret);
355 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
356 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
357 }
358 };
359
360 napi_value result = nullptr;
361 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::OnGetFocusElement",
362 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
363 return result;
364 }
365
OnGetWindowRootElement(napi_env env,NapiCallbackInfo & info)366 napi_value OnGetWindowRootElement(napi_env env, NapiCallbackInfo& info)
367 {
368 HILOG_INFO();
369 int32_t windowId = INVALID_WINDOW_ID;
370 bool isActiveWindow = true;
371 napi_value lastParam = nullptr;
372 if (info.argc >= ARGS_SIZE_TWO) {
373 if (info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) {
374 HILOG_INFO("argc is more than two, use callback: situation 1");
375 lastParam = info.argv[PARAM1];
376 } else if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
377 HILOG_INFO("argc is more than two, use callback: situation 2");
378 lastParam = info.argv[PARAM0];
379 } else {
380 lastParam = nullptr;
381 HILOG_INFO("argc is two, use promise");
382 }
383 if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
384 HILOG_INFO("argc is more than two, use promise: situation 3");
385 isActiveWindow = !ConvertFromJsValue(env, info.argv[PARAM0], windowId);
386 }
387 } else if (info.argc == ARGS_SIZE_ONE) {
388 if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
389 lastParam = info.argv[PARAM0];
390 } else if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
391 isActiveWindow = !ConvertFromJsValue(env, info.argv[PARAM0], windowId);
392 lastParam = nullptr;
393 HILOG_INFO("argc is one, use promise");
394 }
395 } else {
396 lastParam = nullptr;
397 HILOG_INFO("argc is others, use promise");
398 }
399 return GetWindowRootElementCompleteTask(env, windowId, isActiveWindow, lastParam);
400 }
401
GetWindowRootElementCompleteTask(napi_env env,int32_t windowId,bool isActiveWindow,napi_value lastParam)402 napi_value GetWindowRootElementCompleteTask(
403 napi_env env, int32_t windowId, bool isActiveWindow, napi_value lastParam)
404 {
405 auto elementInfo = std::make_shared<OHOS::Accessibility::AccessibilityElementInfo>();
406 auto ret = std::make_shared<RetError>(RET_OK);
407 NapiAsyncTask::ExecuteCallback execute = [weak = context_, isActiveWindow, windowId, elementInfo, ret] () {
408 HILOG_INFO("GetWindowRootElement begin");
409 auto context = weak.lock();
410 if (!context) {
411 HILOG_ERROR("context is released");
412 *ret = RET_ERR_FAILED;
413 return;
414 }
415 if (isActiveWindow) {
416 *ret = context->GetRoot(*elementInfo);
417 } else {
418 AccessibilityWindowInfo windowInfo;
419 windowInfo.SetWindowId(windowId);
420 *ret = context->GetRootByWindow(windowInfo, *elementInfo);
421 }
422 };
423
424 NapiAsyncTask::CompleteCallback complete =
425 [ret, elementInfo](napi_env env, NapiAsyncTask& task, int32_t status) {
426 if (*ret == RET_OK) {
427 napi_value constructor = nullptr;
428 napi_get_reference_value(env, NAccessibilityElement::consRef_, &constructor);
429 napi_value napiElementInfo = nullptr;
430 napi_status result = napi_new_instance(env, constructor, 0, nullptr, &napiElementInfo);
431 HILOG_DEBUG("napi_new_instance result is %{public}d", result);
432 NAccessibilityElement::ConvertElementInfoToJS(env, napiElementInfo, *elementInfo);
433 task.Resolve(env, napiElementInfo);
434 } else {
435 HILOG_ERROR("Get root elementInfo failed. ret : %{public}d", *ret);
436 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
437 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
438 }
439 };
440
441 napi_value result = nullptr;
442 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::OnGetWindowRootElement",
443 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
444 return result;
445 }
446
OnGetWindows(napi_env env,NapiCallbackInfo & info)447 napi_value OnGetWindows(napi_env env, NapiCallbackInfo& info)
448 {
449 HILOG_INFO();
450
451 int64_t displayId = 0;
452 bool hasDisplayId = false;
453 napi_value lastParam = nullptr;
454 if (info.argc >= ARGS_SIZE_TWO) {
455 if (info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) {
456 HILOG_INFO("argc is more than two, use callback: situation 1");
457 lastParam = info.argv[PARAM1];
458 } else if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
459 HILOG_INFO("argc is more than two, use callback: situation 2");
460 lastParam = info.argv[PARAM0];
461 } else {
462 lastParam = nullptr;
463 }
464 if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
465 hasDisplayId = ConvertFromJsValue(env, info.argv[PARAM0], displayId);
466 HILOG_INFO("argc is more than two, use promise: situation 3");
467 }
468 } else if (info.argc == ARGS_SIZE_ONE) {
469 if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
470 lastParam = info.argv[PARAM0];
471 } else if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
472 hasDisplayId = ConvertFromJsValue(env, info.argv[PARAM0], displayId);
473 lastParam = nullptr;
474 HILOG_INFO("argc is one, use promise");
475 }
476 } else {
477 lastParam = nullptr;
478 HILOG_INFO("argc is others, use promise");
479 }
480
481 return hasDisplayId ? GetWindowsByDisplayIdAsync(env, lastParam, displayId) :
482 GetWindowsAsync(env, lastParam);
483 }
484
GetWindowsAsync(napi_env env,napi_value lastParam)485 napi_value GetWindowsAsync(napi_env env, napi_value lastParam)
486 {
487 HILOG_INFO();
488 auto accessibilityWindows = std::make_shared<std::vector<OHOS::Accessibility::AccessibilityWindowInfo>>();
489 auto ret = std::make_shared<RetError>(RET_OK);
490 NapiAsyncTask::ExecuteCallback execute = [weak = context_, accessibilityWindows, ret] () {
491 HILOG_INFO("Getwindows begin");
492 auto context = weak.lock();
493 if (!context) {
494 HILOG_ERROR("context is released");
495 *ret = RET_ERR_FAILED;
496 return;
497 }
498 *ret = context->GetWindows(*accessibilityWindows);
499 };
500
501 NapiAsyncTask::CompleteCallback complete =
502 [ret, accessibilityWindows] (napi_env env, NapiAsyncTask& task, int32_t status) {
503 if (*ret == RET_OK) {
504 napi_value napiWindowInfos = nullptr;
505 napi_create_array(env, &napiWindowInfos);
506 ConvertAccessibilityWindowInfosToJS(env, napiWindowInfos, *accessibilityWindows);
507 task.Resolve(env, napiWindowInfos);
508 } else {
509 HILOG_ERROR("Get windowInfos failed.");
510 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
511 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
512 }
513 };
514
515 napi_value result = nullptr;
516 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::GetWindowsAsync",
517 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
518 return result;
519 }
520
GetWindowsByDisplayIdAsync(napi_env env,napi_value lastParam,int64_t displayId)521 napi_value GetWindowsByDisplayIdAsync(napi_env env, napi_value lastParam, int64_t displayId)
522 {
523 HILOG_INFO();
524 auto accessibilityWindows = std::make_shared<std::vector<OHOS::Accessibility::AccessibilityWindowInfo>>();
525 auto ret = std::make_shared<RetError>(RET_OK);
526 NapiAsyncTask::ExecuteCallback execute = [weak = context_, accessibilityWindows, ret, displayId] () {
527 HILOG_INFO("GetwindowsByDisplayId begin");
528 auto context = weak.lock();
529 if (!context) {
530 HILOG_ERROR("context is released");
531 *ret = RET_ERR_FAILED;
532 return;
533 }
534 if (displayId < 0) {
535 HILOG_ERROR("displayId is error: %{public}" PRId64 "", displayId);
536 *ret = RET_ERR_INVALID_PARAM;
537 return;
538 }
539 *ret = context->GetWindows(static_cast<uint64_t>(displayId), *accessibilityWindows);
540 };
541
542 NapiAsyncTask::CompleteCallback complete =
543 [ret, accessibilityWindows] (napi_env env, NapiAsyncTask& task, int32_t status) {
544 if (*ret == RET_OK) {
545 napi_value napiWindowInfos = nullptr;
546 napi_create_array(env, &napiWindowInfos);
547 ConvertAccessibilityWindowInfosToJS(env, napiWindowInfos, *accessibilityWindows);
548 task.Resolve(env, napiWindowInfos);
549 } else {
550 HILOG_ERROR("Get windowInfosByDisplayId failed.");
551 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
552 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
553 }
554 };
555
556 napi_value result = nullptr;
557 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::GetWindowsByDisplayIdAsync",
558 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
559 return result;
560 }
561
OnGestureInjectSync(napi_env env,NapiCallbackInfo & info)562 napi_value OnGestureInjectSync(napi_env env, NapiCallbackInfo& info)
563 {
564 #ifdef ACCESSIBILITY_EMULATOR_DEFINED
565 ApiReportHelper reporter("NAccessibilityExtensionContext.OnGestureInjectSync");
566 #endif // ACCESSIBILITY_EMULATOR_DEFINED
567 HILOG_INFO();
568 NAccessibilityErrorCode errCode = NAccessibilityErrorCode::ACCESSIBILITY_OK;
569 if (info.argc != ARGS_SIZE_TWO) {
570 HILOG_ERROR("invalid param");
571 errCode = NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM;
572 }
573
574 napi_value nGesturePaths = reinterpret_cast<napi_value>(info.argv[PARAM0]);
575 std::shared_ptr<AccessibilityGestureInjectPath> gesturePath =
576 std::make_shared<AccessibilityGestureInjectPath>();
577 if (errCode == NAccessibilityErrorCode::ACCESSIBILITY_OK) {
578 if (!ConvertGesturePathJSToNAPI(env, nGesturePaths, gesturePath)) {
579 errCode = NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM;
580 HILOG_ERROR("invalid param");
581 }
582 }
583
584 if (errCode == NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM) {
585 napi_throw(env, CreateJsError(env,
586 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
587 ERROR_MESSAGE_PARAMETER_ERROR));
588 return CreateJsUndefined(env);
589 }
590
591 auto context = context_.lock();
592 RetError ret = context->InjectGesture(gesturePath);
593 if (ret != RET_OK) {
594 HILOG_ERROR("result error, ret %{public}d", ret);
595 napi_throw(env, CreateJsError(env,
596 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
597 ERROR_MESSAGE_PARAMETER_ERROR));
598 return CreateJsUndefined(env);
599 }
600
601 HILOG_DEBUG("OnGestureInjectSync success");
602 return CreateJsUndefined(env);
603 }
604
OnGestureInject(napi_env env,NapiCallbackInfo & info)605 napi_value OnGestureInject(napi_env env, NapiCallbackInfo& info)
606 {
607 HILOG_INFO();
608 NAccessibilityErrorCode errCode = NAccessibilityErrorCode::ACCESSIBILITY_OK;
609 if (info.argc < ARGS_SIZE_ONE) {
610 HILOG_ERROR("Not enough params");
611 errCode = NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM;
612 }
613
614 napi_value nGesturePaths = info.argv[PARAM0];
615 std::shared_ptr<AccessibilityGestureInjectPath> gesturePath =
616 std::make_shared<AccessibilityGestureInjectPath>();
617 if (errCode == NAccessibilityErrorCode::ACCESSIBILITY_OK) {
618 if (!ConvertGesturePathJSToNAPI(env, nGesturePaths, gesturePath)) {
619 errCode = NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM;
620 }
621 }
622
623 if (errCode == NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM) {
624 HILOG_ERROR("invalid param");
625 napi_throw(env, CreateJsError(env,
626 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
627 ERROR_MESSAGE_PARAMETER_ERROR));
628 return CreateJsUndefined(env);
629 }
630 return GestureInjectCompleteTask(env, info, gesturePath);
631 }
632
GestureInjectCompleteTask(napi_env env,NapiCallbackInfo & info,std::shared_ptr<AccessibilityGestureInjectPath> gesturePath)633 napi_value GestureInjectCompleteTask(
634 napi_env env, NapiCallbackInfo& info, std::shared_ptr<AccessibilityGestureInjectPath> gesturePath)
635 {
636 #ifdef ACCESSIBILITY_EMULATOR_DEFINED
637 ApiReportHelper reporter("NAccessibilityExtensionContext.OnGestureInject");
638 #endif // ACCESSIBILITY_EMULATOR_DEFINED
639 auto ret = std::make_shared<RetError>(RET_OK);
640 NapiAsyncTask::ExecuteCallback execute = [weak = context_, gesturePath, ret] () {
641 HILOG_INFO("GestureInject begin");
642 auto context = weak.lock();
643 if (!context) {
644 HILOG_ERROR("context is released");
645 *ret = RET_ERR_FAILED;
646 return;
647 }
648
649 *ret = context->InjectGesture(gesturePath);
650 };
651 NapiAsyncTask::CompleteCallback complete =
652 [ret, gesturePath](napi_env env, NapiAsyncTask& task, int32_t status) {
653 if (*ret == RET_OK) {
654 task.Resolve(env, CreateJsUndefined(env));
655 } else {
656 HILOG_ERROR("Gesture inject failed. ret: %{public}d.", *ret);
657 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
658 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
659 }
660 };
661
662 napi_value lastParam = (info.argc == ARGS_SIZE_ONE) ? nullptr :
663 ((info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) ? info.argv[PARAM1] : nullptr);
664 napi_value result = nullptr;
665 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::OnGestureInject",
666 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
667 return result;
668 }
669
OnStartAbility(napi_env env,NapiCallbackInfo & info)670 napi_value OnStartAbility(napi_env env, NapiCallbackInfo& info)
671 {
672 if (info.argc < ARGS_SIZE_ONE) {
673 HILOG_ERROR("Start ability failed, not enough params.");
674 napi_throw(env, CreateJsError(env,
675 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM)));
676 return CreateJsUndefined(env);
677 }
678
679 AAFwk::Want want;
680 if (!CheckStartAbilityInputParam(env, info, want)) {
681 napi_throw(env, CreateJsError(env,
682 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM)));
683 return CreateJsUndefined(env);
684 }
685
686 napi_value lastParam = (info.argc == ARGS_SIZE_ONE) ? nullptr :
687 ((info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) ? info.argv[PARAM1] : nullptr);
688 napi_value result = nullptr;
689 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
690 auto asyncTask = [weak = context_, want, env, task = napiAsyncTask.get()]() {
691 HILOG_INFO("startAbility begin");
692 auto context = weak.lock();
693 if (context == nullptr) {
694 HILOG_ERROR("context is released");
695 task->Reject(env, CreateJsError(env,
696 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
697 ERROR_MESSAGE_PARAMETER_ERROR));
698 return;
699 }
700
701 auto ret = std::make_shared<RetError>(RET_OK);
702 *ret = context->StartAbility(want);
703 if (*ret == RET_OK) {
704 task->Resolve(env, CreateJsUndefined(env));
705 } else {
706 HILOG_ERROR("startAbility failed. ret: %{public}d.", *ret);
707 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
708 task->Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
709 }
710 };
711 // NAccessibilityExtensionContext::OnStartAbility
712 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_high)) {
713 napiAsyncTask->Reject(env, CreateJsError(env,
714 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_SYSTEM_ABNORMALITY),
715 ERROR_MESSAGE_SYSTEM_ABNORMALITY));
716 } else {
717 napiAsyncTask.release();
718 }
719 return result;
720 }
721
OnEnableScreenCurtain(napi_env env,NapiCallbackInfo & info)722 napi_value OnEnableScreenCurtain(napi_env env, NapiCallbackInfo& info)
723 {
724 HILOG_INFO();
725 if (info.argc != ARGS_SIZE_ONE) {
726 HILOG_ERROR("Not enough params");
727 napi_throw(env, CreateJsError(env,
728 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
729 ERROR_MESSAGE_PARAMETER_ERROR));
730 return CreateJsUndefined(env);
731 }
732
733 bool isEnable = false;
734 napi_get_value_bool(env, info.argv[PARAM0], &isEnable);
735 auto context = context_.lock();
736 RetError ret = context->EnableScreenCurtain(isEnable);
737 if (ret != RET_OK) {
738 HILOG_ERROR("result error, ret %{public}d", ret);
739 napi_throw(env, CreateJsError(env,
740 static_cast<int32_t>(NAccessibilityErrorCode::ACCESSIBILITY_ERROR_INVALID_PARAM),
741 ERROR_MESSAGE_PARAMETER_ERROR));
742 return CreateJsUndefined(env);
743 }
744
745 HILOG_INFO("OnEnableScreenCurtain success");
746 return CreateJsUndefined(env);
747 }
748
OnGetElements(napi_env env,NapiCallbackInfo & info)749 napi_value OnGetElements(napi_env env, NapiCallbackInfo& info)
750 {
751 int32_t windowId = 0;
752 int64_t elementId = -1;
753 napi_value lastParam = nullptr;
754
755 if (info.argc >= ARGS_SIZE_TWO) {
756 if (info.argv[PARAM1] != nullptr && IsNapiNumber(env, info.argv[PARAM1])) {
757 ConvertFromJsValue(env, info.argv[PARAM1], elementId);
758 }
759 if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
760 ConvertFromJsValue(env, info.argv[PARAM0], windowId);
761 }
762 } else if (info.argc == ARGS_SIZE_ONE) {
763 if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
764 ConvertFromJsValue(env, info.argv[PARAM0], windowId);
765 }
766 } else {
767 HILOG_ERROR("Not enough params");
768 }
769 HILOG_INFO("windowId: %{public}d, elementId: %{public}" PRId64 "", windowId, elementId);
770 return GetElementsAsync(env, lastParam, windowId, elementId);
771 }
772
GetElementsAsync(napi_env env,napi_value lastParam,int32_t windowId,int64_t elementId)773 napi_value GetElementsAsync(napi_env env, napi_value lastParam, int32_t windowId, int64_t elementId)
774 {
775 auto accessibilityElements = std::make_shared<std::vector<OHOS::Accessibility::AccessibilityElementInfo>>();
776 auto ret = std::make_shared<RetError>(RET_OK);
777 NapiAsyncTask::ExecuteCallback execute = [weak = context_, accessibilityElements, ret, windowId, elementId] () {
778 HILOG_INFO("GetElementsAsync begin");
779 auto context = weak.lock();
780 if (!context) {
781 HILOG_ERROR("context is released");
782 *ret = RET_ERR_FAILED;
783 return;
784 }
785
786 if (windowId <= 0) {
787 HILOG_ERROR("windowId is error: %{public}d", windowId);
788 *ret = RET_ERR_INVALID_PARAM;
789 return;
790 }
791
792 if (elementId < -1) {
793 HILOG_ERROR("elementId is error: %{public}" PRId64 "", elementId);
794 *ret = RET_ERR_INVALID_PARAM;
795 return;
796 }
797 *ret = context->GetElements(windowId, elementId, *accessibilityElements);
798 };
799
800 NapiAsyncTask::CompleteCallback complete =
801 [ret, accessibilityElements] (napi_env env, NapiAsyncTask& task, int32_t status) {
802 if (*ret == RET_OK) {
803 napi_value napiElementInfos = nullptr;
804 napi_create_array(env, &napiElementInfos);
805 NAccessibilityElement::ConvertElementInfosToJS(env, napiElementInfos, *accessibilityElements);
806 task.Resolve(env, napiElementInfos);
807 } else {
808 HILOG_ERROR("Get GetElementsAsync failed.");
809 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
810 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
811 }
812 };
813
814 napi_value result = nullptr;
815 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::GetElementsAsync",
816 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
817 return result;
818 }
819
OnGetDefaultFocusedElementIds(napi_env env,NapiCallbackInfo & info)820 napi_value OnGetDefaultFocusedElementIds(napi_env env, NapiCallbackInfo& info)
821 {
822 HILOG_INFO();
823 int32_t windowId = INVALID_WINDOW_ID;
824 napi_value lastParam = nullptr;
825
826 if (info.argc >= ARGS_SIZE_TWO) {
827 if (info.argv[PARAM1] != nullptr && IsNapiFunction(env, info.argv[PARAM1])) {
828 HILOG_INFO("argc is more than two, use callback: situation 1");
829 lastParam = info.argv[PARAM1];
830 } else if (info.argv[PARAM0] != nullptr && IsNapiFunction(env, info.argv[PARAM0])) {
831 HILOG_INFO("argc is more than two, use callback: situation 2");
832 lastParam = info.argv[PARAM0];
833 } else {
834 lastParam = nullptr;
835 }
836 if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
837 ConvertFromJsValue(env, info.argv[PARAM0], windowId);
838 }
839 } else if (info.argc == ARGS_SIZE_ONE) {
840 if (info.argv[PARAM0] != nullptr && IsNapiNumber(env, info.argv[PARAM0])) {
841 ConvertFromJsValue(env, info.argv[PARAM0], windowId);
842 }
843 } else {
844 HILOG_ERROR("Not enough params");
845 }
846 HILOG_DEBUG("input windowId: %{public}d", windowId);
847 return GetDefaultFocusedElementIdsAsync(env, lastParam, windowId);
848 }
849
GetDefaultFocusedElementIdsAsync(napi_env env,napi_value lastParam,int32_t windowId)850 napi_value GetDefaultFocusedElementIdsAsync(napi_env env, napi_value lastParam, int32_t windowId)
851 {
852 auto accessibilityElements = std::make_shared<std::vector<OHOS::Accessibility::AccessibilityElementInfo>>();
853 auto ret = std::make_shared<RetError>(RET_OK);
854 NapiAsyncTask::ExecuteCallback execute = [weak = context_, accessibilityElements, ret, windowId] () {
855 auto context = weak.lock();
856 if (!context) {
857 HILOG_ERROR("context is released");
858 *ret = RET_ERR_FAILED;
859 return;
860 }
861
862 if (windowId <= 0) {
863 HILOG_ERROR("windowId is error: %{public}d", windowId);
864 *ret = RET_ERR_INVALID_PARAM;
865 return;
866 }
867
868 *ret = context->GetDefaultFocusedElementIds(windowId, *accessibilityElements);
869 };
870
871 NapiAsyncTask::CompleteCallback complete =
872 [ret, accessibilityElements] (napi_env env, NapiAsyncTask& task, int32_t status) {
873 if (*ret == RET_OK) {
874 napi_value napiElementIds = nullptr;
875 napi_create_array(env, &napiElementIds);
876 NAccessibilityElement::ConvertElementIdVecToJS(env, napiElementIds, *accessibilityElements);
877 task.Resolve(env, napiElementIds);
878 } else {
879 HILOG_ERROR("Get GetDefaultFocusedElementIdsAsync failed.");
880 NAccessibilityErrMsg errMsg = QueryRetMsg(*ret);
881 task.Reject(env, CreateJsError(env, static_cast<int32_t>(errMsg.errCode), errMsg.message));
882 }
883 };
884
885 napi_value result = nullptr;
886 NapiAsyncTask::Schedule("NAccessibilityExtensionContext::GetDefaultFocusedElementIdsAsync",
887 env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
888 return result;
889 }
890 };
891 } // namespace
892
CreateJsAccessibilityExtensionContext(napi_env env,std::shared_ptr<AccessibilityExtensionContext> context)893 napi_value CreateJsAccessibilityExtensionContext(
894 napi_env env, std::shared_ptr<AccessibilityExtensionContext> context)
895 {
896 HILOG_INFO();
897 napi_value object = CreateJsExtensionContext(env, context);
898 std::unique_ptr<NAccessibilityExtensionContext> jsContext =
899 std::make_unique<NAccessibilityExtensionContext>(context);
900 if (!object) {
901 HILOG_ERROR("object is nullptr.");
902 return nullptr;
903 }
904 napi_wrap(env, object, jsContext.release(), NAccessibilityExtensionContext::Finalizer, nullptr, nullptr);
905 const char *moduleName = "NAccessibilityExtensionContext";
906 BindNativeFunction(env, object, "setTargetBundleName", moduleName,
907 NAccessibilityExtensionContext::SetTargetBundleName);
908 BindNativeFunction(env, object, "getFocusElement", moduleName,
909 NAccessibilityExtensionContext::GetFocusElement);
910 BindNativeFunction(env, object, "getWindowRootElement", moduleName,
911 NAccessibilityExtensionContext::GetWindowRootElement);
912 BindNativeFunction(env, object, "getWindows", moduleName, NAccessibilityExtensionContext::GetWindows);
913 BindNativeFunction(env, object, "injectGesture", moduleName, NAccessibilityExtensionContext::InjectGesture);
914 BindNativeFunction(env, object, "injectGestureSync", moduleName, NAccessibilityExtensionContext::InjectGestureSync);
915 BindNativeFunction(env, object, "startAbility", moduleName, NAccessibilityExtensionContext::StartAbility);
916 BindNativeFunction(env, object, "enableScreenCurtain", moduleName,
917 NAccessibilityExtensionContext::EnableScreenCurtain);
918 BindNativeFunction(env, object, "getElements", moduleName, NAccessibilityExtensionContext::GetElements);
919 BindNativeFunction(env, object, "getDefaultFocusedElementIds", moduleName,
920 NAccessibilityExtensionContext::GetDefaultFocusedElementIds);
921 return object;
922 }
923 } // namespace Accessibility
924 } // namespace OHOS