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