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 }