androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat Java Examples

The following examples show how to use androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat. 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 vote down vote up
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 #2
Source File: BottomNavigationItemView.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Override
public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
  super.onInitializeAccessibilityNodeInfo(info);
  if (badgeDrawable != null && badgeDrawable.isVisible()) {
    CharSequence customContentDescription = itemData.getTitle();
    if (!TextUtils.isEmpty(itemData.getContentDescription())) {
      customContentDescription = itemData.getContentDescription();
    }
    info.setContentDescription(
        customContentDescription + ", " + badgeDrawable.getContentDescription());
  }
  AccessibilityNodeInfoCompat infoCompat = AccessibilityNodeInfoCompat.wrap(info);
  infoCompat.setCollectionItemInfo(
      CollectionItemInfoCompat.obtain(
          /* rowIndex= */ 0,
          /* rowSpan= */ 1,
          /* columnIndex= */ getItemPosition(),
          /* columnSpan= */ 1,
          /* heading= */ false,
          /* selected= */ isSelected()));
  if (isSelected()) {
    infoCompat.setClickable(false);
    infoCompat.removeAction(AccessibilityActionCompat.ACTION_CLICK);
  }
  infoCompat.setRoleDescription(getResources().getString(R.string.item_view_role_description));
}
 
Example #3
Source File: TabLayout.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Override
public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
  super.onInitializeAccessibilityNodeInfo(info);
  if (badgeDrawable != null && badgeDrawable.isVisible()) {
    CharSequence customContentDescription = getContentDescription();
    info.setContentDescription(
        customContentDescription + ", " + badgeDrawable.getContentDescription());
  }
  AccessibilityNodeInfoCompat infoCompat = AccessibilityNodeInfoCompat.wrap(info);
  infoCompat.setCollectionItemInfo(
      CollectionItemInfoCompat.obtain(
          /* rowIndex= */ 0,
          /* rowSpan= */ 1,
          /* columnIndex= */ tab.getPosition(),
          /* columnSpan= */ 1,
          /* heading= */ false,
          /* selected= */ isSelected()));
  if (isSelected()) {
    infoCompat.setClickable(false);
    infoCompat.removeAction(AccessibilityActionCompat.ACTION_CLICK);
  }
  infoCompat.setRoleDescription("Tab");
}
 
Example #4
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 #5
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 #6
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 #7
Source File: PreferenceCategory.java    From MaterialPreference with Apache License 2.0 6 votes vote down vote up
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfoCompat info) {
    super.onInitializeAccessibilityNodeInfo(info);

    CollectionItemInfoCompat existingItemInfo = info.getCollectionItemInfo();
    if (existingItemInfo == null) {
        return;
    }

    final CollectionItemInfoCompat newItemInfo = CollectionItemInfoCompat.obtain(
            existingItemInfo.getRowIndex(),
            existingItemInfo.getRowSpan(),
            existingItemInfo.getColumnIndex(),
            existingItemInfo.getColumnSpan(),
            true /* heading */,
            existingItemInfo.isSelected());
    info.setCollectionItemInfo(newItemInfo);
}
 
Example #8
Source File: CollectionState.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * 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 AccessibilityNodeInfoCompat node,
    @NonNull CollectionItemInfoCompat item,
    @NonNull CollectionInfoCompat collection) {
  if (AccessibilityNodeInfoUtils.isHeading(node)) {
    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;
}
 
Example #9
Source File: CollectionState.java    From talkback with Apache License 2.0 6 votes vote down vote up
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(node, 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;
}
 
Example #10
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 #11
Source File: NodeDescription.java    From talkback with Apache License 2.0 5 votes vote down vote up
static NodeDescription obtain(AccessibilityNodeInfoCompat node) {
  CollectionItemInfoCompat itemInfo = node.getCollectionItemInfo();
  return new NodeDescription(
      node.getClassName(),
      node.getViewIdResourceName(),
      itemInfo == null ? INDEX_TYPE_RAW : INDEX_TYPE_COLLECTION,
      itemInfo == null ? UNDEFINED_INDEX : itemInfo.getRowIndex(),
      itemInfo == null ? UNDEFINED_INDEX : itemInfo.getColumnIndex(),
      getRawIndexInParent(node),
      node.hashCode());
}
 
Example #12
Source File: CollectionState.java    From talkback with Apache License 2.0 5 votes vote down vote up
/**
 * @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();
  }
}
 
Example #13
Source File: CollectionState.java    From talkback with Apache License 2.0 5 votes vote down vote up
/** @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();
  }
}
 
Example #14
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 #15
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 #16
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 #17
Source File: Chip.java    From material-components-android with Apache License 2.0 5 votes vote down vote up
@Override
public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
  super.onInitializeAccessibilityNodeInfo(info);
  if (isCheckable() || isClickable()) {
    info.setClassName(
        isCheckable()
            ? COMPOUND_BUTTON_ACCESSIBILITY_CLASS_NAME
            : BUTTON_ACCESSIBILITY_CLASS_NAME);
  } else {
    info.setClassName(GENERIC_VIEW_ACCESSIBILITY_CLASS_NAME);
  }
  info.setCheckable(isCheckable());
  info.setClickable(isClickable());

  if (getParent() instanceof ChipGroup) {
    ChipGroup chipGroup = ((ChipGroup) getParent());
    AccessibilityNodeInfoCompat infoCompat = AccessibilityNodeInfoCompat.wrap(info);
    // -1 for unknown column indices in a reflowing layout
    int columnIndex = chipGroup.isSingleLine() ? chipGroup.getIndexOfChip(this) : -1;
    infoCompat.setCollectionItemInfo(
        CollectionItemInfoCompat.obtain(
            /* rowIndex= */ chipGroup.getRowIndex(this),
            /* rowSpan= */ 1,
            /* columnIndex= */ columnIndex,
            /* columnSpan= */ 1,
            /* heading= */ false,
            /* selected= */ isChecked()));
  }
}
 
Example #18
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 #19
Source File: AccessibilityNode.java    From talkback with Apache License 2.0 4 votes vote down vote up
public CollectionItemInfoCompat getCollectionItemInfo() {
  return getCompat().getCollectionItemInfo();
}
 
Example #20
Source File: MaterialButtonToggleGroup.java    From material-components-android with Apache License 2.0 4 votes vote down vote up
/**
 * This override prohibits Views other than {@link MaterialButton} to be added. It also makes
 * updates to the add button shape and margins.
 */
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
  if (!(child instanceof MaterialButton)) {
    Log.e(LOG_TAG, "Child views must be of type MaterialButton.");
    return;
  }

  super.addView(child, index, params);
  MaterialButton buttonChild = (MaterialButton) child;
  setGeneratedIdIfNeeded(buttonChild);
  // Sets sensible default values and an internal checked change listener for this child
  setupButtonChild(buttonChild);

  // Reorders children if a checked child was added to this layout
  if (buttonChild.isChecked()) {
    updateCheckedStates(buttonChild.getId(), true);
    setCheckedId(buttonChild.getId());
  }

  // Saves original corner data
  ShapeAppearanceModel shapeAppearanceModel = buttonChild.getShapeAppearanceModel();
  originalCornerData.add(
      new CornerData(
          shapeAppearanceModel.getTopLeftCornerSize(),
          shapeAppearanceModel.getBottomLeftCornerSize(),
          shapeAppearanceModel.getTopRightCornerSize(),
          shapeAppearanceModel.getBottomRightCornerSize()));

  ViewCompat.setAccessibilityDelegate(
      buttonChild,
      new AccessibilityDelegateCompat() {
        @Override
        public void onInitializeAccessibilityNodeInfo(
            View host, @NonNull AccessibilityNodeInfoCompat info) {
          super.onInitializeAccessibilityNodeInfo(host, info);
          info.setCollectionItemInfo(
              CollectionItemInfoCompat.obtain(
                  /* rowIndex= */ 0,
                  /* rowSpan= */ 1,
                  /* columnIndex= */ getIndexWithinVisibleButtons(host),
                  /* columnSpan= */ 1,
                  /* heading= */ false,
                  /* selected= */ ((MaterialButton) host).isChecked()));
        }
      });
}