• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 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 <ani.h>
17 #include <array>
18 #include <iostream>
19 #include <vector>
20 #include "hilog_wrapper.h"
21 #include "ani_accessibility_common.h"
22 #include <ani_signature_builder.h>
23 
24 using namespace OHOS::Accessibility;
25 using namespace arkts::ani_signature;
26 
ANIStringToStdString(ani_env * env,ani_string ani_str)27 std::string ANICommon::ANIStringToStdString(ani_env *env, ani_string ani_str)
28 {
29     ani_size strSize;
30     env->String_GetUTF8Size(ani_str, &strSize);
31 
32     std::vector<char> buffer(strSize + 1); // +1 for null terminator
33     char* utf8_buffer = buffer.data();
34 
35     ani_size bytes_written = 0;
36     env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written);
37 
38     utf8_buffer[bytes_written] = '\0';
39     std::string content = std::string(utf8_buffer);
40     return content;
41 }
42 
GetStringField(ani_env * env,std::string fieldName,ani_object object,std::string & fieldValue)43 bool ANICommon::GetStringField(ani_env *env, std::string fieldName, ani_object object, std::string &fieldValue)
44 {
45     ani_ref ref;
46     if (env->Object_GetFieldByName_Ref(object, fieldName.c_str(), &ref) != ANI_OK) {
47         HILOG_ERROR("get field %{public}s failed", fieldName.c_str());
48         return false;
49     }
50     ani_boolean isUndefined;
51     if (env->Reference_IsUndefined(ref, &isUndefined) != ANI_OK) {
52         HILOG_ERROR("get field %{public}s undefined failed", fieldName.c_str());
53         return false;
54     }
55     if (!isUndefined) {
56         fieldValue = ANIStringToStdString(env, static_cast<ani_string>(ref));
57         return true;
58     }
59     return false;
60 }
61 
GetIntField(ani_env * env,std::string fieldName,ani_object object,int32_t & fieldValue)62 bool ANICommon::GetIntField(ani_env *env, std::string fieldName, ani_object object, int32_t &fieldValue)
63 {
64     ani_ref ref;
65     if (env->Object_GetFieldByName_Ref(object, fieldName.c_str(), &ref) != ANI_OK) {
66         HILOG_ERROR("get field %{public}s failed", fieldName.c_str());
67         return false;
68     }
69     ani_boolean isUndefined;
70     if (env->Reference_IsUndefined(ref, &isUndefined) != ANI_OK) {
71         HILOG_ERROR("get field %{public}s undefined failed", fieldName.c_str());
72         return false;
73     }
74     if (!isUndefined) {
75         if (env->Object_CallMethodByName_Int(static_cast<ani_object>(ref), "toInt", ":i", &fieldValue) ==
76             ANI_OK) {
77             return true;
78         }
79     }
80     return false;
81 }
82 
GetArrayStringField(ani_env * env,std::string fieldName,ani_object object,std::vector<std::string> & fieldValue)83 bool ANICommon::GetArrayStringField(ani_env *env, std::string fieldName, ani_object object,
84     std::vector<std::string> &fieldValue)
85 {
86     ani_ref ref;
87     if (env->Object_GetFieldByName_Ref(object, fieldName.c_str(), &ref) != ANI_OK) {
88         HILOG_ERROR("get field %{public}s failed", fieldName.c_str());
89         return false;
90     }
91     ani_boolean isUndefined;
92     if (env->Reference_IsUndefined(ref, &isUndefined) != ANI_OK) {
93         HILOG_ERROR("get field %{public}s undefined failed", fieldName.c_str());
94         return false;
95     }
96     if (isUndefined) {
97         return false;
98     }
99 
100     fieldValue.clear();
101     ani_class arrayCls;
102     if (env->FindClass(Builder::BuildClass("escompat.Array").Descriptor().c_str(), &arrayCls) != ANI_OK) {
103         return false;
104     }
105 
106     ani_method arrayLengthMethod;
107     SignatureBuilder objectBuilder{};
108     objectBuilder.SetReturnClass("std.core.Object");
109     std::string objectBuilderDescriptor = objectBuilder.BuildSignatureDescriptor();
110     if (env->Class_FindMethod(arrayCls, "length", objectBuilderDescriptor.c_str(), &arrayLengthMethod) != ANI_OK) {
111         return false;
112     }
113 
114     ani_ref length;
115     if (env->Object_CallMethod_Ref(static_cast<ani_object>(ref), arrayLengthMethod, &length) != ANI_OK) {
116         return false;
117     }
118 
119     int32_t lengthInt;
120     if (env->Object_CallMethodByName_Int(static_cast<ani_object>(length), "toInt", ":i", &lengthInt) != ANI_OK ||
121         lengthInt <= 0) {
122         return false;
123     }
124 
125     ani_method arrayPopMethod;
126     if (env->Class_FindMethod(arrayCls, "pop", objectBuilderDescriptor.c_str(), &arrayPopMethod) != ANI_OK) {
127         return false;
128     }
129 
130     ani_ref string;
131     std::string result;
132     for (int32_t i = 0; i < lengthInt; i++) {
133         if (env->Object_CallMethod_Ref(static_cast<ani_object>(ref), arrayPopMethod, &string) != ANI_OK) {
134             return false;
135         }
136         result = ANIStringToStdString(env, static_cast<ani_string>(string));
137         fieldValue.insert(fieldValue.begin(), result);
138     }
139 
140     return true;
141 }
142 
CheckObserverEqual(ani_env * env,ani_ref fnRef,ani_env * iterEnv,ani_ref iterFn)143 bool ANICommon::CheckObserverEqual(ani_env *env, ani_ref fnRef, ani_env *iterEnv, ani_ref iterFn)
144 {
145     if (env != iterEnv) {
146         HILOG_DEBUG("not the same env");
147         return false;
148     }
149     ani_boolean isEquals = false;
150     if (env->Reference_StrictEquals(fnRef, iterFn, &isEquals) != ANI_OK) {
151         HILOG_ERROR("check observer equal failed!");
152         return false;
153     }
154     return isEquals;
155 }
156 
ConvertStringToEventInfoTypes(const std::string & type)157 EventType ANICommon::ConvertStringToEventInfoTypes(const std::string &type)
158 {
159     static const std::map<const std::string, EventType> eventInfoTypesTable = {
160         {"click", EventType::TYPE_VIEW_CLICKED_EVENT},
161         {"longClick", EventType::TYPE_VIEW_LONG_CLICKED_EVENT},
162         {"select", EventType::TYPE_VIEW_SELECTED_EVENT},
163         {"focus", EventType::TYPE_VIEW_FOCUSED_EVENT},
164         {"textUpdate", EventType::TYPE_VIEW_TEXT_UPDATE_EVENT},
165         {"hoverEnter", EventType::TYPE_VIEW_HOVER_ENTER_EVENT},
166         {"hoverExit", EventType::TYPE_VIEW_HOVER_EXIT_EVENT},
167         {"scroll", EventType::TYPE_VIEW_SCROLLED_EVENT},
168         {"textSelectionUpdate", EventType::TYPE_VIEW_TEXT_SELECTION_UPDATE_EVENT},
169         {"accessibilityFocus", EventType::TYPE_VIEW_ACCESSIBILITY_FOCUSED_EVENT},
170         {"accessibilityFocusClear", EventType::TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED_EVENT},
171         {"requestFocusForAccessibility", EventType::TYPE_VIEW_REQUEST_FOCUS_FOR_ACCESSIBILITY},
172         {"announceForAccessibility", EventType::TYPE_VIEW_ANNOUNCE_FOR_ACCESSIBILITY}};
173 
174     if (eventInfoTypesTable.find(type) == eventInfoTypesTable.end()) {
175         HILOG_WARN("invalid key[%{public}s]", type.c_str());
176         return TYPE_VIEW_INVALID;
177     }
178 
179     return eventInfoTypesTable.at(type);
180 }
181 
ConvertStringToAccessibleOperationType(const std::string & type)182 ActionType ANICommon::ConvertStringToAccessibleOperationType(const std::string &type)
183 {
184     std::map<const std::string, ActionType> accessibleOperationTypeTable = {
185         {"focus", ActionType::ACCESSIBILITY_ACTION_FOCUS},
186         {"clearFocus", ActionType::ACCESSIBILITY_ACTION_CLEAR_FOCUS},
187         {"select", ActionType::ACCESSIBILITY_ACTION_SELECT},
188         {"clearSelection", ActionType::ACCESSIBILITY_ACTION_CLEAR_SELECTION},
189         {"click", ActionType::ACCESSIBILITY_ACTION_CLICK},
190         {"longClick", ActionType::ACCESSIBILITY_ACTION_LONG_CLICK},
191         {"accessibilityFocus", ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS},
192         {"clearAccessibilityFocus", ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS},
193         {"scrollForward", ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD},
194         {"scrollBackward", ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD},
195         {"copy", ActionType::ACCESSIBILITY_ACTION_COPY},
196         {"paste", ActionType::ACCESSIBILITY_ACTION_PASTE},
197         {"cut", ActionType::ACCESSIBILITY_ACTION_CUT},
198         {"setSelection", ActionType::ACCESSIBILITY_ACTION_SET_SELECTION},
199         {"setCursorPosition", ActionType::ACCESSIBILITY_ACTION_SET_CURSOR_POSITION},
200         {"common", ActionType::ACCESSIBILITY_ACTION_COMMON},
201         {"setText", ActionType::ACCESSIBILITY_ACTION_SET_TEXT},
202         {"delete", ActionType::ACCESSIBILITY_ACTION_DELETED},
203         {"home", ActionType::ACCESSIBILITY_ACTION_HOME},
204         {"back", ActionType::ACCESSIBILITY_ACTION_BACK},
205         {"recentTask", ActionType::ACCESSIBILITY_ACTION_RECENTTASK},
206         {"notificationCenter", ActionType::ACCESSIBILITY_ACTION_NOTIFICATIONCENTER},
207         {"controlCenter", ActionType::ACCESSIBILITY_ACTION_CONTROLCENTER},
208         {"spanClick", ActionType::ACCESSIBILITY_ACTION_SPAN_CLICK}};
209 
210     if (accessibleOperationTypeTable.find(type) == accessibleOperationTypeTable.end()) {
211         HILOG_WARN("invalid key[%{public}s]", type.c_str());
212         return ACCESSIBILITY_ACTION_INVALID;
213     }
214 
215     return accessibleOperationTypeTable.at(type);
216 }
217 
ConvertStringToWindowUpdateTypes(const std::string & type)218 WindowUpdateType ANICommon::ConvertStringToWindowUpdateTypes(const std::string &type)
219 {
220     static const std::map<const std::string, WindowUpdateType> windowsUpdateTypesTable = {
221         {"accessibilityFocus", WindowUpdateType::WINDOW_UPDATE_ACCESSIBILITY_FOCUSED},
222         {"focus", WindowUpdateType::WINDOW_UPDATE_FOCUSED},
223         {"active", WindowUpdateType::WINDOW_UPDATE_ACTIVE},
224         {"add", WindowUpdateType::WINDOW_UPDATE_ADDED},
225         {"remove", WindowUpdateType::WINDOW_UPDATE_REMOVED},
226         {"bounds", WindowUpdateType::WINDOW_UPDATE_BOUNDS},
227         {"title", WindowUpdateType::WINDOW_UPDATE_TITLE},
228         {"layer", WindowUpdateType::WINDOW_UPDATE_LAYER},
229         {"parent", WindowUpdateType::WINDOW_UPDATE_PARENT},
230         {"children", WindowUpdateType::WINDOW_UPDATE_CHILDREN},
231         {"pip", WindowUpdateType::WINDOW_UPDATE_PIP},
232         {"property", WindowUpdateType::WINDOW_UPDATE_PROPERTY}};
233 
234     if (windowsUpdateTypesTable.find(type) == windowsUpdateTypesTable.end()) {
235         HILOG_WARN("invalid key[%{public}s]", type.c_str());
236         return WINDOW_UPDATE_INVALID;
237     }
238 
239     return windowsUpdateTypesTable.at(type);
240 }
241 
ConvertStringToTextMoveUnit(const std::string & type)242 TextMoveUnit ANICommon::ConvertStringToTextMoveUnit(const std::string &type)
243 {
244     static const std::map<const std::string, TextMoveUnit> textMoveUnitTable = {{"char", TextMoveUnit::STEP_CHARACTER},
245         {"word", TextMoveUnit::STEP_WORD},
246         {"line", TextMoveUnit::STEP_LINE},
247         {"page", TextMoveUnit::STEP_PAGE},
248         {"paragraph", TextMoveUnit::STEP_PARAGRAPH}};
249 
250     if (textMoveUnitTable.find(type) == textMoveUnitTable.end()) {
251         HILOG_WARN("invalid key[%{public}s]", type.c_str());
252         return STEP_INVALID;
253     }
254 
255     return textMoveUnitTable.at(type);
256 }
257 
CreateBoolObject(ani_env * env,ani_boolean value)258 ani_object ANICommon::CreateBoolObject(ani_env *env, ani_boolean value)
259 {
260     Type boolClass = Builder::BuildClass("std.core.Boolean");
261     ani_class cls {};
262     if (env->FindClass(boolClass.Descriptor().c_str(), &cls) != ANI_OK) {
263         HILOG_ERROR("find class Boolean failed");
264         return nullptr;
265     }
266 
267     ani_method ctor;
268     std::string ctorName = Builder::BuildConstructorName();
269     SignatureBuilder sb{};
270     sb.AddBoolean();
271     if (env->Class_FindMethod(cls, ctorName.c_str(), sb.BuildSignatureDescriptor().c_str(), &ctor) != ANI_OK) {
272         HILOG_ERROR("find method Boolean.constructor failed");
273         return nullptr;
274     }
275 
276     ani_object boolObject;
277     if (env->Object_New(cls, ctor, &boolObject, value) != ANI_OK) {
278         HILOG_ERROR("create Boolean object failed");
279         return nullptr;
280     }
281     return boolObject;
282 }
283 
ConvertEventInfoMandatoryFields(ani_env * env,ani_object eventObject,AccessibilityEventInfo & eventInfo)284 bool ANICommon::ConvertEventInfoMandatoryFields(ani_env *env, ani_object eventObject,
285     AccessibilityEventInfo &eventInfo)
286 {
287     std::string type;
288     if (!GetStringField(env, "type", eventObject, type)) {
289         HILOG_ERROR("get type Faild!");
290         return false;
291     }
292     OHOS::Accessibility::EventType eventType = ConvertStringToEventInfoTypes(type);
293     if (eventType == TYPE_VIEW_INVALID) {
294         HILOG_ERROR("event type is invalid!");
295         return false;
296     }
297     eventInfo.SetEventType(eventType);
298 
299     std::string bundleName;
300     if (!GetStringField(env, "bundleName", eventObject, bundleName)) {
301         HILOG_ERROR("get bundleName Faild!");
302         return false;
303     }
304     if (bundleName == "") {
305         HILOG_ERROR("bundle name is invalid!");
306         return false;
307     }
308     eventInfo.SetBundleName(bundleName);
309 
310     std::string triggerAction;
311     if (!GetStringField(env, "triggerAction", eventObject, triggerAction)) {
312         HILOG_ERROR("get triggerAction Faild!");
313         return false;
314     }
315     OHOS::Accessibility::ActionType action = ConvertStringToAccessibleOperationType(triggerAction);
316     if (action == ACCESSIBILITY_ACTION_INVALID) {
317         HILOG_ERROR("action is invalid!");
318         return false;
319     }
320     eventInfo.SetTriggerAction(action);
321 
322     return true;
323 }
324 
ConvertEventInfoStringFields(ani_env * env,ani_object eventObject,OHOS::Accessibility::AccessibilityEventInfo & eventInfo)325 void ANICommon::ConvertEventInfoStringFields(ani_env *env, ani_object eventObject,
326     OHOS::Accessibility::AccessibilityEventInfo &eventInfo)
327 {
328     std::string windowUpdateType;
329     if (GetStringField(env, "windowUpdateType", eventObject, windowUpdateType)) {
330         eventInfo.SetEventType(TYPE_WINDOW_UPDATE);
331         eventInfo.SetWindowChangeTypes(ConvertStringToWindowUpdateTypes(windowUpdateType));
332     }
333 
334     std::string componentType;
335     if (GetStringField(env, "componentType", eventObject, componentType)) {
336         eventInfo.SetComponentType(componentType);
337     }
338 
339     std::string description;
340     if (GetStringField(env, "description", eventObject, description)) {
341         eventInfo.SetDescription(description);
342     }
343 
344     std::string textMoveUnit;
345     if (GetStringField(env, "textMoveUnit", eventObject, textMoveUnit)) {
346         eventInfo.SetTextMovementStep(ConvertStringToTextMoveUnit(textMoveUnit));
347     }
348 
349     std::vector<std::string> contents;
350     if (GetArrayStringField(env, "contents", eventObject, contents)) {
351         for (auto str : contents) {
352             eventInfo.AddContent(str);
353         }
354     }
355 
356     std::string lastContent;
357     if (GetStringField(env, "lastContent", eventObject, lastContent)) {
358         eventInfo.SetLatestContent(lastContent);
359     }
360 
361     std::string textAnnouncedForAccessibility;
362     if (GetStringField(env, "textAnnouncedForAccessibility", eventObject, textAnnouncedForAccessibility)) {
363         eventInfo.SetTextAnnouncedForAccessibility(textAnnouncedForAccessibility);
364     }
365 
366     std::string customId;
367     if (GetStringField(env, "customId", eventObject, customId)) {
368         eventInfo.SetInspectorKey(customId);
369     }
370 }
371 
ConvertEventInfoIntFields(ani_env * env,ani_object eventObject,OHOS::Accessibility::AccessibilityEventInfo & eventInfo)372 void ANICommon::ConvertEventInfoIntFields(ani_env *env, ani_object eventObject,
373     OHOS::Accessibility::AccessibilityEventInfo &eventInfo)
374 {
375     int32_t pageId;
376     if (GetIntField(env, "pageId", eventObject, pageId)) {
377         eventInfo.SetPageId(pageId);
378     }
379 
380     int32_t beginIndex;
381     if (GetIntField(env, "beginIndex", eventObject, beginIndex)) {
382         eventInfo.SetBeginIndex(beginIndex);
383     }
384 
385     int32_t currentIndex;
386     if (GetIntField(env, "currentIndex", eventObject, currentIndex)) {
387         eventInfo.SetCurrentIndex(currentIndex);
388     }
389 
390     int32_t endIndex;
391     if (GetIntField(env, "endIndex", eventObject, endIndex)) {
392         eventInfo.SetEndIndex(endIndex);
393     }
394 
395     int32_t itemCount;
396     if (GetIntField(env, "itemCount", eventObject, itemCount)) {
397         eventInfo.SetItemCounts(itemCount);
398     }
399 
400     int32_t elementId;
401     if (GetIntField(env, "elementId", eventObject, elementId)) {
402         eventInfo.SetRequestFocusElementId(elementId);
403     }
404 }
405 
SendEventToMainThread(const std::function<void ()> func)406 bool ANICommon::SendEventToMainThread(const std::function<void()> func)
407 {
408     if (func == nullptr) {
409         HILOG_ERROR("func is nullptr!");
410         return false;
411     }
412 
413     if (!mainHandler) {
414         std::shared_ptr<OHOS::AppExecFwk::EventRunner> runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner();
415         if (!runner) {
416             HILOG_ERROR("get main event runner failed!");
417             return false;
418         }
419         mainHandler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
420     }
421     mainHandler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {});
422     return true;
423 }