• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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