Java Code Examples for androidx.core.view.accessibility.AccessibilityNodeInfoCompat#getCollectionInfo()

The following examples show how to use androidx.core.view.accessibility.AccessibilityNodeInfoCompat#getCollectionInfo() . 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: MaterialButtonToggleGroupTest.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Test
@Config(sdk = 23)
public void onInitializeAccessibilityNodeInfo() {
  AccessibilityNodeInfoCompat groupInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(toggleGroup, groupInfoCompat);

  CollectionInfoCompat collectionInfo = groupInfoCompat.getCollectionInfo();
  assertEquals(3, collectionInfo.getColumnCount());
  assertEquals(1, collectionInfo.getRowCount());

  MaterialButton secondChild = (MaterialButton) toggleGroup.getChildAt(1);
  secondChild.setChecked(true);
  AccessibilityNodeInfoCompat buttonInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(secondChild, buttonInfoCompat);

  CollectionItemInfoCompat itemInfo = buttonInfoCompat.getCollectionItemInfo();
  assertEquals(1, itemInfo.getColumnIndex());
  assertEquals(0, itemInfo.getRowIndex());
  assertTrue(itemInfo.isSelected());
}
 
Example 2
Source File: ChipGroupTest.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Test
@Config(minSdk = 23, maxSdk = 28)
public void isSingleLine_initializesAccessibilityNodeInfo() {
  chipgroup.setSingleLine(true);
  AccessibilityNodeInfoCompat groupInfoCompat = AccessibilityNodeInfoCompat.obtain();
  // onLayout must be triggered for rowCount
  chipgroup.layout(0, 0, 100, 100);

  ViewCompat.onInitializeAccessibilityNodeInfo(chipgroup, groupInfoCompat);

  CollectionInfoCompat collectionInfo = groupInfoCompat.getCollectionInfo();
  assertEquals(chipgroup.getChildCount(), collectionInfo.getColumnCount());
  assertEquals(1, collectionInfo.getRowCount());

  Chip secondChild = (Chip) chipgroup.getChildAt(1);
  secondChild.setChecked(true);
  AccessibilityNodeInfoCompat chipInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(secondChild, chipInfoCompat);

  CollectionItemInfoCompat itemInfo = chipInfoCompat.getCollectionItemInfo();
  assertEquals(1, itemInfo.getColumnIndex());
  assertEquals(0, itemInfo.getRowIndex());
  assertTrue(itemInfo.isSelected());
}
 
Example 3
Source File: ChipGroupTest.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Test
@Config(minSdk = 23, maxSdk = 28)
public void isNotSingleLine_initializesAccessibilityNodeInfo() {
  AccessibilityNodeInfoCompat groupInfoCompat = AccessibilityNodeInfoCompat.obtain();
  // onLayout must be triggered for rowCount
  chipgroup.layout(0, 0, 10, 100);
  ViewCompat.onInitializeAccessibilityNodeInfo(chipgroup, groupInfoCompat);

  CollectionInfoCompat collectionInfo = groupInfoCompat.getCollectionInfo();
  assertEquals(-1, collectionInfo.getColumnCount());
  assertEquals(2, collectionInfo.getRowCount());

  Chip secondChild = (Chip) chipgroup.getChildAt(2);
  secondChild.setChecked(true);
  AccessibilityNodeInfoCompat chipInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(secondChild, chipInfoCompat);

  CollectionItemInfoCompat itemInfo = chipInfoCompat.getCollectionItemInfo();
  assertEquals(-1, itemInfo.getColumnIndex());
  assertEquals(1, itemInfo.getRowIndex());
  assertTrue(itemInfo.isSelected());
}
 
Example 4
Source File: AccessibilityUtil.java    From screenshot-tests-for-android with Apache License 2.0 6 votes vote down vote up
/**
 * Gets the role from a given {@link AccessibilityNodeInfoCompat}. If no role is defined it will
 * return AccessibilityRole.NONE, which has a value of null.
 *
 * @param node The node to check.
 * @return {@code AccessibilityRole} the defined role.
 */
public static AccessibilityRole getRole(AccessibilityNodeInfoCompat nodeInfo) {
  AccessibilityRole role = AccessibilityRole.fromValue((String) nodeInfo.getClassName());
  if (role.equals(AccessibilityRole.IMAGE_BUTTON) || role.equals(AccessibilityRole.IMAGE)) {
    return nodeInfo.isClickable() ? AccessibilityRole.IMAGE_BUTTON : AccessibilityRole.IMAGE;
  }

  if (role.equals(AccessibilityRole.NONE)) {
    AccessibilityNodeInfoCompat.CollectionInfoCompat collection = nodeInfo.getCollectionInfo();
    if (collection != null) {
      // RecyclerView will be classified as a list or grid.
      if (collection.getRowCount() > 1 && collection.getColumnCount() > 1) {
        return AccessibilityRole.GRID;
      } else {
        return AccessibilityRole.LIST;
      }
    }
  }

  return role;
}
 
Example 5
Source File: CollectionState.java    From talkback with Apache License 2.0 6 votes vote down vote up
private static boolean shouldEnter(@NonNull AccessibilityNodeInfoCompat collectionRoot) {
  if (collectionRoot.getCollectionInfo() != null) {
    CollectionInfoCompat collectionInfo = collectionRoot.getCollectionInfo();
    if (!hasMultipleItems(
        collectionInfo.getRowCount(),
        collectionInfo.getColumnCount(),
        Role.getRole(collectionRoot))) {
      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;
}
 
Example 6
Source File: BottomNavigationViewTest.java    From material-components-android with Apache License 2.0 5 votes vote down vote up
@UiThreadTest
@Test
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
public void testOnInitializeAccessibilityNodeInfo() {
  BottomNavigationMenuView menuView = bottomNavigation.menuView;

  AccessibilityNodeInfoCompat groupInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(menuView, groupInfoCompat);

  CollectionInfoCompat collectionInfo = groupInfoCompat.getCollectionInfo();
  Assert.assertEquals(3, collectionInfo.getColumnCount());
  Assert.assertEquals(1, collectionInfo.getRowCount());

  BottomNavigationItemView secondChild = (BottomNavigationItemView) menuView.getChildAt(1);
  secondChild.setSelected(true);
  AccessibilityNodeInfoCompat buttonInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(secondChild, buttonInfoCompat);

  // A tab that is currently selected won't be clickable by a11y
  assertFalse(buttonInfoCompat.isClickable());
  assertFalse(
      AccessibilityUtils.hasAction(buttonInfoCompat, AccessibilityActionCompat.ACTION_CLICK));

  CollectionItemInfoCompat itemInfo = buttonInfoCompat.getCollectionItemInfo();
  Assert.assertEquals(1, itemInfo.getColumnIndex());
  Assert.assertEquals(0, itemInfo.getRowIndex());
  assertTrue(itemInfo.isSelected());
}
 
Example 7
Source File: TabLayoutTest.java    From material-components-android with Apache License 2.0 5 votes vote down vote up
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
public void initializesAccessibilityNodeInfo() {
  final LayoutInflater inflater = LayoutInflater.from(activityTestRule.getActivity());
  final TabLayout tabs = (TabLayout) inflater.inflate(R.layout.design_tabs, null);

  final TabLayout.Tab tab1 = tabs.newTab();
  tabs.addTab(tab1);
  final TabLayout.Tab tab2 = tabs.newTab();
  tabs.addTab(tab2, true);

  tabs.getTabAt(0).setCustomView(R.layout.design_tab_item_custom);
  tabs.getTabAt(1).setCustomView(R.layout.design_tab_item_custom);

  AccessibilityNodeInfoCompat groupInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(tabs, groupInfoCompat);

  CollectionInfoCompat collectionInfo = groupInfoCompat.getCollectionInfo();
  assertEquals(2, collectionInfo.getColumnCount());
  assertEquals(1, collectionInfo.getRowCount());

  TabView secondChild = tabs.getTabAt(1).view;
  secondChild.setSelected(true);
  AccessibilityNodeInfoCompat tabInfoCompat = AccessibilityNodeInfoCompat.obtain();
  ViewCompat.onInitializeAccessibilityNodeInfo(secondChild, tabInfoCompat);

  // A tab that is currently selected won't be clickable
  assertFalse(tabInfoCompat.isClickable());
  assertFalse(
      AccessibilityUtils.hasAction(tabInfoCompat, AccessibilityActionCompat.ACTION_CLICK));

  CollectionItemInfoCompat itemInfo = tabInfoCompat.getCollectionItemInfo();
  assertEquals(1, itemInfo.getColumnIndex());
  assertEquals(0, itemInfo.getRowIndex());
  assertTrue(itemInfo.isSelected());
}
 
Example 8
Source File: CollectionState.java    From talkback with Apache License 2.0 5 votes vote down vote up
@Nullable
private static ListItemState getListItemState(
    AccessibilityNodeInfoCompat collectionRoot,
    AccessibilityNodeInfoCompat announcedNode,
    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 = AccessibilityNodeInfoUtils.isHeading(collectionItem);
  int index;
  if (getCollectionAlignmentInternal(collection) == ALIGNMENT_VERTICAL) {
    index = getRowIndex(item, collection);
  } else {
    index = getColumnIndex(item, collection);
  }

  collectionItem.recycle();
  return new ListItemState(heading, index, computeNumbering);
}
 
Example 9
Source File: CollectionState.java    From talkback with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a non-{@code null} PagerItemState if {@code collectionRoot} and {@code announcedNode}
 * are not null.
 *
 * @param collectionRoot the node with role {@link
 *     com.google.android.accessibility.utils.Role#ROLE_PAGER}, representing a collection of
 *     pages. Its descendants include {@code announcedNode}
 * @param announcedNode the node that was given accessibility focus. It is or is a child of a page
 *     item that belongs to the pager defined by {@code collectionRoot}
 * @param computeHeaders is {@code true} if {@link
 *     #shouldComputeHeaders(AccessibilityNodeInfoCompat)} returns {@code true}
 * @return
 */
@Nullable
private static PagerItemState extractPagerItemState(
    AccessibilityNodeInfoCompat collectionRoot,
    AccessibilityNodeInfoCompat announcedNode,
    boolean computeHeaders) {
  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.

  AccessibilityNode collectionItem =
      AccessibilityNode.takeOwnership(
          AccessibilityNodeInfoUtils.getSelfOrMatchingAncestor(
              announcedNode, collectionRoot, FILTER_COLLECTION_ITEM));

  if (collectionItem == null) {
    return null;
  }

  try {
    CollectionInfoCompat collection = collectionRoot.getCollectionInfo();
    CollectionItemInfoCompat item = collectionItem.getCollectionItemInfo();

    boolean heading = computeHeaders && collectionItem.isHeading();
    int rowIndex = getRowIndex(item, collection);
    int columnIndex = getColumnIndex(item, collection);

    return new PagerItemState(heading, rowIndex, columnIndex);
  } finally {
    collectionItem.recycle("CollectionState.extractPagerItemState");
  }
}
 
Example 10
Source File: CollectionState.java    From talkback with Apache License 2.0 5 votes vote down vote up
@Nullable
private static TableItemState getTableItemState(
    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(collectionItem, 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);
}
 
Example 11
Source File: CollectionState.java    From talkback with Apache License 2.0 4 votes vote down vote up
@Override
public boolean accept(AccessibilityNodeInfoCompat node) {
  return FILTER_COLLECTION.accept(node)
      && node.getCollectionInfo() != null
      && node.getCollectionInfo().isHierarchical();
}
 
Example 12
Source File: CollectionState.java    From talkback with Apache License 2.0 4 votes vote down vote up
@Override
public boolean accept(AccessibilityNodeInfoCompat node) {
  return FILTER_COLLECTION.accept(node)
      && (node.getCollectionInfo() == null || !node.getCollectionInfo().isHierarchical());
}
 
Example 13
Source File: CollectionState.java    From talkback with Apache License 2.0 4 votes vote down vote up
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();
  }
}
 
Example 14
Source File: AccessibilityNodeInfoUtils.java    From talkback with Apache License 2.0 3 votes vote down vote up
/**
 * Returns whether the specified node has text. For the purposes of this check, any node with a
 * CollectionInfo is considered to not have text since its text and content description are used
 * only for collection transitions.
 *
 * @param node The node to check.
 * @return {@code true} if the node has text.
 */
private static boolean hasText(AccessibilityNodeInfoCompat node) {
  return node != null
      && node.getCollectionInfo() == null
      && (!TextUtils.isEmpty(node.getText())
          || !TextUtils.isEmpty(node.getContentDescription())
          || !TextUtils.isEmpty(node.getHintText()));
}
 
Example 15
Source File: AccessibilityUtil.java    From screenshot-tests-for-android with Apache License 2.0 2 votes vote down vote up
/**
 * Returns whether the specified node has text or a content description.
 *
 * @param node The node to check.
 * @return {@code true} if the node has text.
 */
public static boolean hasText(@Nullable AccessibilityNodeInfoCompat node) {
  return node != null
      && node.getCollectionInfo() == null
      && (!TextUtils.isEmpty(node.getText()) || !TextUtils.isEmpty(node.getContentDescription()));
}