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