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