public final void onInitializeAccessibilityNodeInfo(View paramView, AccessibilityNodeInfoCompat paramAccessibilityNodeInfoCompat) { super.onInitializeAccessibilityNodeInfo(paramView, paramAccessibilityNodeInfoCompat); paramAccessibilityNodeInfoCompat.setClassName(RecyclerView.class.getName()); if ((!shouldIgnore()) && (this.mRecyclerView.getLayoutManager() != null)) { RecyclerView.LayoutManager localLayoutManager = this.mRecyclerView.getLayoutManager(); RecyclerView.Recycler localRecycler = localLayoutManager.mRecyclerView.mRecycler; RecyclerView.State localState = localLayoutManager.mRecyclerView.mState; if ((ViewCompat.canScrollVertically(localLayoutManager.mRecyclerView, -1)) || (ViewCompat.canScrollHorizontally(localLayoutManager.mRecyclerView, -1))) { paramAccessibilityNodeInfoCompat.addAction(8192); paramAccessibilityNodeInfoCompat.setScrollable(true); } if ((ViewCompat.canScrollVertically(localLayoutManager.mRecyclerView, 1)) || (ViewCompat.canScrollHorizontally(localLayoutManager.mRecyclerView, 1))) { paramAccessibilityNodeInfoCompat.addAction(4096); paramAccessibilityNodeInfoCompat.setScrollable(true); } int i = localLayoutManager.getRowCountForAccessibility(localRecycler, localState); int j = localLayoutManager.getColumnCountForAccessibility(localRecycler, localState); AccessibilityNodeInfoCompat.CollectionInfoCompat localCollectionInfoCompat = new AccessibilityNodeInfoCompat.CollectionInfoCompat(AccessibilityNodeInfoCompat.access$000().obtainCollectionInfo(i, j, false, 0)); AccessibilityNodeInfoCompat.IMPL.setCollectionInfo(paramAccessibilityNodeInfoCompat.mInfo, ((AccessibilityNodeInfoCompat.CollectionInfoCompat)localCollectionInfoCompat).mInfo); } }
private static boolean updateSingleTableHeader(@Nullable AccessibilityNodeInfoCompat node, CollectionInfoCompat collectionInfo, SparseArray<CharSequence> rowHeaders, SparseArray<CharSequence> columnHeaders) { if (node == null) { return false; } CharSequence headingName = getHeaderText(node); CollectionItemInfoCompat itemInfo = node.getCollectionItemInfo(); if (itemInfo != null && headingName != null) { @RowColumnTransition int headingType = getTableHeading(itemInfo, collectionInfo); if ((headingType & TYPE_ROW) != 0) { rowHeaders.put(itemInfo.getRowIndex(), headingName); } if ((headingType & TYPE_COLUMN) != 0) { columnHeaders.put(itemInfo.getColumnIndex(), headingName); } return headingType != TYPE_NONE; } return false; }
/** * In this method, only one cell per row and per column can be the row or column header. * Additionally, a cell can be a row or column header but not both. * * @return {@code TYPE_ROW} or {@ocde TYPE_COLUMN} for row or column headers; * {@code TYPE_INDETERMINATE} for cells marked as headers that are neither row nor column * headers; {@code TYPE_NONE} for all other cells. */ private static @TableHeadingType int getTableHeading(@NonNull CollectionItemInfoCompat item, @NonNull CollectionInfoCompat collection) { if (item.isHeading()) { if (item.getRowSpan() == 1 && item.getColumnSpan() == 1) { if (getRowIndex(item, collection) == 0) { return TYPE_COLUMN; } if (getColumnIndex(item, collection) == 0) { return TYPE_ROW; } } return TYPE_INDETERMINATE; } return TYPE_NONE; }
private static boolean shouldEnter(@NonNull AccessibilityNodeInfoCompat collectionRoot) { if (collectionRoot.getCollectionInfo() != null) { // If the collection info reports that this is a 1x1 collection, then we discard it // and treat it as though we are outside of a collection. CollectionInfoCompat collectionInfo = collectionRoot.getCollectionInfo(); if (collectionInfo.getColumnCount() <= 1 && collectionInfo.getRowCount() <= 1) { return false; } } else if (collectionRoot.getChildCount() <= 1) { // If we don't have collection info, use the child count as an approximation. return false; } // If the collection is flat and contains other flat collections, then we discard it. // We only announce hierarchies of collections if they are explicitly marked hierarchical. // Otherwise we announce only the innermost collection. if (FILTER_FLAT_COLLECTION.accept(collectionRoot) && AccessibilityNodeInfoUtils .hasMatchingDescendant(collectionRoot, FILTER_FLAT_COLLECTION)) { return false; } return true; }
public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state, AccessibilityNodeInfoCompat info) { if (ViewCompat.canScrollVertically(this.mRecyclerView, -1) || ViewCompat.canScrollHorizontally(this.mRecyclerView, -1)) { info.addAction(8192); info.setScrollable(true); } if (ViewCompat.canScrollVertically(this.mRecyclerView, 1) || ViewCompat.canScrollHorizontally(this.mRecyclerView, 1)) { info.addAction(4096); info.setScrollable(true); } info.setCollectionInfo(CollectionInfoCompat.obtain(getRowCountForAccessibility(recycler, state), getColumnCountForAccessibility(recycler, state), isLayoutHierarchical(recycler, state), getSelectionModeForAccessibility(recycler, state))); }
public static @CollectionAlignment int getCollectionAlignmentInternal( @Nullable CollectionInfoCompat collection) { if (collection == null || collection.getRowCount() >= collection.getColumnCount()) { return ALIGNMENT_VERTICAL; } else { return ALIGNMENT_HORIZONTAL; } }
@Nullable private static ListItemState getListItemStateKitKat( AccessibilityNodeInfoCompat collectionRoot, AccessibilityNodeInfoCompat announcedNode, boolean computeHeaders, boolean computeNumbering) { if (collectionRoot == null || collectionRoot.getCollectionInfo() == null) { return null; } // Checking the ancestors should incur zero performance penalty in the typical case // where list items are direct descendants. Assuming list items are not deeply // nested, any performance penalty would be minimal. AccessibilityNodeInfoCompat collectionItem = AccessibilityNodeInfoUtils .getSelfOrMatchingAncestor(announcedNode, collectionRoot, FILTER_COLLECTION_ITEM); if (collectionItem == null) { return null; } CollectionInfoCompat collection = collectionRoot.getCollectionInfo(); CollectionItemInfoCompat item = collectionItem.getCollectionItemInfo(); boolean heading = computeHeaders && item.isHeading(); int index; if (getCollectionAlignmentInternal(collection) == ALIGNMENT_VERTICAL) { index = getRowIndex(item, collection); } else { index = getColumnIndex(item, collection); } collectionItem.recycle(); return new ListItemState(heading, index, computeNumbering); }
@Nullable private static TableItemState getTableItemStateKitKat( AccessibilityNodeInfoCompat collectionRoot, AccessibilityNodeInfoCompat announcedNode, SparseArray<CharSequence> rowHeaders, SparseArray<CharSequence> columnHeaders, boolean computeHeaders, boolean computeNumbering) { if (collectionRoot == null || collectionRoot.getCollectionInfo() == null) { return null; } // Checking the ancestors should incur zero performance penalty in the typical case // where list items are direct descendants. Assuming list items are not deeply // nested, any performance penalty would be minimal. AccessibilityNodeInfoCompat collectionItem = AccessibilityNodeInfoUtils .getSelfOrMatchingAncestor(announcedNode, collectionRoot, FILTER_COLLECTION_ITEM); if (collectionItem == null) { return null; } CollectionInfoCompat collection = collectionRoot.getCollectionInfo(); CollectionItemInfoCompat item = collectionItem.getCollectionItemInfo(); int heading = computeHeaders ? getTableHeading(item, collection) : TYPE_NONE; int rowIndex = getRowIndex(item, collection); int columnIndex = getColumnIndex(item, collection); CharSequence rowName = rowIndex != -1 ? rowHeaders.get(rowIndex) : null; CharSequence columnName = columnIndex != -1 ? columnHeaders.get(columnIndex) : null; collectionItem.recycle(); return new TableItemState( heading, rowName, columnName, rowIndex, columnIndex, computeNumbering); }
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 (!updateSingleTableHeader(child, collectionInfo, rowHeaders, columnHeaders)) { int numGrandchildren = child.getChildCount(); for (int j = 0; j < numGrandchildren; ++j) { AccessibilityNodeInfoCompat grandchild = child.getChild(j); updateSingleTableHeader(grandchild, collectionInfo, rowHeaders, columnHeaders); grandchild.recycle(); } } child.recycle(); } }
/** * @return -1 if there is no valid row index for the item; otherwise the item's row index */ private static int getRowIndex(@NonNull CollectionItemInfoCompat item, @NonNull CollectionInfoCompat collection) { if (item.getRowSpan() == collection.getRowCount()) { return -1; } else if (item.getRowIndex() < 0) { return -1; } else { return item.getRowIndex(); } }
/** * @return -1 if there is no valid column index for the item; otherwise the item's column index */ private static int getColumnIndex(@NonNull CollectionItemInfoCompat item, @NonNull CollectionInfoCompat collection) { if (item.getColumnSpan() == collection.getColumnCount()) { return -1; } else if (item.getColumnIndex() < 0) { return -1; } else { return item.getColumnIndex(); } }