1 /*
2 * Copyright (c) 2022-2023 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 "js_accessibility_manager.h"
17
18 #include "accessibility_constants.h"
19 #include "accessibility_event_info.h"
20 #include "accessibility_system_ability_client.h"
21
22 #include "adapter/ohos/entrance/ace_application_info.h"
23 #include "base/log/dump_log.h"
24 #include "base/log/event_report.h"
25 #include "base/log/log.h"
26 #include "base/utils/linear_map.h"
27 #include "base/utils/string_utils.h"
28 #include "base/utils/utils.h"
29 #include "core/components_ng/base/inspector.h"
30 #include "core/pipeline/pipeline_context.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32 #include "frameworks/bridge/common/dom/dom_type.h"
33
34 using namespace OHOS::Accessibility;
35 using namespace OHOS::AccessibilityConfig;
36 using namespace std;
37
38 namespace OHOS::Ace::Framework {
39 namespace {
40 const char DUMP_ORDER[] = "-accessibility";
41 const char DUMP_INSPECTOR[] = "-inspector";
42 const char ACCESSIBILITY_FOCUSED_EVENT[] = "accessibilityfocus";
43 const char ACCESSIBILITY_CLEAR_FOCUS_EVENT[] = "accessibilityclearfocus";
44 const char TEXT_CHANGE_EVENT[] = "textchange";
45 const char PAGE_CHANGE_EVENT[] = "pagechange";
46 const char SCROLL_END_EVENT[] = "scrollend";
47 const char SCROLL_START_EVENT[] = "scrollstart";
48 const char MOUSE_HOVER_ENTER[] = "mousehoverenter";
49 const char MOUSE_HOVER_EXIT[] = "mousehoverexit";
50 const char IMPORTANT_YES[] = "yes";
51 const char IMPORTANT_NO[] = "no";
52 const char IMPORTANT_NO_HIDE_DES[] = "no-hide-descendants";
53 const char LIST_TAG[] = "List";
54 const char SIDEBARCONTAINER_TAG[] = "SideBarContainer";
55 constexpr int32_t INVALID_PARENT_ID = -2100000;
56 constexpr int32_t DEFAULT_PARENT_ID = 2100000;
57 constexpr int32_t ROOT_STACK_BASE = 1100000;
58 constexpr int32_t ROOT_DECOR_BASE = 3100000;
59 constexpr int32_t CARD_NODE_ID_RATION = 10000;
60 constexpr int32_t CARD_ROOT_NODE_ID_RATION = 1000;
61 constexpr int32_t CARD_BASE = 100000;
62
63 struct ActionTable {
64 AceAction aceAction;
65 ActionType action;
66 };
67
68 struct CommonProperty {
69 int32_t windowId = 0;
70 int32_t windowLeft = 0;
71 int32_t windowTop = 0;
72 int32_t pageId = 0;
73 std::string pagePath;
74 };
75
ConvertStrToEventType(const std::string & type)76 Accessibility::EventType ConvertStrToEventType(const std::string& type)
77 {
78 // static linear map must be sorted by key.
79 static const LinearMapNode<Accessibility::EventType> eventTypeMap[] = {
80 { ACCESSIBILITY_CLEAR_FOCUS_EVENT, Accessibility::EventType::TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED_EVENT },
81 { ACCESSIBILITY_FOCUSED_EVENT, Accessibility::EventType::TYPE_VIEW_ACCESSIBILITY_FOCUSED_EVENT },
82 { DOM_CLICK, Accessibility::EventType::TYPE_VIEW_CLICKED_EVENT },
83 { DOM_FOCUS, Accessibility::EventType::TYPE_VIEW_FOCUSED_EVENT },
84 { DOM_LONG_PRESS, Accessibility::EventType::TYPE_VIEW_LONG_CLICKED_EVENT },
85 { MOUSE_HOVER_ENTER, Accessibility::EventType::TYPE_VIEW_HOVER_ENTER_EVENT },
86 { MOUSE_HOVER_EXIT, Accessibility::EventType::TYPE_VIEW_HOVER_EXIT_EVENT },
87 { PAGE_CHANGE_EVENT, Accessibility::EventType::TYPE_PAGE_STATE_UPDATE },
88 { SCROLL_END_EVENT, Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT },
89 { SCROLL_START_EVENT, Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT },
90 { DOM_SELECTED, Accessibility::EventType::TYPE_VIEW_SELECTED_EVENT },
91 { TEXT_CHANGE_EVENT, Accessibility::EventType::TYPE_VIEW_TEXT_UPDATE_EVENT },
92 { DOM_TOUCH_END, Accessibility::EventType::TYPE_TOUCH_END },
93 { DOM_TOUCH_START, Accessibility::EventType::TYPE_TOUCH_BEGIN },
94 };
95 Accessibility::EventType eventType = Accessibility::EventType::TYPE_VIEW_INVALID;
96 int64_t idx = BinarySearchFindIndex(eventTypeMap, ArraySize(eventTypeMap), type.c_str());
97 if (idx >= 0) {
98 eventType = eventTypeMap[idx].value;
99 }
100 return eventType;
101 }
102
ConvertAceEventType(AccessibilityEventType type)103 Accessibility::EventType ConvertAceEventType(AccessibilityEventType type)
104 {
105 static const LinearEnumMapNode<AccessibilityEventType, Accessibility::EventType> eventTypeMap[] = {
106 { AccessibilityEventType::CLICK, Accessibility::EventType::TYPE_VIEW_CLICKED_EVENT },
107 { AccessibilityEventType::LONG_PRESS, Accessibility::EventType::TYPE_VIEW_LONG_CLICKED_EVENT },
108 { AccessibilityEventType::SELECTED, Accessibility::EventType::TYPE_VIEW_SELECTED_EVENT },
109 { AccessibilityEventType::FOCUS, Accessibility::EventType::TYPE_VIEW_FOCUSED_EVENT },
110 { AccessibilityEventType::TEXT_CHANGE, Accessibility::EventType::TYPE_VIEW_TEXT_UPDATE_EVENT },
111 { AccessibilityEventType::PAGE_CHANGE, Accessibility::EventType::TYPE_PAGE_STATE_UPDATE },
112 { AccessibilityEventType::CHANGE, Accessibility::EventType::TYPE_PAGE_CONTENT_UPDATE },
113 { AccessibilityEventType::SCROLL_END, Accessibility::EventType::TYPE_VIEW_SCROLLED_EVENT },
114 { AccessibilityEventType::TEXT_SELECTION_UPDATE,
115 Accessibility::EventType::TYPE_VIEW_TEXT_SELECTION_UPDATE_EVENT },
116 { AccessibilityEventType::ACCESSIBILITY_FOCUSED,
117 Accessibility::EventType::TYPE_VIEW_ACCESSIBILITY_FOCUSED_EVENT },
118 { AccessibilityEventType::ACCESSIBILITY_FOCUS_CLEARED,
119 Accessibility::EventType::TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED_EVENT },
120 { AccessibilityEventType::TEXT_MOVE_UNIT, Accessibility::EventType::TYPE_VIEW_TEXT_MOVE_UNIT_EVENT },
121 };
122 Accessibility::EventType eventType = Accessibility::EventType::TYPE_VIEW_INVALID;
123 int64_t idx = BinarySearchFindIndex(eventTypeMap, ArraySize(eventTypeMap), type);
124 if (idx >= 0) {
125 eventType = eventTypeMap[idx].value;
126 }
127 return eventType;
128 }
129
ConvertAceAction(AceAction aceAction)130 ActionType ConvertAceAction(AceAction aceAction)
131 {
132 static const ActionTable actionTable[] = {
133 { AceAction::ACTION_CLICK, ActionType::ACCESSIBILITY_ACTION_CLICK },
134 { AceAction::ACTION_LONG_CLICK, ActionType::ACCESSIBILITY_ACTION_LONG_CLICK },
135 { AceAction::ACTION_SCROLL_FORWARD, ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD },
136 { AceAction::ACTION_SCROLL_BACKWARD, ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD },
137 { AceAction::ACTION_FOCUS, ActionType::ACCESSIBILITY_ACTION_FOCUS },
138 { AceAction::ACTION_ACCESSIBILITY_FOCUS, ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS },
139 { AceAction::ACTION_CLEAR_ACCESSIBILITY_FOCUS, ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS },
140 { AceAction::ACTION_NEXT_AT_MOVEMENT_GRANULARITY, ActionType::ACCESSIBILITY_ACTION_NEXT_TEXT },
141 { AceAction::ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, ActionType::ACCESSIBILITY_ACTION_PREVIOUS_TEXT },
142 { AceAction::ACTION_SET_TEXT, ActionType::ACCESSIBILITY_ACTION_SET_TEXT },
143 };
144 for (const auto& item : actionTable) {
145 if (aceAction == item.aceAction) {
146 return item.action;
147 }
148 }
149 return ActionType::ACCESSIBILITY_ACTION_INVALID;
150 }
151
ConvertAccessibilityValue(const AccessibilityValue & value)152 inline RangeInfo ConvertAccessibilityValue(const AccessibilityValue& value)
153 {
154 return RangeInfo(static_cast<int>(value.min), static_cast<int>(value.max), static_cast<int>(value.current));
155 }
156
ConvertToCardAccessibilityId(int32_t nodeId,int32_t cardId,int32_t rootNodeId)157 int32_t ConvertToCardAccessibilityId(int32_t nodeId, int32_t cardId, int32_t rootNodeId)
158 {
159 // result is integer total ten digits, top five for agp virtualViewId, end five for ace nodeId,
160 // for example agp virtualViewId is 32, ace nodeId is 1000001, convert to result is 00032 10001.
161 int32_t result = 0;
162 if (nodeId == rootNodeId + ROOT_STACK_BASE) {
163 // for example agp virtualViewId is 32 root node is 2100000, convert to result is 00032 21000.
164 result = cardId * CARD_BASE + (static_cast<int32_t>(nodeId / CARD_BASE)) * CARD_ROOT_NODE_ID_RATION +
165 nodeId % CARD_BASE;
166 } else {
167 result = cardId * CARD_BASE + (static_cast<int32_t>(nodeId / DOM_ROOT_NODE_ID_BASE)) * CARD_NODE_ID_RATION +
168 nodeId % DOM_ROOT_NODE_ID_BASE;
169 }
170 return result;
171 }
172
UpdateAccessibilityNodeInfo(const RefPtr<AccessibilityNode> & node,AccessibilityElementInfo & nodeInfo,const RefPtr<JsAccessibilityManager> & manager,int windowId)173 void UpdateAccessibilityNodeInfo(const RefPtr<AccessibilityNode>& node, AccessibilityElementInfo& nodeInfo,
174 const RefPtr<JsAccessibilityManager>& manager, int windowId)
175 {
176 LOGD("nodeId:%{public}d", node->GetNodeId());
177 int leftTopX = static_cast<int>(node->GetLeft()) + manager->GetWindowLeft(node->GetWindowId());
178 int leftTopY = static_cast<int>(node->GetTop()) + manager->GetWindowTop(node->GetWindowId());
179 int rightBottomX = leftTopX + static_cast<int>(node->GetWidth());
180 int rightBottomY = leftTopY + static_cast<int>(node->GetHeight());
181 if (manager->isOhosHostCard()) {
182 int32_t id = ConvertToCardAccessibilityId(node->GetNodeId(), manager->GetCardId(), manager->GetRootNodeId());
183 nodeInfo.SetAccessibilityId(id);
184 if (node->GetParentId() == -1) {
185 nodeInfo.SetParent(-1);
186 } else {
187 nodeInfo.SetParent(
188 ConvertToCardAccessibilityId(node->GetParentId(), manager->GetCardId(), manager->GetRootNodeId()));
189 }
190 leftTopX = static_cast<int>(node->GetLeft() + manager->GetCardOffset().GetX());
191 leftTopY = static_cast<int>(node->GetTop() + manager->GetCardOffset().GetY());
192 rightBottomX = leftTopX + static_cast<int>(node->GetWidth());
193 rightBottomY = leftTopY + static_cast<int>(node->GetHeight());
194 Accessibility::Rect bounds(leftTopX, leftTopY, rightBottomX, rightBottomY);
195 nodeInfo.SetRectInScreen(bounds);
196 } else {
197 if (node->GetTag() == SIDEBARCONTAINER_TAG) {
198 Rect sideBarRect = node->GetRect();
199 for (const auto& childNode : node->GetChildList()) {
200 sideBarRect = sideBarRect.CombineRect(childNode->GetRect());
201 }
202 leftTopX = static_cast<int>(sideBarRect.Left()) + manager->GetWindowLeft(node->GetWindowId());
203 leftTopY = static_cast<int>(sideBarRect.Top()) + manager->GetWindowTop(node->GetWindowId());
204 rightBottomX = static_cast<int>(sideBarRect.Right()) + manager->GetWindowLeft(node->GetWindowId());
205 rightBottomY = static_cast<int>(sideBarRect.Bottom()) + manager->GetWindowTop(node->GetWindowId());
206 }
207 Accessibility::Rect bounds(leftTopX, leftTopY, rightBottomX, rightBottomY);
208 nodeInfo.SetRectInScreen(bounds);
209 nodeInfo.SetComponentId(static_cast<int>(node->GetNodeId()));
210 nodeInfo.SetParent(static_cast<int>(node->GetParentId()));
211 }
212
213 if (node->GetParentId() == -1) {
214 const auto& children = node->GetChildList();
215 if (!children.empty()) {
216 auto lastChildNode = manager->GetAccessibilityNodeById(children.back()->GetNodeId());
217 if (lastChildNode) {
218 rightBottomX = leftTopX + static_cast<int>(lastChildNode->GetWidth());
219 rightBottomY = leftTopY + static_cast<int>(lastChildNode->GetHeight());
220 Accessibility::Rect bounds(leftTopX, leftTopY, rightBottomX, rightBottomY);
221 nodeInfo.SetRectInScreen(bounds);
222 }
223 }
224 nodeInfo.SetParent(INVALID_PARENT_ID);
225 }
226 if (node->GetNodeId() == 0) {
227 nodeInfo.SetParent(INVALID_PARENT_ID);
228 }
229 nodeInfo.SetPagePath(manager->GetPagePath());
230 nodeInfo.SetWindowId(windowId);
231 nodeInfo.SetChecked(node->GetCheckedState());
232 nodeInfo.SetEnabled(node->GetEnabledState());
233 nodeInfo.SetFocused(node->GetFocusedState());
234 nodeInfo.SetSelected(node->GetSelectedState());
235 nodeInfo.SetCheckable(node->GetCheckableState());
236 nodeInfo.SetClickable(node->GetClickableState());
237 nodeInfo.SetFocusable(node->GetFocusableState());
238 nodeInfo.SetScrollable(node->GetScrollableState());
239 nodeInfo.SetLongClickable(node->GetLongClickableState());
240 nodeInfo.SetEditable(node->GetEditable());
241 nodeInfo.SetPluraLineSupported(node->GetIsMultiLine());
242 nodeInfo.SetPassword(node->GetIsPassword());
243 nodeInfo.SetTextLengthLimit(node->GetMaxTextLength());
244 nodeInfo.SetSelectedBegin(node->GetTextSelectionStart());
245 nodeInfo.SetSelectedEnd(node->GetTextSelectionEnd());
246 nodeInfo.SetVisible(node->GetShown() && node->GetVisible());
247 nodeInfo.SetHint(node->GetHintText());
248 std::string accessibilityLabel = node->GetAccessibilityLabel();
249 nodeInfo.SetLabeled(atoi(accessibilityLabel.c_str()));
250 nodeInfo.SetError(node->GetErrorText());
251 nodeInfo.SetComponentResourceId(node->GetJsComponentId());
252 nodeInfo.SetInspectorKey(node->GetJsComponentId());
253 RangeInfo rangeInfo = ConvertAccessibilityValue(node->GetAccessibilityValue());
254 nodeInfo.SetRange(rangeInfo);
255 nodeInfo.SetInputType(static_cast<int>(node->GetTextInputType()));
256 nodeInfo.SetComponentType(node->GetTag());
257 GridInfo gridInfo(
258 node->GetCollectionInfo().rows, node->GetCollectionInfo().columns, (nodeInfo.IsPluraLineSupported() ? 0 : 1));
259 nodeInfo.SetGrid(gridInfo);
260 nodeInfo.SetAccessibilityFocus(node->GetAccessibilityFocusedState());
261 nodeInfo.SetPageId(node->GetPageId());
262
263 int32_t row = node->GetCollectionItemInfo().row;
264 int32_t column = node->GetCollectionItemInfo().column;
265 GridItemInfo gridItemInfo(row, row, column, column, false, nodeInfo.IsSelected());
266 nodeInfo.SetGridItem(gridItemInfo);
267 nodeInfo.SetBundleName(AceApplicationInfo::GetInstance().GetPackageName());
268
269 if (node->GetTag() == LIST_TAG) {
270 nodeInfo.SetItemCounts(node->GetListItemCounts());
271 nodeInfo.SetBeginIndex(node->GetListBeginIndex());
272 nodeInfo.SetEndIndex(node->GetListEndIndex());
273 }
274 if (node->GetIsPassword()) {
275 std::string strStar(node->GetText().size(), '*');
276 nodeInfo.SetContent(strStar);
277 } else {
278 nodeInfo.SetContent(node->GetText());
279 }
280
281 if (!node->GetAccessibilityHint().empty()) {
282 if (node->GetAccessibilityLabel().empty()) {
283 LOGI("UpdateAccessibilityNodeInfo Label is null");
284 } else {
285 LOGI("UpdateAccessibilityNodeInfo Label is not null");
286 }
287 }
288
289 auto supportAceActions = node->GetSupportAction();
290 std::vector<ActionType> actions(supportAceActions.size());
291
292 for (auto it = supportAceActions.begin(); it != supportAceActions.end(); ++it) {
293 AccessibleAction action(ConvertAceAction(*it), "ace");
294 nodeInfo.AddAction(action);
295 }
296
297 if (node->GetImportantForAccessibility() == IMPORTANT_YES) {
298 actions.emplace_back(ActionType::ACCESSIBILITY_ACTION_FOCUS);
299 nodeInfo.SetCheckable(true);
300 } else if (node->GetImportantForAccessibility() == IMPORTANT_NO ||
301 node->GetImportantForAccessibility() == IMPORTANT_NO_HIDE_DES) {
302 nodeInfo.SetVisible(false);
303 }
304
305 manager->UpdateNodeChildIds(node);
306 for (const auto& child : node->GetChildIds()) {
307 nodeInfo.AddChild(child);
308 }
309
310 #ifdef ACE_DEBUG
311 std::string actionForLog;
312 for (const auto& action : supportAceActions) {
313 if (!actionForLog.empty()) {
314 actionForLog.append(",");
315 }
316 actionForLog.append(std::to_string(static_cast<int32_t>(action)));
317 }
318 LOGD("Support action is %{public}s", actionForLog.c_str());
319 #endif
320 }
321
UpdateCacheInfo(std::list<AccessibilityElementInfo> & infos,uint32_t mode,const RefPtr<AccessibilityNode> & node,const RefPtr<JsAccessibilityManager> & jsAccessibilityManager,int windowId)322 void UpdateCacheInfo(std::list<AccessibilityElementInfo>& infos, uint32_t mode, const RefPtr<AccessibilityNode>& node,
323 const RefPtr<JsAccessibilityManager>& jsAccessibilityManager, int windowId)
324 {
325 // parent
326 uint32_t umode = mode;
327 if (umode & static_cast<uint32_t>(PREFETCH_PREDECESSORS)) {
328 if (node->GetParentId() != -1 && node->GetParentId() != DEFAULT_PARENT_ID) {
329 AccessibilityElementInfo parentNodeInfo;
330 UpdateAccessibilityNodeInfo(node->GetParentNode(), parentNodeInfo, jsAccessibilityManager, windowId);
331 infos.emplace_back(parentNodeInfo);
332 }
333 }
334 // sister/brothers
335 if (umode & static_cast<uint32_t>(PREFETCH_SIBLINGS)) {
336 if (node->GetParentId() != -1 && node->GetParentId() != DEFAULT_PARENT_ID) {
337 for (const auto& item : node->GetParentNode()->GetChildList()) {
338 if (node->GetNodeId() != item->GetNodeId()) {
339 AccessibilityElementInfo siblingNodeInfo;
340 UpdateAccessibilityNodeInfo(item, siblingNodeInfo, jsAccessibilityManager, windowId);
341 infos.emplace_back(siblingNodeInfo);
342 }
343 }
344 }
345 }
346 // children
347 if (umode & static_cast<uint32_t>(PREFETCH_CHILDREN)) {
348 for (const auto& item : node->GetChildList()) {
349 AccessibilityElementInfo childNodeInfo;
350 UpdateAccessibilityNodeInfo(item, childNodeInfo, jsAccessibilityManager, windowId);
351 infos.emplace_back(childNodeInfo);
352 }
353 }
354 }
355
BoolToString(bool tag)356 inline std::string BoolToString(bool tag)
357 {
358 return tag ? "true" : "false";
359 }
360
ConvertInputTypeToString(AceTextCategory type)361 std::string ConvertInputTypeToString(AceTextCategory type)
362 {
363 switch (type) {
364 case AceTextCategory::INPUT_TYPE_DEFAULT:
365 return "INPUT_TYPE_DEFAULT";
366 case AceTextCategory::INPUT_TYPE_TEXT:
367 return "INPUT_TYPE_TEXT";
368 case AceTextCategory::INPUT_TYPE_EMAIL:
369 return "INPUT_TYPE_EMAIL";
370 case AceTextCategory::INPUT_TYPE_DATE:
371 return "INPUT_TYPE_DATE";
372 case AceTextCategory::INPUT_TYPE_TIME:
373 return "INPUT_TYPE_TIME";
374 case AceTextCategory::INPUT_TYPE_NUMBER:
375 return "INPUT_TYPE_NUMBER";
376 case AceTextCategory::INPUT_TYPE_PASSWORD:
377 return "INPUT_TYPE_PASSWORD";
378 default:
379 return "illegal input type";
380 }
381 }
382
FindAccessibilityFocus(const RefPtr<AccessibilityNode> & node,RefPtr<AccessibilityNode> & resultNode)383 bool FindAccessibilityFocus(const RefPtr<AccessibilityNode>& node, RefPtr<AccessibilityNode>& resultNode)
384 {
385 if (node->GetAccessibilityFocusedState()) {
386 resultNode = node;
387 LOGI("FindFocus nodeId(%{public}d)", resultNode->GetNodeId());
388 return true;
389 }
390 if (!node->GetChildList().empty()) {
391 for (const auto& item : node->GetChildList()) {
392 if (resultNode != nullptr) {
393 return true;
394 }
395 if (FindAccessibilityFocus(item, resultNode)) {
396 LOGI("FindFocus nodeId:%{public}d", item->GetNodeId());
397 return true;
398 }
399 }
400 }
401
402 return false;
403 }
404
FindAccessibilityFocus(const RefPtr<NG::UINode> & node)405 RefPtr<NG::FrameNode> FindAccessibilityFocus(const RefPtr<NG::UINode>& node)
406 {
407 auto frameNode = AceType::DynamicCast<NG::FrameNode>(node);
408 if (frameNode) {
409 if (frameNode->GetRenderContext()->GetAccessibilityFocus().value_or(false)) {
410 LOGI("FindFocus nodeId(%{public}d)", node->GetAccessibilityId());
411 return frameNode;
412 }
413 }
414
415 if (!node->GetChildren().empty()) {
416 for (const auto& child : node->GetChildren()) {
417 auto result = FindAccessibilityFocus(child);
418 if (result) {
419 return result;
420 }
421 }
422 }
423 return nullptr;
424 }
425
FindInputFocus(const RefPtr<AccessibilityNode> & node,RefPtr<AccessibilityNode> & resultNode)426 bool FindInputFocus(const RefPtr<AccessibilityNode>& node, RefPtr<AccessibilityNode>& resultNode)
427 {
428 CHECK_NULL_RETURN_NOLOG(node, false);
429 if (!node->GetFocusedState() && (node->GetParentId() != -1)) {
430 return false;
431 }
432 if (node->GetFocusedState()) {
433 resultNode = node;
434 LOGI("FindFocus nodeId:%{public}d", resultNode->GetNodeId());
435 }
436 if (!node->GetChildList().empty()) {
437 for (const auto& item : node->GetChildList()) {
438 if (FindInputFocus(item, resultNode)) {
439 return true;
440 }
441 }
442 }
443 return node->GetFocusedState();
444 }
445
FindInputFocus(const RefPtr<NG::UINode> & node)446 RefPtr<NG::FrameNode> FindInputFocus(const RefPtr<NG::UINode>& node)
447 {
448 auto frameNode = AceType::DynamicCast<NG::FrameNode>(node);
449 CHECK_NULL_RETURN_NOLOG(frameNode, nullptr);
450 if (!(frameNode->GetFocusHub() ? frameNode->GetFocusHub()->IsCurrentFocus() : false)) {
451 return nullptr;
452 }
453
454 if (frameNode->GetFocusHub()->IsChild()) {
455 LOGI("FoundFocus nodeId(%{public}d)", node->GetAccessibilityId());
456 if (frameNode->IsInternal()) {
457 return frameNode->GetFocusParent();
458 }
459 return frameNode;
460 }
461
462 auto focusHub = frameNode->GetFocusHub();
463 auto focusChildren = focusHub->GetChildren();
464 for (const auto& focusChild : focusChildren) {
465 auto childNode = FindInputFocus(focusChild->GetFrameNode());
466 if (childNode) {
467 return childNode;
468 }
469 }
470 return nullptr;
471 }
472
FindText(const RefPtr<AccessibilityNode> & node,const std::string & text,std::list<RefPtr<AccessibilityNode>> & nodeList)473 void FindText(
474 const RefPtr<AccessibilityNode>& node, const std::string& text, std::list<RefPtr<AccessibilityNode>>& nodeList)
475 {
476 CHECK_NULL_VOID_NOLOG(node);
477 if (node->GetText().find(text) != std::string::npos) {
478 LOGI("FindText find nodeId(%{public}d)", node->GetNodeId());
479 nodeList.push_back(node);
480 }
481 if (!node->GetChildList().empty()) {
482 for (const auto& child : node->GetChildList()) {
483 FindText(child, text, nodeList);
484 }
485 }
486 }
487
FindText(const RefPtr<NG::UINode> & node,const std::string & text,std::list<RefPtr<NG::FrameNode>> & nodeList)488 void FindText(const RefPtr<NG::UINode>& node, const std::string& text, std::list<RefPtr<NG::FrameNode>>& nodeList)
489 {
490 CHECK_NULL_VOID(node);
491
492 auto frameNode = AceType::DynamicCast<NG::FrameNode>(node);
493 if (frameNode && !frameNode->IsInternal()) {
494 if (frameNode->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText().find(text) !=
495 std::string::npos) {
496 LOGI("FindText find nodeId(%{public}d)", frameNode->GetAccessibilityId());
497 nodeList.push_back(frameNode);
498 }
499 }
500
501 if (!node->GetChildren().empty()) {
502 for (const auto& child : node->GetChildren()) {
503 FindText(child, text, nodeList);
504 }
505 }
506 }
507
GetInspectorById(const RefPtr<NG::FrameNode> & root,int32_t id)508 RefPtr<NG::FrameNode> GetInspectorById(const RefPtr<NG::FrameNode>& root, int32_t id)
509 {
510 CHECK_NULL_RETURN(root, nullptr);
511 std::queue<RefPtr<NG::UINode>> nodes;
512 nodes.push(root);
513 RefPtr<NG::FrameNode> frameNode;
514 while (!nodes.empty()) {
515 auto current = nodes.front();
516 nodes.pop();
517 frameNode = AceType::DynamicCast<NG::FrameNode>(current);
518 if (frameNode != nullptr) {
519 if (id == frameNode->GetAccessibilityId()) {
520 return frameNode;
521 }
522 }
523 const auto& children = current->GetChildren();
524 for (const auto& child : children) {
525 nodes.push(child);
526 }
527 }
528 return nullptr;
529 }
530
GetFrameNodeChildren(const RefPtr<NG::UINode> & uiNode,std::vector<int32_t> & children,int32_t pageId)531 void GetFrameNodeChildren(const RefPtr<NG::UINode>& uiNode, std::vector<int32_t>& children, int32_t pageId)
532 {
533 if (AceType::InstanceOf<NG::FrameNode>(uiNode)) {
534 if (uiNode->GetTag() == "stage") {
535 } else if (uiNode->GetTag() == "page") {
536 if (uiNode->GetPageId() != pageId) {
537 return;
538 }
539 } else {
540 auto frameNode = AceType::DynamicCast<NG::FrameNode>(uiNode);
541 if (!frameNode->IsInternal()) {
542 children.emplace_back(uiNode->GetAccessibilityId());
543 return;
544 }
545 }
546 }
547
548 for (const auto& frameChild : uiNode->GetChildren()) {
549 GetFrameNodeChildren(frameChild, children, pageId);
550 }
551 }
552
GetFrameNodeChildren(const RefPtr<NG::UINode> & uiNode,std::list<RefPtr<NG::FrameNode>> & children)553 void GetFrameNodeChildren(const RefPtr<NG::UINode>& uiNode, std::list<RefPtr<NG::FrameNode>>& children)
554 {
555 if (AceType::InstanceOf<NG::FrameNode>(uiNode)) {
556 auto frameNode = AceType::DynamicCast<NG::FrameNode>(uiNode);
557 if (!frameNode->IsInternal()) {
558 children.emplace_back(frameNode);
559 }
560 } else {
561 for (const auto& frameChild : uiNode->GetChildren()) {
562 GetFrameNodeChildren(frameChild, children);
563 }
564 }
565 }
566
GetParentId(const RefPtr<NG::UINode> & uiNode)567 int32_t GetParentId(const RefPtr<NG::UINode>& uiNode)
568 {
569 auto parent = uiNode->GetParent();
570 while (parent) {
571 if (AceType::InstanceOf<NG::FrameNode>(parent)) {
572 return parent->GetAccessibilityId();
573 }
574 parent = parent->GetParent();
575 }
576 return INVALID_PARENT_ID;
577 }
578
FillEventInfo(const RefPtr<NG::FrameNode> & node,AccessibilityEventInfo & eventInfo)579 void FillEventInfo(const RefPtr<NG::FrameNode>& node, AccessibilityEventInfo& eventInfo)
580 {
581 eventInfo.SetComponentType(node->GetTag());
582 eventInfo.SetPageId(node->GetPageId());
583 eventInfo.AddContent(node->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText());
584 eventInfo.SetLatestContent(node->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText());
585 }
586
FillEventInfo(const RefPtr<AccessibilityNode> & node,AccessibilityEventInfo & eventInfo)587 void FillEventInfo(const RefPtr<AccessibilityNode>& node, AccessibilityEventInfo& eventInfo)
588 {
589 eventInfo.SetComponentType(node->GetTag());
590 if (node->GetTag() == LIST_TAG) {
591 eventInfo.SetItemCounts(node->GetListItemCounts());
592 eventInfo.SetBeginIndex(node->GetListBeginIndex());
593 eventInfo.SetEndIndex(node->GetListEndIndex());
594 }
595 eventInfo.SetPageId(node->GetPageId());
596 eventInfo.AddContent(node->GetText());
597 eventInfo.SetLatestContent(node->GetText());
598 }
599
UpdateSupportAction(const RefPtr<NG::FrameNode> & node,AccessibilityElementInfo & nodeInfo)600 void UpdateSupportAction(const RefPtr<NG::FrameNode>& node, AccessibilityElementInfo& nodeInfo)
601 {
602 auto gestureEventHub = node->GetEventHub<NG::EventHub>()->GetGestureEventHub();
603 if (gestureEventHub) {
604 nodeInfo.SetClickable(gestureEventHub->IsClickable());
605 if (gestureEventHub->IsClickable()) {
606 AccessibleAction action(ACCESSIBILITY_ACTION_CLICK, "ace");
607 nodeInfo.AddAction(action);
608 }
609 nodeInfo.SetLongClickable(gestureEventHub->IsLongClickable());
610 if (gestureEventHub->IsLongClickable()) {
611 AccessibleAction action(ACCESSIBILITY_ACTION_LONG_CLICK, "ace");
612 nodeInfo.AddAction(action);
613 }
614 }
615 if (nodeInfo.IsFocusable()) {
616 AccessibleAction action(ACCESSIBILITY_ACTION_FOCUS, "ace");
617 nodeInfo.AddAction(action);
618 }
619 }
620
UpdateAccessibilityElementInfo(const RefPtr<NG::FrameNode> & node,const CommonProperty & commonProperty,AccessibilityElementInfo & nodeInfo)621 void UpdateAccessibilityElementInfo(
622 const RefPtr<NG::FrameNode>& node, const CommonProperty& commonProperty, AccessibilityElementInfo& nodeInfo)
623 {
624 NG::RectF rect;
625 if (node->IsActive()) {
626 rect = node->GetTransformRectRelativeToWindow();
627 }
628 nodeInfo.SetParent(GetParentId(node));
629 std::vector<int32_t> children;
630 for (const auto& item : node->GetChildren()) {
631 GetFrameNodeChildren(item, children, commonProperty.pageId);
632 }
633 for (const auto& child : children) {
634 nodeInfo.AddChild(child);
635 }
636
637 auto accessibilityProperty = node->GetAccessibilityProperty<NG::AccessibilityProperty>();
638 nodeInfo.SetAccessibilityId(node->GetAccessibilityId());
639 nodeInfo.SetComponentType(node->GetTag());
640 nodeInfo.SetEnabled(node->GetFocusHub() ? node->GetFocusHub()->IsEnabled() : true);
641 nodeInfo.SetFocusable(node->GetFocusHub() ? node->GetFocusHub()->IsFocusable() : false);
642 nodeInfo.SetFocused(node->GetFocusHub() ? node->GetFocusHub()->IsCurrentFocus() : false);
643 nodeInfo.SetAccessibilityFocus(node->GetRenderContext()->GetAccessibilityFocus().value_or(false));
644 nodeInfo.SetInspectorKey(node->GetInspectorId().value_or(""));
645 nodeInfo.SetContent(accessibilityProperty->GetText());
646 nodeInfo.SetVisible(node->IsVisible());
647 if (node->IsVisible()) {
648 auto left = rect.Left() + commonProperty.windowLeft;
649 auto top = rect.Top() + commonProperty.windowTop;
650 auto right = rect.Right() + commonProperty.windowLeft;
651 auto bottom = rect.Bottom() + commonProperty.windowTop;
652 Accessibility::Rect bounds { left, top, right, bottom };
653 nodeInfo.SetRectInScreen(bounds);
654 }
655
656 if (accessibilityProperty->HasRange()) {
657 RangeInfo rangeInfo = ConvertAccessibilityValue(accessibilityProperty->GetAccessibilityValue());
658 nodeInfo.SetRange(rangeInfo);
659 }
660
661 nodeInfo.SetWindowId(commonProperty.windowId);
662 nodeInfo.SetPageId(node->GetPageId());
663 nodeInfo.SetPagePath(commonProperty.pagePath);
664 nodeInfo.SetBundleName(AceApplicationInfo::GetInstance().GetPackageName());
665
666 UpdateSupportAction(node, nodeInfo);
667 }
668
669 // focus move search
AddFocusableNode(std::list<RefPtr<NG::FrameNode>> & nodeList,const RefPtr<NG::FrameNode> & node)670 void AddFocusableNode(std::list<RefPtr<NG::FrameNode>>& nodeList, const RefPtr<NG::FrameNode>& node)
671 {
672 nodeList.emplace_back(node);
673
674 std::list<RefPtr<NG::FrameNode>> children;
675 for (const auto& child : node->GetChildren()) {
676 GetFrameNodeChildren(child, children);
677 }
678
679 for (const auto& child : children) {
680 AddFocusableNode(nodeList, child);
681 }
682 }
683
GetNextFocusableNode(const std::list<RefPtr<NG::FrameNode>> & nodeList,RefPtr<NG::FrameNode> & node)684 RefPtr<NG::FrameNode> GetNextFocusableNode(
685 const std::list<RefPtr<NG::FrameNode>>& nodeList, RefPtr<NG::FrameNode>& node)
686 {
687 auto nodeItem = nodeList.begin();
688 for (; nodeItem != nodeList.end(); nodeItem++) {
689 if ((*nodeItem)->GetAccessibilityId() == node->GetAccessibilityId()) {
690 break;
691 }
692 }
693
694 if (nodeItem != nodeList.end()) {
695 if (++nodeItem != nodeList.end()) {
696 return (*nodeItem);
697 }
698 }
699 if (!nodeList.empty()) {
700 return (*nodeList.begin());
701 }
702
703 return nullptr;
704 }
705
GetPreviousFocusableNode(const std::list<RefPtr<NG::FrameNode>> & nodeList,RefPtr<NG::FrameNode> & node)706 RefPtr<NG::FrameNode> GetPreviousFocusableNode(
707 const std::list<RefPtr<NG::FrameNode>>& nodeList, RefPtr<NG::FrameNode>& node)
708 {
709 auto nodeItem = nodeList.rbegin();
710 for (; nodeItem != nodeList.rend(); nodeItem++) {
711 if ((*nodeItem)->GetAccessibilityId() == node->GetAccessibilityId()) {
712 break;
713 }
714 }
715
716 if (nodeItem != nodeList.rend()) {
717 if (++nodeItem != nodeList.rend()) {
718 return (*nodeItem);
719 }
720 }
721 if (!nodeList.empty()) {
722 return (*nodeList.rbegin());
723 }
724
725 return nullptr;
726 }
727
FindNodeInRelativeDirection(const std::list<RefPtr<NG::FrameNode>> & nodeList,RefPtr<NG::FrameNode> & node,int direction)728 RefPtr<NG::FrameNode> FindNodeInRelativeDirection(
729 const std::list<RefPtr<NG::FrameNode>>& nodeList, RefPtr<NG::FrameNode>& node, int direction)
730 {
731 switch (direction) {
732 case FocusMoveDirection::FORWARD:
733 return GetNextFocusableNode(nodeList, node);
734 case FocusMoveDirection::BACKWARD:
735 return GetPreviousFocusableNode(nodeList, node);
736 default:
737 break;
738 }
739
740 return nullptr;
741 }
742
FindNodeInAbsoluteDirection(const std::list<RefPtr<NG::FrameNode>> & nodeList,RefPtr<NG::FrameNode> & node,const int direction)743 RefPtr<NG::FrameNode> FindNodeInAbsoluteDirection(
744 const std::list<RefPtr<NG::FrameNode>>& nodeList, RefPtr<NG::FrameNode>& node, const int direction)
745 {
746 NG::RectF rect = node->GetTransformRectRelativeToWindow();
747 auto left = rect.Left();
748 auto top = rect.Top();
749 auto width = rect.Width();
750 auto height = rect.Height();
751 Rect tempBest(left, top, width, height);
752 auto nodeRect = tempBest;
753 switch (direction) {
754 case FocusMoveDirection::LEFT:
755 tempBest.SetLeft(left + width + 1);
756 break;
757 case FocusMoveDirection::RIGHT:
758 tempBest.SetLeft(left - width - 1);
759 break;
760 case FocusMoveDirection::UP:
761 tempBest.SetTop(top + height + 1);
762 break;
763 case FocusMoveDirection::DOWN:
764 tempBest.SetTop(top - height - 1);
765 break;
766 default:
767 break;
768 }
769
770 RefPtr<NG::FrameNode> nearestNode = nullptr;
771 for (const auto& nodeItem : nodeList) {
772 if (nodeItem->GetAccessibilityId() == node->GetAccessibilityId() || nodeItem->IsRootNode()) {
773 continue;
774 }
775 rect = nodeItem->GetTransformRectRelativeToWindow();
776 Rect itemRect(rect.Left(), rect.Top(), rect.Width(), rect.Height());
777 if (CheckBetterRect(nodeRect, direction, itemRect, tempBest)) {
778 tempBest = itemRect;
779 nearestNode = nodeItem;
780 }
781 }
782 LOGI("found %{public}d", nearestNode ? nearestNode->GetAccessibilityId() : -1);
783 return nearestNode;
784 }
785
786 // execute action
RequestFocus(RefPtr<NG::FrameNode> & frameNode)787 bool RequestFocus(RefPtr<NG::FrameNode>& frameNode)
788 {
789 auto focusHub = frameNode->GetFocusHub();
790 CHECK_NULL_RETURN_NOLOG(focusHub, false);
791 return focusHub->RequestFocusImmediately();
792 }
793
ActClick(RefPtr<NG::FrameNode> & frameNode)794 bool ActClick(RefPtr<NG::FrameNode>& frameNode)
795 {
796 auto gesture = frameNode->GetEventHub<NG::EventHub>()->GetGestureEventHub();
797 CHECK_NULL_RETURN_NOLOG(gesture, false);
798 return gesture->ActClick();
799 }
800
ActLongClick(RefPtr<NG::FrameNode> & frameNode)801 bool ActLongClick(RefPtr<NG::FrameNode>& frameNode)
802 {
803 auto gesture = frameNode->GetEventHub<NG::EventHub>()->GetGestureEventHub();
804 CHECK_NULL_RETURN_NOLOG(gesture, false);
805 return gesture->ActLongClick();
806 }
807
ClearAccessibilityFocus(const RefPtr<NG::FrameNode> & root,int32_t focusNodeId)808 void ClearAccessibilityFocus(const RefPtr<NG::FrameNode>& root, int32_t focusNodeId)
809 {
810 auto oldFocusNode = GetInspectorById(root, focusNodeId);
811 CHECK_NULL_VOID_NOLOG(oldFocusNode);
812 oldFocusNode->GetRenderContext()->OnAccessibilityFocusUpdate(false);
813 }
814
815 } // namespace
816
~JsAccessibilityManager()817 JsAccessibilityManager::~JsAccessibilityManager()
818 {
819 auto eventType = AccessibilityStateEventType::EVENT_ACCESSIBILITY_STATE_CHANGED;
820
821 UnsubscribeStateObserver(eventType);
822 UnsubscribeToastObserver();
823
824 DeregisterInteractionOperation();
825 }
OnConfigChanged(const AccessibilityConfig::CONFIG_ID id,const AccessibilityConfig::ConfigValue & value)826 void JsAccessibilityManager::ToastAccessibilityConfigObserver::OnConfigChanged(
827 const AccessibilityConfig::CONFIG_ID id, const AccessibilityConfig::ConfigValue& value)
828 {
829 LOGD("accessibility content timeout changed:%{public}u", value.contentTimeout);
830 AceApplicationInfo::GetInstance().SetBarrierfreeDuration((int32_t)value.contentTimeout);
831 }
832
SubscribeToastObserver()833 bool JsAccessibilityManager::SubscribeToastObserver()
834 {
835 LOGD("SubscribeToastObserver");
836 if (!toastObserver_) {
837 toastObserver_ = std::make_shared<ToastAccessibilityConfigObserver>();
838 }
839 CHECK_NULL_RETURN_NOLOG(toastObserver_, false);
840 auto& config = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
841 bool isSuccess = config.InitializeContext();
842 if (!isSuccess) {
843 LOGE("AccessibilityConfig InitializeContext failed");
844 return false;
845 }
846 config.SubscribeConfigObserver(CONFIG_CONTENT_TIMEOUT, toastObserver_);
847 return true;
848 }
849
UnsubscribeToastObserver()850 bool JsAccessibilityManager::UnsubscribeToastObserver()
851 {
852 LOGI("UnsubscribeToastObserver");
853 CHECK_NULL_RETURN_NOLOG(toastObserver_, false);
854 auto& config = OHOS::AccessibilityConfig::AccessibilityConfig::GetInstance();
855 bool isSuccess = config.InitializeContext();
856 if (!isSuccess) {
857 LOGE("AccessibilityConfig InitializeContext failed");
858 return false;
859 }
860 config.UnsubscribeConfigObserver(CONFIG_CONTENT_TIMEOUT, toastObserver_);
861 return true;
862 }
863
SubscribeStateObserver(const int eventType)864 bool JsAccessibilityManager::SubscribeStateObserver(const int eventType)
865 {
866 LOGD("SubscribeStateObserver");
867 if (!stateObserver_) {
868 stateObserver_ = std::make_shared<JsAccessibilityStateObserver>();
869 }
870
871 stateObserver_->SetHandler(WeakClaim(this));
872
873 auto instance = AccessibilitySystemAbilityClient::GetInstance();
874 CHECK_NULL_RETURN_NOLOG(instance, false);
875 Accessibility::RetError ret = instance->SubscribeStateObserver(stateObserver_, eventType);
876 LOGD("SubscribeStateObserver:%{public}d", ret);
877 return ret == RET_OK;
878 }
879
UnsubscribeStateObserver(const int eventType)880 bool JsAccessibilityManager::UnsubscribeStateObserver(const int eventType)
881 {
882 LOGI("UnsubscribeStateObserver");
883 CHECK_NULL_RETURN_NOLOG(stateObserver_, false);
884 std::shared_ptr<AccessibilitySystemAbilityClient> instance = AccessibilitySystemAbilityClient::GetInstance();
885 CHECK_NULL_RETURN_NOLOG(instance, false);
886 Accessibility::RetError ret = instance->UnsubscribeStateObserver(stateObserver_, eventType);
887 LOGI("UnsubscribeStateObserver:%{public}d", ret);
888 return ret == RET_OK;
889 }
890
InitializeCallback()891 void JsAccessibilityManager::InitializeCallback()
892 {
893 LOGD("InitializeCallback");
894 if (IsRegister()) {
895 return;
896 }
897
898 auto pipelineContext = GetPipelineContext().Upgrade();
899 CHECK_NULL_VOID_NOLOG(pipelineContext);
900 windowId_ = pipelineContext->GetWindowId();
901
902 auto client = AccessibilitySystemAbilityClient::GetInstance();
903 CHECK_NULL_VOID_NOLOG(client);
904 bool isEnabled = false;
905 client->IsEnabled(isEnabled);
906 AceApplicationInfo::GetInstance().SetAccessibilityEnabled(isEnabled);
907
908 SubscribeToastObserver();
909 SubscribeStateObserver(AccessibilityStateEventType::EVENT_ACCESSIBILITY_STATE_CHANGED);
910 if (isEnabled) {
911 RegisterInteractionOperation(windowId_);
912 }
913 }
914
SendAccessibilitySyncEvent(const AccessibilityEvent & accessibilityEvent,AccessibilityEventInfo eventInfo)915 bool JsAccessibilityManager::SendAccessibilitySyncEvent(
916 const AccessibilityEvent& accessibilityEvent, AccessibilityEventInfo eventInfo)
917 {
918 if (!IsRegister()) {
919 return false;
920 }
921
922 auto client = AccessibilitySystemAbilityClient::GetInstance();
923 CHECK_NULL_RETURN(client, false);
924 bool isEnabled = false;
925 client->IsEnabled(isEnabled);
926 if (!isEnabled) {
927 return false;
928 }
929
930 LOGD("type:%{public}s nodeId:%{public}d", accessibilityEvent.eventType.c_str(), accessibilityEvent.nodeId);
931
932 Accessibility::EventType type = Accessibility::EventType::TYPE_VIEW_INVALID;
933 if (accessibilityEvent.type != AccessibilityEventType::UNKNOWN) {
934 type = ConvertAceEventType(accessibilityEvent.type);
935 } else {
936 type = ConvertStrToEventType(accessibilityEvent.eventType);
937 }
938
939 if (type == Accessibility::EventType::TYPE_VIEW_INVALID) {
940 return false;
941 }
942
943 eventInfo.SetSource(accessibilityEvent.nodeId);
944 eventInfo.SetEventType(type);
945 eventInfo.SetCurrentIndex(static_cast<int>(accessibilityEvent.currentItemIndex));
946 eventInfo.SetItemCounts(static_cast<int>(accessibilityEvent.itemCount));
947 eventInfo.SetBundleName(AceApplicationInfo::GetInstance().GetPackageName());
948
949 return client->SendEvent(eventInfo);
950 }
951
SendAccessibilityAsyncEvent(const AccessibilityEvent & accessibilityEvent)952 void JsAccessibilityManager::SendAccessibilityAsyncEvent(const AccessibilityEvent& accessibilityEvent)
953 {
954 auto context = GetPipelineContext().Upgrade();
955 CHECK_NULL_VOID_NOLOG(context);
956 int32_t windowId = context->GetWindowId();
957 if (windowId == 0) {
958 return;
959 }
960
961 AccessibilityEventInfo eventInfo;
962 if (AceType::InstanceOf<NG::PipelineContext>(context)) {
963 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(context);
964 auto node = GetInspectorById(ngPipeline->GetRootElement(), accessibilityEvent.nodeId);
965 CHECK_NULL_VOID_NOLOG(node);
966 FillEventInfo(node, eventInfo);
967 } else {
968 auto node = GetAccessibilityNodeFromPage(accessibilityEvent.nodeId);
969 CHECK_NULL_VOID_NOLOG(node);
970 FillEventInfo(node, eventInfo);
971 }
972 eventInfo.SetWindowId(windowId);
973
974 context->GetTaskExecutor()->PostTask(
975 [weak = WeakClaim(this), accessibilityEvent, eventInfo] {
976 auto jsAccessibilityManager = weak.Upgrade();
977 CHECK_NULL_VOID(jsAccessibilityManager);
978 jsAccessibilityManager->SendAccessibilitySyncEvent(accessibilityEvent, eventInfo);
979 },
980 TaskExecutor::TaskType::BACKGROUND);
981 }
982
UpdateNodeChildIds(const RefPtr<AccessibilityNode> & node)983 void JsAccessibilityManager::UpdateNodeChildIds(const RefPtr<AccessibilityNode>& node)
984 {
985 CHECK_NULL_VOID_NOLOG(node);
986 node->ActionUpdateIds();
987 const auto& children = node->GetChildList();
988 std::vector<int32_t> childrenVec;
989 auto cardId = GetCardId();
990 auto rootNodeId = GetRootNodeId();
991
992 // get last stack children to barrier free service.
993 if ((node->GetNodeId() == GetRootNodeId() + ROOT_STACK_BASE) && !children.empty() && !IsDeclarative()) {
994 auto lastChildNodeId = children.back()->GetNodeId();
995 if (isOhosHostCard()) {
996 childrenVec.emplace_back(ConvertToCardAccessibilityId(lastChildNodeId, cardId, rootNodeId));
997 } else {
998 childrenVec.emplace_back(lastChildNodeId);
999 for (const auto& child : children) {
1000 if (child->GetNodeId() == ROOT_DECOR_BASE - 1) {
1001 childrenVec.emplace_back(child->GetNodeId());
1002 break;
1003 }
1004 }
1005 }
1006 } else {
1007 childrenVec.resize(children.size());
1008 if (isOhosHostCard()) {
1009 std::transform(children.begin(), children.end(), childrenVec.begin(),
1010 [cardId, rootNodeId](const RefPtr<AccessibilityNode>& child) {
1011 return ConvertToCardAccessibilityId(child->GetNodeId(), cardId, rootNodeId);
1012 });
1013 } else {
1014 std::transform(children.begin(), children.end(), childrenVec.begin(),
1015 [](const RefPtr<AccessibilityNode>& child) { return child->GetNodeId(); });
1016 }
1017 }
1018 node->SetChildIds(childrenVec);
1019 }
1020
DumpHandleEvent(const std::vector<std::string> & params)1021 void JsAccessibilityManager::DumpHandleEvent(const std::vector<std::string>& params)
1022 {
1023 if (!(params.size() == EVENT_DUMP_PARAM_LENGTH_LOWER || params.size() == EVENT_DUMP_PARAM_LENGTH_UPPER)) {
1024 DumpLog::GetInstance().Print("Error: params length is illegal!");
1025 return;
1026 }
1027 if (params[EVENT_DUMP_ORDER_INDEX] != DUMP_ORDER && params[EVENT_DUMP_ORDER_INDEX] != DUMP_INSPECTOR) {
1028 DumpLog::GetInstance().Print("Error: not accessibility dump order!");
1029 return;
1030 }
1031
1032 auto pipeline = context_.Upgrade();
1033 CHECK_NULL_VOID(pipeline);
1034 int32_t nodeId = StringUtils::StringToInt(params[EVENT_DUMP_ID_INDEX]);
1035 auto action = static_cast<AceAction>(StringUtils::StringToInt(params[EVENT_DUMP_ACTION_INDEX]));
1036 auto op = ConvertAceAction(action);
1037 if (AceType::InstanceOf<NG::PipelineContext>(pipeline)) {
1038 pipeline->GetTaskExecutor()->PostTask(
1039 [weak = WeakClaim(this), op, nodeId]() {
1040 auto jsAccessibilityManager = weak.Upgrade();
1041 CHECK_NULL_VOID(jsAccessibilityManager);
1042 jsAccessibilityManager->ExecuteActionNG(nodeId, op);
1043 },
1044 TaskExecutor::TaskType::UI);
1045 return;
1046 }
1047
1048 auto node = GetAccessibilityNodeFromPage(nodeId);
1049 CHECK_NULL_VOID(node);
1050
1051 std::string eventParams;
1052 if (params.size() == EVENT_DUMP_PARAM_LENGTH_UPPER) {
1053 eventParams = params[EVENT_DUMP_ACTION_PARAM_INDEX];
1054 }
1055 std::map<std::string, std::string> paramsMap;
1056 if (op == ActionType::ACCESSIBILITY_ACTION_SET_TEXT) {
1057 paramsMap = { { ACTION_ARGU_SET_TEXT, eventParams } };
1058 }
1059
1060 pipeline->GetTaskExecutor()->PostTask(
1061 [weak = WeakClaim(this), op, node, paramsMap, pipeline]() {
1062 auto jsAccessibilityManager = weak.Upgrade();
1063 CHECK_NULL_VOID(jsAccessibilityManager);
1064 jsAccessibilityManager->AccessibilityActionEvent(
1065 op, paramsMap, node, AceType::DynamicCast<PipelineContext>(pipeline));
1066 },
1067 TaskExecutor::TaskType::UI);
1068 }
1069
DumpProperty(const std::vector<std::string> & params)1070 void JsAccessibilityManager::DumpProperty(const std::vector<std::string>& params)
1071 {
1072 CHECK_NULL_VOID_NOLOG(DumpLog::GetInstance().GetDumpFile());
1073 if (params.empty()) {
1074 DumpLog::GetInstance().Print("Error: params cannot be empty!");
1075 return;
1076 }
1077 if (params.size() != PROPERTY_DUMP_PARAM_LENGTH) {
1078 DumpLog::GetInstance().Print("Error: params length is illegal!");
1079 return;
1080 }
1081 if (params[0] != DUMP_ORDER && params[0] != DUMP_INSPECTOR) {
1082 DumpLog::GetInstance().Print("Error: not accessibility dump order!");
1083 return;
1084 }
1085
1086 auto node = GetAccessibilityNodeFromPage(StringUtils::StringToInt(params[1]));
1087 if (!node) {
1088 DumpLog::GetInstance().Print("Error: can't find node with ID " + params[1]);
1089 return;
1090 }
1091
1092 const auto& supportAceActions = node->GetSupportAction();
1093 std::string actionForDump;
1094 for (const auto& action : supportAceActions) {
1095 if (!actionForDump.empty()) {
1096 actionForDump.append(",");
1097 }
1098 actionForDump.append(std::to_string(static_cast<int32_t>(action)));
1099 }
1100
1101 const auto& charValue = node->GetChartValue();
1102
1103 DumpLog::GetInstance().AddDesc("ID: ", node->GetNodeId());
1104 DumpLog::GetInstance().AddDesc("parent ID: ", node->GetParentId());
1105 DumpLog::GetInstance().AddDesc("child IDs: ", GetNodeChildIds(node));
1106 DumpLog::GetInstance().AddDesc("component type: ", node->GetTag());
1107 DumpLog::GetInstance().AddDesc("input type: ", node->GetInputType());
1108 DumpLog::GetInstance().AddDesc("text: ", node->GetText());
1109 DumpLog::GetInstance().AddDesc("width: ", node->GetWidth());
1110 DumpLog::GetInstance().AddDesc("height: ", node->GetHeight());
1111 DumpLog::GetInstance().AddDesc("left: ", node->GetLeft() + GetCardOffset().GetX());
1112 DumpLog::GetInstance().AddDesc("top: ", node->GetTop() + GetCardOffset().GetY());
1113 DumpLog::GetInstance().AddDesc("enabled: ", BoolToString(node->GetEnabledState()));
1114 DumpLog::GetInstance().AddDesc("checked: ", BoolToString(node->GetCheckedState()));
1115 DumpLog::GetInstance().AddDesc("selected: ", BoolToString(node->GetSelectedState()));
1116 DumpLog::GetInstance().AddDesc("focusable: ", BoolToString(node->GetFocusableState()));
1117 DumpLog::GetInstance().AddDesc("focused: ", BoolToString(node->GetFocusedState()));
1118 DumpLog::GetInstance().AddDesc("checkable: ", BoolToString(node->GetCheckableState()));
1119 DumpLog::GetInstance().AddDesc("clickable: ", BoolToString(node->GetClickableState()));
1120 DumpLog::GetInstance().AddDesc("long clickable: ", BoolToString(node->GetLongClickableState()));
1121 DumpLog::GetInstance().AddDesc("scrollable: ", BoolToString(node->GetScrollableState()));
1122 DumpLog::GetInstance().AddDesc("editable: ", BoolToString(node->GetEditable()));
1123 DumpLog::GetInstance().AddDesc("hint text: ", node->GetHintText());
1124 DumpLog::GetInstance().AddDesc("error text: ", node->GetErrorText());
1125 DumpLog::GetInstance().AddDesc("js component id: ", node->GetJsComponentId());
1126 DumpLog::GetInstance().AddDesc("accessibility label: ", node->GetAccessibilityLabel());
1127 DumpLog::GetInstance().AddDesc("accessibility hint: ", node->GetAccessibilityHint());
1128 DumpLog::GetInstance().AddDesc("max text length: ", node->GetMaxTextLength());
1129 DumpLog::GetInstance().AddDesc("text selection start: ", node->GetTextSelectionStart());
1130 DumpLog::GetInstance().AddDesc("text selection end: ", node->GetTextSelectionEnd());
1131 DumpLog::GetInstance().AddDesc("is multi line: ", BoolToString(node->GetIsMultiLine()));
1132 DumpLog::GetInstance().AddDesc("is password", BoolToString(node->GetIsPassword()));
1133 DumpLog::GetInstance().AddDesc("text input type: ", ConvertInputTypeToString(node->GetTextInputType()));
1134 DumpLog::GetInstance().AddDesc("min value: ", node->GetAccessibilityValue().min);
1135 DumpLog::GetInstance().AddDesc("max value: ", node->GetAccessibilityValue().max);
1136 DumpLog::GetInstance().AddDesc("current value: ", node->GetAccessibilityValue().current);
1137 DumpLog::GetInstance().AddDesc("collection info rows: ", node->GetCollectionInfo().rows);
1138 DumpLog::GetInstance().AddDesc("collection info columns: ", node->GetCollectionInfo().columns);
1139 DumpLog::GetInstance().AddDesc("collection item info, row: ", node->GetCollectionItemInfo().row);
1140 DumpLog::GetInstance().AddDesc("collection item info, column: ", node->GetCollectionItemInfo().column);
1141 DumpLog::GetInstance().AddDesc("chart has value: ", BoolToString(charValue && !charValue->empty()));
1142 DumpLog::GetInstance().AddDesc("accessibilityGroup: ", BoolToString(node->GetAccessible()));
1143 DumpLog::GetInstance().AddDesc("accessibilityImportance: ", node->GetImportantForAccessibility());
1144 DumpLog::GetInstance().AddDesc("support action: ", actionForDump);
1145
1146 DumpLog::GetInstance().Print(0, node->GetTag(), node->GetChildList().size());
1147 }
1148
DumpTreeNG(const RefPtr<NG::FrameNode> & parent,int32_t depth,NodeId nodeID,const CommonProperty & commonProperty)1149 static void DumpTreeNG(
1150 const RefPtr<NG::FrameNode>& parent, int32_t depth, NodeId nodeID, const CommonProperty& commonProperty)
1151 {
1152 auto node = GetInspectorById(parent, nodeID);
1153 if (!node) {
1154 DumpLog::GetInstance().Print("Error: failed to get accessibility node with ID " + std::to_string(nodeID));
1155 return;
1156 }
1157
1158 if (!node->IsActive()) {
1159 return;
1160 }
1161
1162 NG::RectF rect = node->GetTransformRectRelativeToWindow();
1163 DumpLog::GetInstance().AddDesc("ID: " + std::to_string(node->GetAccessibilityId()));
1164 DumpLog::GetInstance().AddDesc("compid: " + node->GetInspectorId().value_or(""));
1165 DumpLog::GetInstance().AddDesc("text: " + node->GetAccessibilityProperty<NG::AccessibilityProperty>()->GetText());
1166 DumpLog::GetInstance().AddDesc("top: " + std::to_string(rect.Top() + commonProperty.windowTop));
1167 DumpLog::GetInstance().AddDesc("left: " + std::to_string(rect.Left() + commonProperty.windowLeft));
1168 DumpLog::GetInstance().AddDesc("width: " + std::to_string(rect.Width()));
1169 DumpLog::GetInstance().AddDesc("height: " + std::to_string(rect.Height()));
1170 DumpLog::GetInstance().AddDesc("visible: " + std::to_string(node->IsVisible()));
1171 auto gestureEventHub = node->GetEventHub<NG::EventHub>()->GetGestureEventHub();
1172 DumpLog::GetInstance().AddDesc(
1173 "clickable: " + std::to_string(gestureEventHub ? gestureEventHub->IsClickable() : false));
1174 DumpLog::GetInstance().AddDesc(
1175 "checkable: " + std::to_string(node->GetAccessibilityProperty<NG::AccessibilityProperty>()->IsCheckable()));
1176
1177 std::vector<int32_t> children;
1178 for (const auto& item : node->GetChildren()) {
1179 GetFrameNodeChildren(item, children, commonProperty.pageId);
1180 }
1181 DumpLog::GetInstance().Print(depth, node->GetTag(), children.size());
1182
1183 for (auto nodeId : children) {
1184 DumpTreeNG(node, depth + 1, nodeId, commonProperty);
1185 }
1186 }
1187
DumpTree(int32_t depth,NodeId nodeID)1188 void JsAccessibilityManager::DumpTree(int32_t depth, NodeId nodeID)
1189 {
1190 auto pipeline = context_.Upgrade();
1191 CHECK_NULL_VOID(pipeline);
1192 if (!AceType::InstanceOf<NG::PipelineContext>(pipeline)) {
1193 AccessibilityNodeManager::DumpTree(depth, nodeID);
1194 } else {
1195 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
1196 auto rootNode = ngPipeline->GetRootElement();
1197 CHECK_NULL_VOID(rootNode);
1198 nodeID = rootNode -> GetAccessibilityId();
1199 auto windowLeft = GetWindowLeft(ngPipeline->GetWindowId());
1200 auto windowTop = GetWindowTop(ngPipeline->GetWindowId());
1201 auto page = ngPipeline->GetStageManager()->GetLastPage();
1202 CHECK_NULL_VOID(page);
1203 auto pageId = page->GetPageId();
1204 auto pagePath = GetPagePath();
1205 CommonProperty commonProperty { ngPipeline->GetWindowId(), windowLeft, windowTop, pageId, pagePath };
1206 DumpTreeNG(rootNode, depth, nodeID, commonProperty);
1207 }
1208 }
1209
SetCardViewParams(const std::string & key,bool focus)1210 void JsAccessibilityManager::SetCardViewParams(const std::string& key, bool focus)
1211 {
1212 LOGD("SetCardViewParams key=%{public}s focus=%{public}d", key.c_str(), focus);
1213 callbackKey_ = key;
1214 if (!callbackKey_.empty()) {
1215 InitializeCallback();
1216 }
1217 }
1218
UpdateViewScale()1219 void JsAccessibilityManager::UpdateViewScale()
1220 {
1221 auto context = GetPipelineContext().Upgrade();
1222 CHECK_NULL_VOID_NOLOG(context);
1223 float scaleX = 1.0;
1224 float scaleY = 1.0;
1225 if (context->GetViewScale(scaleX, scaleY)) {
1226 scaleX_ = scaleX;
1227 scaleY_ = scaleY;
1228 }
1229 }
1230
HandleComponentPostBinding()1231 void JsAccessibilityManager::HandleComponentPostBinding()
1232 {
1233 for (auto targetIter = nodeWithTargetMap_.begin(); targetIter != nodeWithTargetMap_.end();) {
1234 auto nodeWithTarget = targetIter->second.Upgrade();
1235 if (nodeWithTarget) {
1236 if (nodeWithTarget->GetTag() == ACCESSIBILITY_TAG_POPUP) {
1237 auto idNodeIter = nodeWithIdMap_.find(targetIter->first);
1238 if (idNodeIter != nodeWithIdMap_.end()) {
1239 auto nodeWithId = idNodeIter->second.Upgrade();
1240 if (nodeWithId) {
1241 nodeWithId->SetAccessibilityHint(nodeWithTarget->GetText());
1242 } else {
1243 nodeWithIdMap_.erase(idNodeIter);
1244 }
1245 }
1246 }
1247 ++targetIter;
1248 } else {
1249 // clear the disabled node in the maps
1250 nodeWithTargetMap_.erase(targetIter++);
1251 }
1252 }
1253
1254 // clear the disabled node in the maps
1255 for (auto idItem = nodeWithIdMap_.begin(); idItem != nodeWithIdMap_.end();) {
1256 if (!idItem->second.Upgrade()) {
1257 nodeWithIdMap_.erase(idItem++);
1258 } else {
1259 ++idItem;
1260 }
1261 }
1262 }
1263
Create()1264 RefPtr<AccessibilityNodeManager> AccessibilityNodeManager::Create()
1265 {
1266 return AceType::MakeRefPtr<JsAccessibilityManager>();
1267 }
1268
SearchElementInfoByAccessibilityId(const int32_t elementId,const int32_t requestId,AccessibilityElementOperatorCallback & callback,const int32_t mode)1269 void JsAccessibilityManager::JsInteractionOperation::SearchElementInfoByAccessibilityId(const int32_t elementId,
1270 const int32_t requestId, AccessibilityElementOperatorCallback& callback, const int32_t mode)
1271 {
1272 LOGD("elementId(%{public}d) requestId(%{public}d) mode(%{public}d)", elementId, requestId, mode);
1273 auto jsAccessibilityManager = GetHandler().Upgrade();
1274 CHECK_NULL_VOID(jsAccessibilityManager);
1275 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1276 CHECK_NULL_VOID_NOLOG(context);
1277 context->GetTaskExecutor()->PostTask(
1278 [jsAccessibilityManager, elementId, requestId, &callback, mode]() {
1279 CHECK_NULL_VOID(jsAccessibilityManager);
1280 jsAccessibilityManager->SearchElementInfoByAccessibilityId(elementId, requestId, callback, mode);
1281 },
1282 TaskExecutor::TaskType::UI);
1283 }
1284
SearchElementInfoByAccessibilityId(const int32_t elementId,const int32_t requestId,AccessibilityElementOperatorCallback & callback,const int32_t mode)1285 void JsAccessibilityManager::SearchElementInfoByAccessibilityId(const int32_t elementId, const int32_t requestId,
1286 AccessibilityElementOperatorCallback& callback, const int32_t mode)
1287 {
1288 std::list<AccessibilityElementInfo> infos;
1289
1290 auto pipeline = context_.Upgrade();
1291 if (pipeline) {
1292 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
1293 if (ngPipeline) {
1294 SearchElementInfoByAccessibilityIdNG(elementId, mode, infos);
1295 SetSearchElementInfoByAccessibilityIdResult(callback, infos, requestId);
1296 return;
1297 }
1298 }
1299
1300 NodeId nodeId = elementId;
1301 // get root node
1302 if (elementId == -1) {
1303 nodeId = 0;
1304 }
1305 auto weak = WeakClaim(this);
1306 auto jsAccessibilityManager = weak.Upgrade();
1307 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1308 auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage(nodeId);
1309 if (!node) {
1310 LOGW("AccessibilityNodeInfo can't attach component by Id = %{public}d, window:%{public}d", nodeId, windowId_);
1311 SetSearchElementInfoByAccessibilityIdResult(callback, infos, requestId);
1312 return;
1313 }
1314
1315 AccessibilityElementInfo nodeInfo;
1316 UpdateAccessibilityNodeInfo(node, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_);
1317 infos.push_back(nodeInfo);
1318 // cache parent/siblings/children infos
1319 UpdateCacheInfo(infos, mode, node, jsAccessibilityManager, jsAccessibilityManager->windowId_);
1320
1321 SetSearchElementInfoByAccessibilityIdResult(callback, infos, requestId);
1322 LOGD("requestId(%{public}d)", requestId);
1323 }
1324
SearchElementInfoByAccessibilityIdNG(int32_t elementId,int32_t mode,std::list<AccessibilityElementInfo> & infos)1325 void JsAccessibilityManager::SearchElementInfoByAccessibilityIdNG(
1326 int32_t elementId, int32_t mode, std::list<AccessibilityElementInfo>& infos)
1327 {
1328 auto pipeline = context_.Upgrade();
1329 CHECK_NULL_VOID(pipeline);
1330
1331 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
1332 auto rootNode = ngPipeline->GetRootElement();
1333 CHECK_NULL_VOID(rootNode);
1334
1335 AccessibilityElementInfo nodeInfo;
1336 NodeId nodeId = elementId;
1337 // accessibility use -1 for first search to get root node
1338 if (elementId == -1) {
1339 nodeId = rootNode->GetAccessibilityId();
1340 }
1341
1342 auto node = GetInspectorById(rootNode, nodeId);
1343 CHECK_NULL_VOID(node);
1344 auto page = ngPipeline->GetStageManager()->GetLastPage();
1345 CHECK_NULL_VOID(page);
1346 auto pageId = page->GetPageId();
1347 auto pagePath = GetPagePath();
1348 CommonProperty commonProperty { ngPipeline->GetWindowId(), GetWindowLeft(ngPipeline->GetWindowId()),
1349 GetWindowTop(ngPipeline->GetWindowId()), pageId, pagePath };
1350 UpdateAccessibilityElementInfo(node, commonProperty, nodeInfo);
1351
1352 infos.push_back(nodeInfo);
1353 }
1354
SearchElementInfosByTextNG(int32_t elementId,const std::string & text,std::list<Accessibility::AccessibilityElementInfo> & infos)1355 void JsAccessibilityManager::SearchElementInfosByTextNG(
1356 int32_t elementId, const std::string& text, std::list<Accessibility::AccessibilityElementInfo>& infos)
1357 {
1358 auto pipeline = context_.Upgrade();
1359 CHECK_NULL_VOID(pipeline);
1360
1361 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
1362 auto rootNode = ngPipeline->GetRootElement();
1363 CHECK_NULL_VOID(rootNode);
1364
1365 auto node = GetInspectorById(rootNode, elementId);
1366 CHECK_NULL_VOID(node);
1367 std::list<RefPtr<NG::FrameNode>> results;
1368 FindText(node, text, results);
1369 if (results.empty()) {
1370 return;
1371 }
1372 auto page = ngPipeline->GetStageManager()->GetLastPage();
1373 CHECK_NULL_VOID(page);
1374 auto pageId = page->GetPageId();
1375 auto pagePath = GetPagePath();
1376 CommonProperty commonProperty { ngPipeline->GetWindowId(), GetWindowLeft(ngPipeline->GetWindowId()),
1377 GetWindowTop(ngPipeline->GetWindowId()), pageId, pagePath };
1378 for (const auto& node : results) {
1379 AccessibilityElementInfo nodeInfo;
1380 UpdateAccessibilityElementInfo(node, commonProperty, nodeInfo);
1381 infos.emplace_back(nodeInfo);
1382 }
1383 }
1384
SearchElementInfosByText(const int32_t elementId,const std::string & text,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1385 void JsAccessibilityManager::JsInteractionOperation::SearchElementInfosByText(const int32_t elementId,
1386 const std::string& text, const int32_t requestId, AccessibilityElementOperatorCallback& callback)
1387 {
1388 LOGI("elementId(%{public}d) text(%{public}s)", elementId, text.c_str());
1389 if (text.empty()) {
1390 LOGW("Text is null");
1391 return;
1392 }
1393 auto jsAccessibilityManager = GetHandler().Upgrade();
1394 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1395 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1396 if (context) {
1397 context->GetTaskExecutor()->PostTask(
1398 [jsAccessibilityManager, elementId, text, requestId, &callback]() {
1399 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1400 jsAccessibilityManager->SearchElementInfosByText(elementId, text, requestId, callback);
1401 },
1402 TaskExecutor::TaskType::UI);
1403 }
1404 }
1405
SearchElementInfosByText(const int32_t elementId,const std::string & text,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1406 void JsAccessibilityManager::SearchElementInfosByText(const int32_t elementId, const std::string& text,
1407 const int32_t requestId, AccessibilityElementOperatorCallback& callback)
1408 {
1409 if (text.empty()) {
1410 LOGW("Text is null");
1411 return;
1412 }
1413
1414 if (elementId == -1) {
1415 return;
1416 }
1417
1418 std::list<AccessibilityElementInfo> infos;
1419
1420 auto pipeline = context_.Upgrade();
1421 if (pipeline) {
1422 if (AceType::InstanceOf<NG::PipelineContext>(pipeline)) {
1423 SearchElementInfosByTextNG(elementId, text, infos);
1424 SetSearchElementInfoByTextResult(callback, infos, requestId);
1425 return;
1426 }
1427 }
1428
1429 auto weak = WeakClaim(this);
1430 auto jsAccessibilityManager = weak.Upgrade();
1431 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1432 NodeId nodeId = elementId;
1433 auto node = jsAccessibilityManager->GetAccessibilityNodeFromPage(nodeId);
1434 CHECK_NULL_VOID_NOLOG(node);
1435 std::list<RefPtr<AccessibilityNode>> nodeList;
1436 FindText(node, text, nodeList);
1437 if (!nodeList.empty()) {
1438 for (const auto& node : nodeList) {
1439 LOGI(" FindText end nodeId:%{public}d", node->GetNodeId());
1440 AccessibilityElementInfo nodeInfo;
1441 UpdateAccessibilityNodeInfo(node, nodeInfo, jsAccessibilityManager, jsAccessibilityManager->windowId_);
1442 infos.emplace_back(nodeInfo);
1443 }
1444 }
1445
1446 LOGI("SetSearchElementInfoByTextResult infos.size(%{public}zu)", infos.size());
1447 SetSearchElementInfoByTextResult(callback, infos, requestId);
1448 }
1449
FindFocusedElementInfo(const int32_t elementId,const int32_t focusType,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1450 void JsAccessibilityManager::JsInteractionOperation::FindFocusedElementInfo(const int32_t elementId,
1451 const int32_t focusType, const int32_t requestId, AccessibilityElementOperatorCallback& callback)
1452 {
1453 LOGI("elementId(%{public}d) focusType(%{public}d)", elementId, focusType);
1454 auto jsAccessibilityManager = GetHandler().Upgrade();
1455 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1456 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1457 CHECK_NULL_VOID_NOLOG(context);
1458 context->GetTaskExecutor()->PostTask(
1459 [jsAccessibilityManager, elementId, focusType, requestId, &callback]() {
1460 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1461 jsAccessibilityManager->FindFocusedElementInfo(elementId, focusType, requestId, callback);
1462 },
1463 TaskExecutor::TaskType::UI);
1464 }
1465
FindFocusedElementInfo(const int32_t elementId,const int32_t focusType,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1466 void JsAccessibilityManager::FindFocusedElementInfo(const int32_t elementId, const int32_t focusType,
1467 const int32_t requestId, AccessibilityElementOperatorCallback& callback)
1468 {
1469 AccessibilityElementInfo nodeInfo;
1470 if (focusType != FOCUS_TYPE_INPUT && focusType != FOCUS_TYPE_ACCESSIBILITY) {
1471 nodeInfo.SetValidElement(false);
1472 SetFindFocusedElementInfoResult(callback, nodeInfo, requestId);
1473 return;
1474 }
1475
1476 auto context = context_.Upgrade();
1477 if (!context) {
1478 SetFindFocusedElementInfoResult(callback, nodeInfo, requestId);
1479 return;
1480 }
1481
1482 if (AceType::InstanceOf<NG::PipelineContext>(context)) {
1483 FindFocusedElementInfoNG(elementId, focusType, nodeInfo);
1484 SetFindFocusedElementInfoResult(callback, nodeInfo, requestId);
1485 return;
1486 }
1487
1488 NodeId nodeId = static_cast<NodeId>(elementId);
1489 if (elementId == -1) {
1490 nodeId = 0;
1491 }
1492
1493 auto node = GetAccessibilityNodeFromPage(nodeId);
1494 if (!node) {
1495 nodeInfo.SetValidElement(false);
1496 SetFindFocusedElementInfoResult(callback, nodeInfo, requestId);
1497 return;
1498 }
1499
1500 RefPtr<AccessibilityNode> resultNode = nullptr;
1501 bool status = false;
1502 if (focusType == FOCUS_TYPE_ACCESSIBILITY) {
1503 status = FindAccessibilityFocus(node, resultNode);
1504 }
1505 if (focusType == FOCUS_TYPE_INPUT) {
1506 status = FindInputFocus(node, resultNode);
1507 }
1508
1509 LOGI("FindFocus status(%{public}d)", status);
1510 if ((status) && (resultNode != nullptr)) {
1511 LOGI("FindFocus nodeId:%{public}d", resultNode->GetNodeId());
1512 UpdateAccessibilityNodeInfo(resultNode, nodeInfo, Claim(this), windowId_);
1513 }
1514
1515 SetFindFocusedElementInfoResult(callback, nodeInfo, requestId);
1516 }
1517
FindFocusedElementInfoNG(int32_t elementId,int32_t focusType,Accessibility::AccessibilityElementInfo & info)1518 void JsAccessibilityManager::FindFocusedElementInfoNG(
1519 int32_t elementId, int32_t focusType, Accessibility::AccessibilityElementInfo& info)
1520 {
1521 auto pipeline = context_.Upgrade();
1522 CHECK_NULL_VOID(pipeline);
1523
1524 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
1525 auto rootNode = ngPipeline->GetRootElement();
1526 CHECK_NULL_VOID(rootNode);
1527
1528 NodeId nodeId = elementId;
1529 // accessibility use -1 for first search to get root node
1530 if (elementId == -1) {
1531 nodeId = rootNode->GetAccessibilityId();
1532 }
1533
1534 auto node = GetInspectorById(rootNode, nodeId);
1535 CHECK_NULL_VOID(node);
1536 RefPtr<NG::FrameNode> resultNode;
1537 if (focusType == FOCUS_TYPE_ACCESSIBILITY) {
1538 resultNode = FindAccessibilityFocus(node);
1539 }
1540 if (focusType == FOCUS_TYPE_INPUT) {
1541 resultNode = FindInputFocus(node);
1542 }
1543 CHECK_NULL_VOID(resultNode);
1544 auto page = ngPipeline->GetStageManager()->GetLastPage();
1545 CHECK_NULL_VOID(page);
1546 auto pageId = page->GetPageId();
1547 auto pagePath = GetPagePath();
1548 CommonProperty commonProperty { ngPipeline->GetWindowId(), GetWindowLeft(ngPipeline->GetWindowId()),
1549 GetWindowTop(ngPipeline->GetWindowId()), pageId, pagePath };
1550 UpdateAccessibilityElementInfo(resultNode, commonProperty, info);
1551 }
1552
ExecuteAction(const int32_t elementId,const int32_t action,const std::map<std::string,std::string> & actionArguments,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1553 void JsAccessibilityManager::JsInteractionOperation::ExecuteAction(const int32_t elementId, const int32_t action,
1554 const std::map<std::string, std::string>& actionArguments, const int32_t requestId,
1555 AccessibilityElementOperatorCallback& callback)
1556 {
1557 LOGI("id:%{public}d, action:%{public}d, request:%{public}d.", elementId, action, requestId);
1558 auto jsAccessibilityManager = GetHandler().Upgrade();
1559 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1560 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1561 CHECK_NULL_VOID_NOLOG(context);
1562 auto actionInfo = static_cast<ActionType>(action);
1563 context->GetTaskExecutor()->PostTask(
1564 [jsAccessibilityManager, elementId, actionInfo, actionArguments, requestId, &callback] {
1565 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1566 jsAccessibilityManager->ExecuteAction(elementId, actionInfo, actionArguments, requestId, callback);
1567 },
1568 TaskExecutor::TaskType::UI);
1569 }
1570
AccessibilityActionEvent(const ActionType & action,const std::map<std::string,std::string> actionArguments,const RefPtr<AccessibilityNode> & node,const RefPtr<PipelineContext> & context)1571 bool JsAccessibilityManager::AccessibilityActionEvent(const ActionType& action,
1572 const std::map<std::string, std::string> actionArguments, const RefPtr<AccessibilityNode>& node,
1573 const RefPtr<PipelineContext>& context)
1574 {
1575 if (!node || !context) {
1576 return false;
1577 }
1578 ContainerScope scope(context->GetInstanceId());
1579 switch (action) {
1580 case ActionType::ACCESSIBILITY_ACTION_CLICK: {
1581 node->SetClicked(true);
1582 if (!node->GetClickEventMarker().IsEmpty()) {
1583 context->SendEventToFrontend(node->GetClickEventMarker());
1584 node->ActionClick();
1585 return true;
1586 }
1587 return node->ActionClick();
1588 }
1589 case ActionType::ACCESSIBILITY_ACTION_LONG_CLICK: {
1590 if (!node->GetLongPressEventMarker().IsEmpty()) {
1591 context->SendEventToFrontend(node->GetLongPressEventMarker());
1592 node->ActionLongClick();
1593 return true;
1594 }
1595 return node->ActionLongClick();
1596 }
1597 case ActionType::ACCESSIBILITY_ACTION_SET_TEXT: {
1598 if (!node->GetSetTextEventMarker().IsEmpty()) {
1599 context->SendEventToFrontend(node->GetSetTextEventMarker());
1600 node->ActionSetText(actionArguments.find(ACTION_ARGU_SET_TEXT)->second);
1601 return true;
1602 }
1603 return node->ActionSetText(actionArguments.find(ACTION_ARGU_SET_TEXT)->second);
1604 }
1605 case ActionType::ACCESSIBILITY_ACTION_FOCUS: {
1606 context->AccessibilityRequestFocus(std::to_string(node->GetNodeId()));
1607 if (!node->GetFocusEventMarker().IsEmpty()) {
1608 context->SendEventToFrontend(node->GetFocusEventMarker());
1609 node->ActionFocus();
1610 return true;
1611 }
1612 return node->ActionFocus();
1613 }
1614 case ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS: {
1615 return RequestAccessibilityFocus(node);
1616 }
1617 case ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
1618 return ClearAccessibilityFocus(node);
1619 }
1620 case ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD:
1621 return node->ActionScrollForward();
1622 case ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD:
1623 return node->ActionScrollBackward();
1624 default:
1625 return false;
1626 }
1627 }
1628
SendActionEvent(const Accessibility::ActionType & action,NodeId nodeId)1629 void JsAccessibilityManager::SendActionEvent(const Accessibility::ActionType& action, NodeId nodeId)
1630 {
1631 static std::unordered_map<Accessibility::ActionType, std::string> actionToStr {
1632 { Accessibility::ActionType::ACCESSIBILITY_ACTION_CLICK, DOM_CLICK },
1633 { Accessibility::ActionType::ACCESSIBILITY_ACTION_LONG_CLICK, DOM_LONG_PRESS },
1634 { Accessibility::ActionType::ACCESSIBILITY_ACTION_FOCUS, DOM_FOCUS },
1635 { Accessibility::ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS, ACCESSIBILITY_FOCUSED_EVENT },
1636 { Accessibility::ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS, ACCESSIBILITY_CLEAR_FOCUS_EVENT },
1637 { Accessibility::ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD, SCROLL_END_EVENT },
1638 { Accessibility::ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD, SCROLL_END_EVENT },
1639 };
1640 if (actionToStr.find(action) == actionToStr.end()) {
1641 return;
1642 }
1643 AccessibilityEvent accessibilityEvent;
1644 accessibilityEvent.eventType = actionToStr[action];
1645 accessibilityEvent.nodeId = static_cast<int>(nodeId);
1646 SendAccessibilityAsyncEvent(accessibilityEvent);
1647 }
1648
ExecuteActionNG(int32_t elementId,ActionType action)1649 bool JsAccessibilityManager::ExecuteActionNG(int32_t elementId, ActionType action)
1650 {
1651 bool result = false;
1652 auto context = context_.Upgrade();
1653 CHECK_NULL_RETURN(context, result);
1654 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(context);
1655 ContainerScope instance(ngPipeline->GetInstanceId());
1656 auto frameNode = GetInspectorById(ngPipeline->GetRootElement(), elementId);
1657 CHECK_NULL_RETURN(frameNode, result);
1658
1659 switch (action) {
1660 case ActionType::ACCESSIBILITY_ACTION_FOCUS: {
1661 result = RequestFocus(frameNode);
1662 break;
1663 }
1664 case ActionType::ACCESSIBILITY_ACTION_CLICK: {
1665 result = ActClick(frameNode);
1666 break;
1667 }
1668 case ActionType::ACCESSIBILITY_ACTION_LONG_CLICK: {
1669 result = ActLongClick(frameNode);
1670 break;
1671 }
1672 case ActionType::ACCESSIBILITY_ACTION_ACCESSIBILITY_FOCUS: {
1673 if (elementId == currentFocusNodeId_) {
1674 LOGW("This node is focused.");
1675 return result;
1676 }
1677 Framework::ClearAccessibilityFocus(ngPipeline->GetRootElement(), currentFocusNodeId_);
1678 frameNode->GetRenderContext()->OnAccessibilityFocusUpdate(true);
1679 currentFocusNodeId_ = frameNode->GetAccessibilityId();
1680 result = true;
1681 break;
1682 }
1683 case ActionType::ACCESSIBILITY_ACTION_CLEAR_ACCESSIBILITY_FOCUS: {
1684 if (elementId != currentFocusNodeId_) {
1685 return result;
1686 }
1687 frameNode->GetRenderContext()->OnAccessibilityFocusUpdate(false);
1688 currentFocusNodeId_ = -1;
1689 result = true;
1690 break;
1691 }
1692 case ActionType::ACCESSIBILITY_ACTION_SCROLL_FORWARD:
1693 case ActionType::ACCESSIBILITY_ACTION_SCROLL_BACKWARD:
1694 return true;
1695 default:
1696 break;
1697 }
1698
1699 return result;
1700 }
1701
ExecuteAction(const int32_t elementId,const ActionType & action,const std::map<std::string,std::string> actionArguments,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1702 void JsAccessibilityManager::ExecuteAction(const int32_t elementId, const ActionType& action,
1703 const std::map<std::string, std::string> actionArguments, const int32_t requestId,
1704 AccessibilityElementOperatorCallback& callback)
1705 {
1706 LOGI("ExecuteAction elementId:%{public}d action:%{public}d", elementId, action);
1707
1708 bool actionResult = false;
1709 auto context = context_.Upgrade();
1710 if (!context) {
1711 SetExecuteActionResult(callback, actionResult, requestId);
1712 return;
1713 }
1714
1715 if (AceType::InstanceOf<NG::PipelineContext>(context)) {
1716 actionResult = ExecuteActionNG(elementId, action);
1717 } else {
1718 auto node = GetAccessibilityNodeFromPage(elementId);
1719 if (!node) {
1720 LOGW("AccessibilityNodeInfo can't attach component by Id = %{public}d", elementId);
1721 SetExecuteActionResult(callback, false, requestId);
1722 return;
1723 }
1724
1725 actionResult =
1726 AccessibilityActionEvent(action, actionArguments, node, AceType::DynamicCast<PipelineContext>(context));
1727 }
1728 LOGI("SetExecuteActionResult actionResult= %{public}d", actionResult);
1729 SetExecuteActionResult(callback, actionResult, requestId);
1730 if (actionResult && AceType::InstanceOf<PipelineContext>(context)) {
1731 SendActionEvent(action, elementId);
1732 }
1733 }
1734
ClearFocus()1735 void JsAccessibilityManager::JsInteractionOperation::ClearFocus()
1736 {
1737 LOGI("ClearFocus");
1738 auto jsAccessibilityManager = GetHandler().Upgrade();
1739 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1740 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1741 CHECK_NULL_VOID_NOLOG(context);
1742 context->GetTaskExecutor()->PostTask(
1743 [jsAccessibilityManager] {
1744 if (!jsAccessibilityManager) {
1745 return;
1746 }
1747 jsAccessibilityManager->ClearCurrentFocus();
1748 },
1749 TaskExecutor::TaskType::UI);
1750 }
1751
OutsideTouch()1752 void JsAccessibilityManager::JsInteractionOperation::OutsideTouch() {}
1753
IsRegister()1754 bool JsAccessibilityManager::IsRegister()
1755 {
1756 return isReg_;
1757 }
1758
Register(bool state)1759 void JsAccessibilityManager::Register(bool state)
1760 {
1761 isReg_ = state;
1762 }
1763
RegisterInteractionOperation(const int windowId)1764 int JsAccessibilityManager::RegisterInteractionOperation(const int windowId)
1765 {
1766 LOGI("RegisterInteractionOperation windowId:%{public}d", windowId);
1767 if (IsRegister()) {
1768 return 0;
1769 }
1770
1771 std::shared_ptr<AccessibilitySystemAbilityClient> instance = AccessibilitySystemAbilityClient::GetInstance();
1772 CHECK_NULL_RETURN_NOLOG(instance, -1);
1773 interactionOperation_ = std::make_shared<JsInteractionOperation>();
1774 interactionOperation_->SetHandler(WeakClaim(this));
1775 Accessibility::RetError retReg = instance->RegisterElementOperator(windowId, interactionOperation_);
1776 LOGI("RegisterInteractionOperation end windowId:%{public}d, ret:%{public}d", windowId, retReg);
1777 Register(retReg == RET_OK);
1778
1779 return retReg;
1780 }
1781
DeregisterInteractionOperation()1782 void JsAccessibilityManager::DeregisterInteractionOperation()
1783 {
1784 if (!IsRegister()) {
1785 return;
1786 }
1787 int windowId = GetWindowId();
1788
1789 auto instance = AccessibilitySystemAbilityClient::GetInstance();
1790 CHECK_NULL_VOID_NOLOG(instance);
1791 Register(false);
1792 currentFocusNodeId_ = -1;
1793 LOGI("DeregisterInteractionOperation windowId:%{public}d", windowId);
1794 instance->DeregisterElementOperator(windowId);
1795 }
1796
OnStateChanged(const bool state)1797 void JsAccessibilityManager::JsAccessibilityStateObserver::OnStateChanged(const bool state)
1798 {
1799 LOGI("accessibility state changed:%{public}d", state);
1800 auto jsAccessibilityManager = GetHandler().Upgrade();
1801 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1802 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1803 CHECK_NULL_VOID_NOLOG(context);
1804 context->GetTaskExecutor()->PostTask(
1805 [jsAccessibilityManager, state]() {
1806 if (state) {
1807 jsAccessibilityManager->RegisterInteractionOperation(jsAccessibilityManager->GetWindowId());
1808 } else {
1809 jsAccessibilityManager->DeregisterInteractionOperation();
1810 }
1811 AceApplicationInfo::GetInstance().SetAccessibilityEnabled(state);
1812 },
1813 TaskExecutor::TaskType::UI);
1814 }
1815
FocusMoveSearch(const int32_t elementId,const int32_t direction,const int32_t requestId,AccessibilityElementOperatorCallback & callback)1816 void JsAccessibilityManager::JsInteractionOperation::FocusMoveSearch(const int32_t elementId, const int32_t direction,
1817 const int32_t requestId, AccessibilityElementOperatorCallback& callback)
1818 {
1819 LOGI("elementId:%{public}d,direction:%{public}d,requestId:%{public}d", elementId, direction, requestId);
1820 auto jsAccessibilityManager = GetHandler().Upgrade();
1821 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1822 auto context = jsAccessibilityManager->GetPipelineContext().Upgrade();
1823 CHECK_NULL_VOID_NOLOG(context);
1824 context->GetTaskExecutor()->PostTask(
1825 [jsAccessibilityManager, elementId, direction, requestId, &callback] {
1826 CHECK_NULL_VOID_NOLOG(jsAccessibilityManager);
1827 jsAccessibilityManager->FocusMoveSearch(elementId, direction, requestId, callback);
1828 },
1829 TaskExecutor::TaskType::UI);
1830 }
1831
FocusMoveSearch(const int32_t elementId,const int32_t direction,const int32_t requestId,Accessibility::AccessibilityElementOperatorCallback & callback)1832 void JsAccessibilityManager::FocusMoveSearch(const int32_t elementId, const int32_t direction, const int32_t requestId,
1833 Accessibility::AccessibilityElementOperatorCallback& callback)
1834 {
1835 AccessibilityElementInfo nodeInfo;
1836 auto context = GetPipelineContext().Upgrade();
1837 if (!context) {
1838 LOGI("FocusMoveSearch context is null");
1839 nodeInfo.SetValidElement(false);
1840 SetFocusMoveSearchResult(callback, nodeInfo, requestId);
1841 return;
1842 }
1843
1844 if (AceType::InstanceOf<NG::PipelineContext>(context)) {
1845 FocusMoveSearchNG(elementId, direction, nodeInfo);
1846 SetFocusMoveSearchResult(callback, nodeInfo, requestId);
1847 return;
1848 }
1849
1850 auto node = GetAccessibilityNodeFromPage(elementId);
1851 if (!node) {
1852 LOGW("AccessibilityNodeInfo can't attach component by Id = %{public}d", (NodeId)elementId);
1853 nodeInfo.SetValidElement(false);
1854 SetFocusMoveSearchResult(callback, nodeInfo, requestId);
1855 return;
1856 }
1857
1858 // get root node.
1859 auto rootNode = node;
1860 while (rootNode->GetParentNode()) {
1861 rootNode = rootNode->GetParentNode();
1862 if (!rootNode->GetParentNode()) {
1863 break;
1864 }
1865 }
1866
1867 std::list<RefPtr<AccessibilityNode>> nodeList;
1868 AddFocusableNode(nodeList, rootNode);
1869 RefPtr<AccessibilityNode> resultNode;
1870
1871 switch (direction) {
1872 case FocusMoveDirection::FORWARD:
1873 case FocusMoveDirection::BACKWARD:
1874 // forward and backward
1875 resultNode = FindNodeInRelativeDirection(nodeList, node, direction);
1876 break;
1877 case FocusMoveDirection::UP:
1878 case FocusMoveDirection::DOWN:
1879 case FocusMoveDirection::LEFT:
1880 case FocusMoveDirection::RIGHT:
1881 // up, down, left and right
1882 resultNode = FindNodeInAbsoluteDirection(nodeList, node, direction);
1883 break;
1884 default:
1885 break;
1886 }
1887
1888 if (resultNode) {
1889 LOGI("FocusMoveSearch end nodeId:%{public}d", resultNode->GetNodeId());
1890 auto jsAccessibilityManager = Claim(this);
1891 UpdateAccessibilityNodeInfo(resultNode, nodeInfo, jsAccessibilityManager, windowId_);
1892 }
1893
1894 SetFocusMoveSearchResult(callback, nodeInfo, requestId);
1895 }
1896
AddFocusableNode(std::list<RefPtr<AccessibilityNode>> & nodeList,const RefPtr<AccessibilityNode> & node)1897 void JsAccessibilityManager::AddFocusableNode(
1898 std::list<RefPtr<AccessibilityNode>>& nodeList, const RefPtr<AccessibilityNode>& node)
1899 {
1900 const std::string importance = node->GetImportantForAccessibility();
1901 if (CanAccessibilityFocused(node)) {
1902 nodeList.push_back(node);
1903 }
1904 if (!node->GetAccessible() && importance != "no-hide-descendants") {
1905 for (auto& child : node->GetChildList()) {
1906 AddFocusableNode(nodeList, child);
1907 }
1908 }
1909 }
1910
CanAccessibilityFocused(const RefPtr<AccessibilityNode> & node)1911 bool JsAccessibilityManager::CanAccessibilityFocused(const RefPtr<AccessibilityNode>& node)
1912 {
1913 return node != nullptr && !node->IsRootNode() && node->GetVisible() &&
1914 node->GetImportantForAccessibility() != "no" &&
1915 node->GetImportantForAccessibility() != "no-hide-descendants";
1916 }
1917
FindNodeInRelativeDirection(const std::list<RefPtr<AccessibilityNode>> & nodeList,RefPtr<AccessibilityNode> & node,const int direction)1918 RefPtr<AccessibilityNode> JsAccessibilityManager::FindNodeInRelativeDirection(
1919 const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node, const int direction)
1920 {
1921 switch (direction) {
1922 case FocusMoveDirection::FORWARD:
1923 return GetNextFocusableNode(nodeList, node);
1924 case FocusMoveDirection::BACKWARD:
1925 return GetPreviousFocusableNode(nodeList, node);
1926 default:
1927 break;
1928 }
1929
1930 return nullptr;
1931 }
1932
FindNodeInAbsoluteDirection(const std::list<RefPtr<AccessibilityNode>> & nodeList,RefPtr<AccessibilityNode> & node,const int direction)1933 RefPtr<AccessibilityNode> JsAccessibilityManager::FindNodeInAbsoluteDirection(
1934 const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node, const int direction)
1935 {
1936 LOGI("FindNodeInAbsoluteDirection");
1937 auto tempBest = node->GetRect();
1938 auto nodeRect = node->GetRect();
1939
1940 switch (direction) {
1941 case FocusMoveDirection::LEFT:
1942 tempBest.SetLeft(node->GetLeft() + node->GetWidth() + 1);
1943 break;
1944 case FocusMoveDirection::RIGHT:
1945 tempBest.SetLeft(node->GetLeft() - node->GetWidth() - 1);
1946 break;
1947 case FocusMoveDirection::UP:
1948 tempBest.SetTop(node->GetTop() + node->GetHeight() + 1);
1949 break;
1950 case FocusMoveDirection::DOWN:
1951 tempBest.SetTop(node->GetTop() - node->GetHeight() - 1);
1952 break;
1953 default:
1954 break;
1955 }
1956
1957 RefPtr<AccessibilityNode> nearestNode = nullptr;
1958 for (auto nodeItem = nodeList.begin(); nodeItem != nodeList.end(); nodeItem++) {
1959 if ((*nodeItem)->GetNodeId() == node->GetNodeId() || (*nodeItem)->IsRootNode()) {
1960 continue;
1961 }
1962 auto itemRect = (*nodeItem)->GetRect();
1963 if (CheckBetterRect(nodeRect, direction, itemRect, tempBest)) {
1964 tempBest = itemRect;
1965 nearestNode = (*nodeItem);
1966 }
1967 }
1968
1969 return nearestNode;
1970 }
1971
GetNextFocusableNode(const std::list<RefPtr<AccessibilityNode>> & nodeList,RefPtr<AccessibilityNode> & node)1972 RefPtr<AccessibilityNode> JsAccessibilityManager::GetNextFocusableNode(
1973 const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node)
1974 {
1975 LOGI("GetNextFocusableNode");
1976 auto nodeItem = nodeList.begin();
1977 for (; nodeItem != nodeList.end(); nodeItem++) {
1978 if ((*nodeItem)->GetNodeId() == node->GetNodeId()) {
1979 break;
1980 }
1981 }
1982
1983 if (nodeItem != nodeList.end() && ++nodeItem != nodeList.end()) {
1984 return (*nodeItem);
1985 }
1986 if (!nodeList.empty()) {
1987 return (*nodeList.begin());
1988 }
1989
1990 return nullptr;
1991 }
1992
GetPreviousFocusableNode(const std::list<RefPtr<AccessibilityNode>> & nodeList,RefPtr<AccessibilityNode> & node)1993 RefPtr<AccessibilityNode> JsAccessibilityManager::GetPreviousFocusableNode(
1994 const std::list<RefPtr<AccessibilityNode>>& nodeList, RefPtr<AccessibilityNode>& node)
1995 {
1996 LOGI("GetPreviousFocusableNode");
1997 auto nodeItem = nodeList.rbegin();
1998 for (; nodeItem != nodeList.rend(); nodeItem++) {
1999 if ((*nodeItem)->GetNodeId() == node->GetNodeId()) {
2000 break;
2001 }
2002 }
2003
2004 if (nodeItem != nodeList.rend() && ++nodeItem != nodeList.rend()) {
2005 return (*nodeItem);
2006 }
2007
2008 if (!nodeList.empty()) {
2009 return (*nodeList.rbegin());
2010 }
2011 return nullptr;
2012 }
2013
RequestAccessibilityFocus(const RefPtr<AccessibilityNode> & node)2014 bool JsAccessibilityManager::RequestAccessibilityFocus(const RefPtr<AccessibilityNode>& node)
2015 {
2016 LOGI("RequestAccessibilityFocus");
2017 auto requestNodeId = node->GetNodeId();
2018 if (currentFocusNodeId_ == requestNodeId) {
2019 LOGW("This node is focused.");
2020 return false;
2021 }
2022
2023 ClearCurrentFocus();
2024 currentFocusNodeId_ = requestNodeId;
2025 node->SetAccessibilityFocusedState(true);
2026 LOGI("RequestAccessibilityFocus SetFocusedState true nodeId:%{public}d", node->GetNodeId());
2027 return node->ActionAccessibilityFocus(true);
2028 }
2029
ClearAccessibilityFocus(const RefPtr<AccessibilityNode> & node)2030 bool JsAccessibilityManager::ClearAccessibilityFocus(const RefPtr<AccessibilityNode>& node)
2031 {
2032 LOGI("ClearAccessibilityFocus");
2033 auto requestNodeId = node->GetNodeId();
2034 if (currentFocusNodeId_ != requestNodeId) {
2035 LOGW("This node is not focused.");
2036 return false;
2037 }
2038
2039 currentFocusNodeId_ = -1;
2040 node->SetAccessibilityFocusedState(false);
2041 return node->ActionAccessibilityFocus(false);
2042 }
2043
ClearCurrentFocus()2044 bool JsAccessibilityManager::ClearCurrentFocus()
2045 {
2046 LOGI("ClearCurrentFocus");
2047 auto currentFocusNode = GetAccessibilityNodeFromPage(currentFocusNodeId_);
2048 CHECK_NULL_RETURN_NOLOG(currentFocusNode, false);
2049 currentFocusNodeId_ = -1;
2050 currentFocusNode->SetFocusedState(false);
2051 currentFocusNode->SetAccessibilityFocusedState(false);
2052 LOGI("ClearCurrentFocus SetFocusedState false nodeId:%{public}d", currentFocusNode->GetNodeId());
2053 return currentFocusNode->ActionAccessibilityFocus(false);
2054 }
2055
FocusMoveSearchNG(int32_t elementId,int32_t direction,Accessibility::AccessibilityElementInfo & info)2056 void JsAccessibilityManager::FocusMoveSearchNG(
2057 int32_t elementId, int32_t direction, Accessibility::AccessibilityElementInfo& info)
2058 {
2059 auto pipeline = context_.Upgrade();
2060 CHECK_NULL_VOID(pipeline);
2061
2062 auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipeline);
2063 auto rootNode = ngPipeline->GetRootElement();
2064 CHECK_NULL_VOID(rootNode);
2065
2066 auto node = GetInspectorById(rootNode, elementId);
2067 CHECK_NULL_VOID(node);
2068 std::list<RefPtr<NG::FrameNode>> nodeList;
2069 Framework::AddFocusableNode(nodeList, rootNode);
2070
2071 RefPtr<NG::FrameNode> resultNode;
2072 switch (direction) {
2073 case FocusMoveDirection::FORWARD:
2074 case FocusMoveDirection::BACKWARD:
2075 resultNode = Framework::FindNodeInRelativeDirection(nodeList, node, direction);
2076 break;
2077 case FocusMoveDirection::UP:
2078 case FocusMoveDirection::DOWN:
2079 case FocusMoveDirection::LEFT:
2080 case FocusMoveDirection::RIGHT:
2081 resultNode = Framework::FindNodeInAbsoluteDirection(nodeList, node, direction);
2082 break;
2083 default:
2084 break;
2085 }
2086
2087 CHECK_NULL_VOID(resultNode);
2088 auto page = ngPipeline->GetStageManager()->GetLastPage();
2089 CHECK_NULL_VOID(page);
2090 auto pageId = page->GetPageId();
2091 auto pagePath = GetPagePath();
2092 CommonProperty commonProperty { ngPipeline->GetWindowId(), GetWindowLeft(ngPipeline->GetWindowId()),
2093 GetWindowTop(ngPipeline->GetWindowId()), pageId, pagePath };
2094 UpdateAccessibilityElementInfo(resultNode, commonProperty, info);
2095 }
2096
2097 // AccessibilitySystemAbilityClient will release callback after DeregisterElementOperator
SetSearchElementInfoByAccessibilityIdResult(AccessibilityElementOperatorCallback & callback,const std::list<AccessibilityElementInfo> & infos,const int32_t requestId)2098 void JsAccessibilityManager::SetSearchElementInfoByAccessibilityIdResult(AccessibilityElementOperatorCallback& callback,
2099 const std::list<AccessibilityElementInfo>& infos, const int32_t requestId)
2100 {
2101 if (IsRegister()) {
2102 callback.SetSearchElementInfoByAccessibilityIdResult(infos, requestId);
2103 }
2104 }
2105
SetSearchElementInfoByTextResult(AccessibilityElementOperatorCallback & callback,const std::list<AccessibilityElementInfo> & infos,const int32_t requestId)2106 void JsAccessibilityManager::SetSearchElementInfoByTextResult(AccessibilityElementOperatorCallback& callback,
2107 const std::list<AccessibilityElementInfo>& infos, const int32_t requestId)
2108 {
2109 if (IsRegister()) {
2110 callback.SetSearchElementInfoByTextResult(infos, requestId);
2111 }
2112 }
2113
SetFindFocusedElementInfoResult(AccessibilityElementOperatorCallback & callback,const AccessibilityElementInfo & info,const int32_t requestId)2114 void JsAccessibilityManager::SetFindFocusedElementInfoResult(
2115 AccessibilityElementOperatorCallback& callback, const AccessibilityElementInfo& info, const int32_t requestId)
2116 {
2117 if (IsRegister()) {
2118 callback.SetFindFocusedElementInfoResult(info, requestId);
2119 }
2120 }
2121
SetFocusMoveSearchResult(AccessibilityElementOperatorCallback & callback,const AccessibilityElementInfo & info,const int32_t requestId)2122 void JsAccessibilityManager::SetFocusMoveSearchResult(
2123 AccessibilityElementOperatorCallback& callback, const AccessibilityElementInfo& info, const int32_t requestId)
2124 {
2125 if (IsRegister()) {
2126 callback.SetFocusMoveSearchResult(info, requestId);
2127 }
2128 }
2129
SetExecuteActionResult(AccessibilityElementOperatorCallback & callback,const bool succeeded,const int32_t requestId)2130 void JsAccessibilityManager::SetExecuteActionResult(
2131 AccessibilityElementOperatorCallback& callback, const bool succeeded, const int32_t requestId)
2132 {
2133 if (IsRegister()) {
2134 callback.SetExecuteActionResult(succeeded, requestId);
2135 }
2136 }
2137
GetPagePath()2138 std::string JsAccessibilityManager::GetPagePath()
2139 {
2140 auto context = context_.Upgrade();
2141 CHECK_NULL_RETURN(context, "");
2142 auto frontend = context->GetFrontend();
2143 CHECK_NULL_RETURN(frontend, "");
2144 ContainerScope scope(context->GetInstanceId());
2145 return frontend->GetPagePath();
2146 }
2147
2148 } // namespace OHOS::Ace::Framework
2149