Java Code Examples for androidx.core.view.accessibility.AccessibilityNodeInfoCompat#getChild()
The following examples show how to use
androidx.core.view.accessibility.AccessibilityNodeInfoCompat#getChild() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: NodeDescription.java From talkback with Apache License 2.0 | 6 votes |
private static int getRawIndexInParent(AccessibilityNodeInfoCompat node) { if (node == null) { return UNDEFINED_INDEX; } AccessibilityNodeInfoCompat parent = node.getParent(); if (parent == null) { return UNDEFINED_INDEX; } for (int i = 0; i < parent.getChildCount(); i++) { AccessibilityNodeInfoCompat child = parent.getChild(i); try { if (node.equals(child)) { return i; } } finally { AccessibilityNodeInfoUtils.recycleNodes(child); } } return UNDEFINED_INDEX; }
Example 2
Source File: NodeDescription.java From talkback with Apache License 2.0 | 6 votes |
public boolean indexMatches(AccessibilityNodeInfoCompat node) { if (node == null) { return false; } if (indexType == INDEX_TYPE_COLLECTION) { CollectionItemInfoCompat itemInfo = node.getCollectionItemInfo(); return (itemInfo != null) && (itemInfo.getRowIndex() == rowIndex) && (itemInfo.getColumnIndex() == columnIndex); } else { AccessibilityNodeInfoCompat parent = null; AccessibilityNodeInfoCompat child = null; try { parent = node.getParent(); if (parent == null || parent.getChildCount() <= rawIndexInParent) { return false; } child = parent.getChild(rawIndexInParent); return node.equals(child); } finally { AccessibilityNodeInfoUtils.recycleNodes(parent, child); } } }
Example 3
Source File: NodePathDescription.java From talkback with Apache License 2.0 | 6 votes |
/** <strong>Note:</strong> Caller is responsible to recycle the returned node. */ private static AccessibilityNodeInfoCompat findChildMatchesIndex( AccessibilityNodeInfoCompat parent, NodeDescription childDescription) { if (childDescription.indexType == NodeDescription.INDEX_TYPE_RAW) { if ((childDescription.rawIndexInParent == NodeDescription.UNDEFINED_INDEX) || (parent.getChildCount() <= childDescription.rawIndexInParent)) { return null; } else { return parent.getChild(childDescription.rawIndexInParent); } } else { // INDEX_TYPE_COLLECTION for (int i = 0; i < parent.getChildCount(); i++) { AccessibilityNodeInfoCompat child = parent.getChild(i); // Validate CollectionItemInfo. if (childDescription.indexMatches(child)) { return child; } AccessibilityNodeInfoUtils.recycleNodes(child); } return null; } }
Example 4
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 6 votes |
private static boolean hasVisibleChildren(AccessibilityNodeInfoCompat node) { int childCount = node.getChildCount(); for (int i = 0; i < childCount; ++i) { AccessibilityNodeInfoCompat child = node.getChild(i); if (child != null) { try { if (child.isVisibleToUser()) { return true; } } finally { child.recycle(); } } } return false; }
Example 5
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 6 votes |
public static int countVisibleChildren(AccessibilityNodeInfoCompat node) { if (node == null) { return 0; } int childCount = node.getChildCount(); int childVisibleCount = 0; for (int i = 0; i < childCount; ++i) { AccessibilityNodeInfoCompat child = node.getChild(i); if (child != null) { try { if (child.isVisibleToUser()) { ++childVisibleCount; } } finally { child.recycle(); } } } return childVisibleCount; }
Example 6
Source File: TreeDebug.java From talkback with Apache License 2.0 | 6 votes |
private static void logNodeTree( AccessibilityNodeInfoCompat node, String indent, HashSet<AccessibilityNodeInfoCompat> seen) { if (!seen.add(node)) { LogUtils.v(TAG, "Cycle: %d", node.hashCode()); return; } // Include the hash code as a "poor man's" id, knowing that it // might not always be unique. LogUtils.v(TAG, "%s(%d)%s", indent, node.hashCode(), nodeDebugDescription(node)); indent += " "; int childCount = node.getChildCount(); for (int i = 0; i < childCount; ++i) { AccessibilityNodeInfoCompat child = node.getChild(i); if (child == null) { LogUtils.v(TAG, "%sCouldn't get child %d", indent, i); continue; } logNodeTree(child, indent, seen); } }
Example 7
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 5 votes |
/** * Returns the result of applying a filter using breadth-first traversal. * * @param node The root node to traverse from. * @param filter The filter to satisfy. * @return The first node reached via BFS traversal that satisfies the filter. */ public static AccessibilityNodeInfoCompat searchFromBfs( AccessibilityNodeInfoCompat node, Filter<AccessibilityNodeInfoCompat> filter) { if (node == null) { return null; } final ArrayDeque<AccessibilityNodeInfoCompat> queue = new ArrayDeque<>(); Set<AccessibilityNodeInfoCompat> visitedNodes = new HashSet<>(); queue.add(AccessibilityNodeInfoCompat.obtain(node)); try { while (!queue.isEmpty()) { final AccessibilityNodeInfoCompat item = queue.removeFirst(); visitedNodes.add(item); if (filter.accept(item)) { return item; } final int childCount = item.getChildCount(); for (int i = 0; i < childCount; i++) { final AccessibilityNodeInfoCompat child = item.getChild(i); if (child != null && !visitedNodes.contains(child)) { queue.addLast(child); } } item.recycle(); } } finally { while (!queue.isEmpty()) { queue.removeFirst().recycle(); } } return null; }
Example 8
Source File: InputFocusInterpreter.java From talkback with Apache License 2.0 | 5 votes |
/** * Gets target child node from the source AdapterView node. * * <p><strong>Note:</strong> Caller is responsible for recycling the returned node. */ private static @Nullable AccessibilityNodeInfoCompat getTargetChildFromAdapterView( AccessibilityEvent event) { AccessibilityNodeInfoCompat sourceNode = null; try { sourceNode = AccessibilityNodeInfoUtils.toCompat(event.getSource()); if (sourceNode == null) { return null; } if (event.getItemCount() <= 0 || event.getFromIndex() < 0 || event.getCurrentItemIndex() < 0) { return null; } int index = event.getCurrentItemIndex() - event.getFromIndex(); if (index < 0 || index >= sourceNode.getChildCount()) { return null; } AccessibilityNodeInfoCompat targetChildNode = sourceNode.getChild(index); // TODO: Think about to replace childNode check with sourceNode check. if ((targetChildNode == null) || !AccessibilityNodeInfoUtils.isTopLevelScrollItem(targetChildNode)) { AccessibilityNodeInfoUtils.recycleNodes(targetChildNode); return null; } else { return targetChildNode; } } finally { AccessibilityNodeInfoUtils.recycleNodes(sourceNode); } }
Example 9
Source File: FocusProcessorForLogicalNavigation.java From talkback with Apache License 2.0 | 5 votes |
/** * Returns the first or the last child. * * @param node The parent node whose first or last child is returned. * @param firstChild If {@code true} indicates first child, else last child. * @return First or last child of the {@code node} */ private static AccessibilityNodeInfoCompat getFirstOrLastChild( @Nullable AccessibilityNodeInfoCompat node, boolean firstChild) { if (node != null && node.getChildCount() > 0) { int childNumber = 0; if (!firstChild) { childNumber = node.getChildCount() - 1; } return node.getChild(childNumber); } return null; }
Example 10
Source File: ScrollFeedbackManager.java From talkback with Apache License 2.0 | 5 votes |
private static CharSequence getSelectedPageTitle(AccessibilityNodeInfo node) { // We need to refresh() after the scroll to get an accurate page title if (node == null) { return null; } AccessibilityNodeInfoCompat nodeCompat = AccessibilityNodeInfoUtils.toCompat(node); nodeCompat.refresh(); int numChildren = nodeCompat.getChildCount(); // Not the number of pages! CharSequence title = null; for (int i = 0; i < numChildren; ++i) { AccessibilityNodeInfoCompat child = nodeCompat.getChild(i); if (child != null) { try { if (child.isVisibleToUser()) { if (title == null) { // Try to roughly match RulePagerPage, which uses getNodeText // (but completely matching all the time is not critical). title = AccessibilityNodeInfoUtils.getNodeText(child); } else { // Multiple visible children, abort. return null; } } } finally { child.recycle(); } } } return title; }
Example 11
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 5 votes |
/** * Collects all descendants that match filter, into matches. * * @param node The root node to start searching. * @param filter The filter to match the nodes against. * @param matchRoot Flag that allows match with root node. * @param visitedNodes The set of nodes already visited, for protection against loops. This will * be modified. Caller is responsible to recycle the nodes. * @param matches The list of nodes matching filter. This will be appended to. Caller is * responsible to recycle this. */ private static void getMatchingDescendants( @Nullable AccessibilityNodeInfoCompat node, Filter<AccessibilityNodeInfoCompat> filter, boolean matchRoot, Set<AccessibilityNodeInfoCompat> visitedNodes, List<AccessibilityNodeInfoCompat> matches) { if (node == null) { return; } // Update visited nodes. if (visitedNodes.contains(node)) { return; } else { visitedNodes.add(AccessibilityNodeInfoCompat.obtain(node)); // Caller must recycle } // If node matches filter... collect node. if (matchRoot && filter.accept(node)) { matches.add(AccessibilityNodeInfoCompat.obtain(node)); // Caller must recycle } // For each child of node... int childCount = node.getChildCount(); for (int i = 0; i < childCount; ++i) { AccessibilityNodeInfoCompat child = node.getChild(i); // Must recycle if (child == null) { continue; } try { // Recurse on child. getMatchingDescendants(child, filter, /* matchRoot= */ true, visitedNodes, matches); } finally { child.recycle(); } } }
Example 12
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 5 votes |
/** * Returns the first child (by depth-first search) of {@code node} that matches the {@code * filter}. Returns {@code null} if no nodes match. The caller is responsible for recycling all * nodes in {@code visitedNodes} and the node returned by this method, if non-{@code null}. */ private static @Nullable AccessibilityNodeInfoCompat getMatchingDescendant( AccessibilityNodeInfoCompat node, Filter<AccessibilityNodeInfoCompat> filter, HashSet<AccessibilityNodeInfoCompat> visitedNodes) { if (node == null) { return null; } if (visitedNodes.contains(node)) { return null; } else { visitedNodes.add(AccessibilityNodeInfoCompat.obtain(node)); } int childCount = node.getChildCount(); for (int i = 0; i < childCount; ++i) { AccessibilityNodeInfoCompat child = node.getChild(i); if (child == null) { continue; } if (filter.accept(child)) { return child; // child was already obtained by node.getChild(). } try { AccessibilityNodeInfoCompat childMatch = getMatchingDescendant(child, filter, visitedNodes); if (childMatch != null) { return childMatch; } } finally { child.recycle(); } } return null; }
Example 13
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 5 votes |
public static @Nullable CharSequence getSelectedPageTitle(AccessibilityNodeInfoCompat viewPager) { if ((viewPager == null) || (Role.getRole(viewPager) != Role.ROLE_PAGER)) { return null; } int numChildren = viewPager.getChildCount(); // Not the number of pages! CharSequence title = null; for (int i = 0; i < numChildren; ++i) { AccessibilityNodeInfoCompat child = viewPager.getChild(i); if (child != null) { try { if (child.isVisibleToUser()) { if (title == null) { // Try to roughly match RulePagerPage, which uses getNodeText // (but completely matching all the time is not critical). title = getNodeText(child); } else { // Multiple visible children, abort. return null; } } } finally { recycleNodes(child); } } } return title; }
Example 14
Source File: CollectionState.java From talkback with Apache License 2.0 | 5 votes |
/** * For finding the name of the header, we want to use a simpler strategy than the * NodeSpeechRuleProcessor. We don't want to include the role description of items within the * header, because it will add confusion when the header name is appended to collection items. But * we do want to search down the tree in case the immediate root element doesn't have text. * * <p>We traverse single children of single children until we find a node with text. If we hit any * node that has multiple children, we simply stop the search and return {@code null}. */ public static @Nullable CharSequence getHeaderText(AccessibilityNodeInfoCompat node) { if (node == null) { return null; } Set<AccessibilityNodeInfoCompat> visitedNodes = new HashSet<>(); try { AccessibilityNodeInfoCompat currentNode = AccessibilityNodeInfoCompat.obtain(node); while (currentNode != null) { if (!visitedNodes.add(currentNode)) { // Cycle in traversal. currentNode.recycle(); return null; } CharSequence nodeText = AccessibilityNodeInfoUtils.getNodeText(currentNode); if (nodeText != null) { return nodeText; } if (currentNode.getChildCount() != 1) { return null; } currentNode = currentNode.getChild(0); } } finally { AccessibilityNodeInfoUtils.recycleNodes(visitedNodes); } return null; }
Example 15
Source File: DirectionalTraversalStrategy.java From talkback with Apache License 2.0 | 4 votes |
/** * Goes through root and its descendant nodes, sorting out the focusable nodes and the container * nodes for use in finding focus. * * @return whether the root is focusable or has focusable children in its hierarchy */ private boolean processNodes(AccessibilityNodeInfoCompat root, boolean forceRefresh) { if (root == null) { return false; } if (forceRefresh) { root.refresh(); } Rect currentRect = new Rect(); root.getBoundsInScreen(currentRect); // Determine if the node is inside mRootRect (within a fudge factor). If it is outside, we // will optimize by skipping its entire hierarchy. if (!Rect.intersects(currentRect, mRootRectPadded)) { return false; } AccessibilityNodeInfoCompat rootNode = AccessibilityNodeInfoCompat.obtain(root); mAllNodes.add(rootNode); // When we reach a node that supports web navigation, we traverse using the web navigation // actions, so we should not add any of its descendants to the list of focusable nodes. if (WebInterfaceUtils.hasNativeWebContent(rootNode)) { mFocusables.add(rootNode); return true; } else { boolean isFocusable = AccessibilityNodeInfoUtils.shouldFocusNode(rootNode, mSpeakingNodesCache); if (isFocusable) { mFocusables.add(rootNode); } boolean hasFocusableDescendants = false; int childCount = rootNode.getChildCount(); for (int i = 0; i < childCount; ++i) { AccessibilityNodeInfoCompat child = rootNode.getChild(i); if (child != null) { hasFocusableDescendants |= processNodes(child, forceRefresh); child.recycle(); } } if (hasFocusableDescendants) { mContainers.add(rootNode); } return isFocusable || hasFocusableDescendants; } }
Example 16
Source File: FeedbackUtils.java From talkback with Apache License 2.0 | 4 votes |
/** * Gets the developer-provided text inside a node that will be used to generate spoken feedback. * If the node does not have any text, we attempt to get node text of any non-focusable children. * If there are no focusable children with text, an empty string will be returned. * * <p>Note: This method should never be called with nodes returned from * AccessibilityNodeInfo#obtain. These nodes do not retain children information, so this method * may return the incorrect text. Instead, use SwitchAccessNodeCompat#getNodeText. * * @param nodeCompat the {@link AccessibilityNodeInfoCompat} of the node from which the * developer-provided text should be retrieved * @return the developer-provided text (content description or text) of the given node. If there * is neither content description nor text inside the node or its children, then return an * empty string */ public static String getNodeText(AccessibilityNodeInfoCompat nodeCompat) { CharSequence speakableText = nodeCompat.getContentDescription(); if (StringUtils.isEmpty(speakableText)) { speakableText = nodeCompat.getText(); } // If speakable text is empty, see if there are any non-focusable children nodes. If so, use // their text for the speakable text of this node. We filter out any focusable children nodes // to prevent duplicated speakable text from both a parent and child node. if (StringUtils.isEmpty(speakableText)) { StringBuilder builder = new StringBuilder(); int numChildren = nodeCompat.getChildCount(); for (int i = 0; i < numChildren; i++) { AccessibilityNodeInfoCompat child = nodeCompat.getChild(i); if ((child != null) && AccessibilityNodeInfoUtils.hasMinimumPixelsVisibleOnScreen(child) && !AccessibilityNodeInfoUtils.shouldFocusNode(child)) { CharSequence childText = getNodeText(child); if (!StringUtils.isEmpty(childText)) { if (builder.length() != 0) { builder.append(" "); } builder.append(childText); } } if (child != null) { child.recycle(); } } speakableText = builder.toString(); } if (StringUtils.isEmpty(speakableText)) { speakableText = ""; } return speakableText.toString(); }
Example 17
Source File: AccessibilityNodeInfoUtils.java From talkback with Apache License 2.0 | 4 votes |
private static boolean hasNonActionableSpeakingChildren( AccessibilityNodeInfoCompat node, Map<AccessibilityNodeInfoCompat, Boolean> speakingNodeCache, Set<AccessibilityNodeInfoCompat> visitedNodes) { final int childCount = node.getChildCount(); AccessibilityNodeInfoCompat child; // Has non-actionable, speaking children? for (int i = 0; i < childCount; i++) { child = node.getChild(i); if (child == null) { LogUtils.v(TAG, "Child %d is null, skipping it", i); continue; } if (!visitedNodes.add(child)) { child.recycle(); return false; } // Ignore invisible nodes. if (!isVisible(child)) { LogUtils.v(TAG, "Child %d is invisible, skipping it", i); continue; } // Ignore focusable nodes. if (isAccessibilityFocusableInternal(child, speakingNodeCache, visitedNodes)) { LogUtils.v(TAG, "Child %d is focusable, skipping it", i); continue; } // Recursively check non-focusable child nodes. if (isSpeakingNode(child, speakingNodeCache, visitedNodes)) { LogUtils.v(TAG, "Does have actionable speaking children (child %d)", i); return true; } } LogUtils.v(TAG, "Does not have non-actionable speaking children"); return false; }
Example 18
Source File: CollectionState.java From talkback with Apache License 2.0 | 4 votes |
private static void updateTableHeaderInfo( AccessibilityNodeInfoCompat collectionRoot, SparseArray<CharSequence> rowHeaders, SparseArray<CharSequence> columnHeaders, boolean computeHeaders) { rowHeaders.clear(); columnHeaders.clear(); if (!computeHeaders) { return; } if (collectionRoot == null || collectionRoot.getCollectionInfo() == null) { return; } // Limit search to children and grandchildren of the root node for performance reasons. // We want to search grandchildren because web pages put table headers <th> inside table // rows <tr> so they are nested two levels down. CollectionInfoCompat collectionInfo = collectionRoot.getCollectionInfo(); int numChildren = collectionRoot.getChildCount(); for (int i = 0; i < numChildren; ++i) { AccessibilityNodeInfoCompat child = collectionRoot.getChild(i); if (child == null) { continue; } if (!updateSingleTableHeader(child, collectionInfo, rowHeaders, columnHeaders)) { int numGrandchildren = child.getChildCount(); for (int j = 0; j < numGrandchildren; ++j) { AccessibilityNodeInfoCompat grandchild = child.getChild(j); if (grandchild == null) { continue; } updateSingleTableHeader(grandchild, collectionInfo, rowHeaders, columnHeaders); grandchild.recycle(); } } child.recycle(); } }