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

The following examples show how to use androidx.core.view.accessibility.AccessibilityNodeInfoCompat#getBoundsInScreen() . 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: AccessibilityNodeInfoUtils.java    From talkback with Apache License 2.0 6 votes vote down vote up
/** Determines whether the specified node has bounds identical to the bounds of its window. */
private static boolean areBoundsIdenticalToWindow(AccessibilityNodeInfoCompat node) {
  if (node == null) {
    return false;
  }

  AccessibilityWindowInfoCompat window = getWindow(node);
  if (window == null) {
    return false;
  }

  Rect windowBounds = new Rect();
  window.getBoundsInScreen(windowBounds);

  Rect nodeBounds = new Rect();
  node.getBoundsInScreen(nodeBounds);

  return windowBounds.equals(nodeBounds);
}
 
Example 2
Source File: TraversalStrategyUtils.java    From talkback with Apache License 2.0 6 votes vote down vote up
private static boolean isNodeInBoundsOfOther(
    AccessibilityNodeInfoCompat outerNode, AccessibilityNodeInfoCompat innerNode) {
  if (outerNode == null || innerNode == null) {
    return false;
  }

  Rect outerRect = new Rect();
  Rect innerRect = new Rect();
  outerNode.getBoundsInScreen(outerRect);
  innerNode.getBoundsInScreen(innerRect);

  if (outerRect.top > innerRect.bottom || outerRect.bottom < innerRect.top) {
    return false;
  }

  //noinspection RedundantIfStatement
  if (outerRect.left > innerRect.right || outerRect.right < innerRect.left) {
    return false;
  }

  return true;
}
 
Example 3
Source File: ProcessorCursorState.java    From talkback with Apache License 2.0 6 votes vote down vote up
private void touchStart(AccessibilityEvent event, EventId eventId) {
  // Detect if the node is visible and editing; if so, then show the overlay with a delay.
  AccessibilityNodeInfoCompat refreshedNode = AccessibilityNodeInfoUtils.refreshNode(focusedNode);
  if (refreshedNode != null) {
    boolean focused;
    AccessibilityWindowInfoCompat window = AccessibilityNodeInfoUtils.getWindow(refreshedNode);
    focused =
        refreshedNode.isVisibleToUser()
            && refreshedNode.isFocused()
            && window != null
            && window.isFocused();
    if (focused) {
      Rect r = new Rect();
      refreshedNode.getBoundsInScreen(r);
      overlay.showDelayed(r);
    }
    refreshedNode.recycle();

    overlay.onAccessibilityEvent(event, eventId);
  }
}
 
Example 4
Source File: AccessibilityUtil.java    From screenshot-tests-for-android with Apache License 2.0 5 votes vote down vote up
/**
 * Returns whether a AccessibilityNodeInfoCompat has the same size and position as its containing
 * Window.
 *
 * @param node The {@link AccessibilityNodeInfoCompat} to evaluate
 * @return {@code true} if node has equal bounds to its containing Window
 */
public static boolean areBoundsIdenticalToWindow(AccessibilityNodeInfoCompat node, View view) {
  Window window = null;
  Context context = view.getContext();
  while (context instanceof ContextWrapper) {
    if (context instanceof Activity) {
      window = ((Activity) context).getWindow();
    }
    context = ((ContextWrapper) context).getBaseContext();
  }

  if (window == null) {
    return false;
  }

  WindowManager.LayoutParams windowParams = window.getAttributes();
  Rect windowBounds =
      new Rect(
          windowParams.x,
          windowParams.y,
          windowParams.x + windowParams.width,
          windowParams.y + windowParams.height);

  Rect nodeBounds = new Rect();
  node.getBoundsInScreen(nodeBounds);

  return windowBounds.equals(nodeBounds);
}
 
Example 5
Source File: DirectionalTraversalStrategy.java    From talkback with Apache License 2.0 5 votes vote down vote up
@Override
public @Nullable AccessibilityNodeInfoCompat focusInitial(
    AccessibilityNodeInfoCompat root, int direction) {
  if (root == null) {
    return null;
  }

  Rect rootRect = new Rect();
  root.getBoundsInScreen(rootRect);

  AccessibilityNodeInfoCompat focusedNode =
      root.findFocus(AccessibilityNodeInfoCompat.FOCUS_ACCESSIBILITY);

  Rect searchRect = new Rect();
  if (focusedNode != null) {
    getSearchStartRect(focusedNode, direction, searchRect);
  } else if (direction == TraversalStrategy.SEARCH_FOCUS_LEFT) {
    searchRect.set(rootRect.right, rootRect.top, rootRect.right + 1, rootRect.bottom);
  } else if (direction == TraversalStrategy.SEARCH_FOCUS_RIGHT) {
    searchRect.set(rootRect.left - 1, rootRect.top, rootRect.left, rootRect.bottom);
  } else if (direction == TraversalStrategy.SEARCH_FOCUS_UP) {
    searchRect.set(rootRect.left, rootRect.bottom, rootRect.right, rootRect.bottom + 1);
  } else {
    searchRect.set(rootRect.left, rootRect.top - 1, rootRect.right, rootRect.top);
  }

  AccessibilityNodeInfoCompat newFocus = findFocus(focusedNode, searchRect, direction);
  if (newFocus != null) {
    return AccessibilityNodeInfoCompat.obtain(newFocus);
  }

  return null;
}
 
Example 6
Source File: DirectionalTraversalStrategy.java    From talkback with Apache License 2.0 5 votes vote down vote up
/**
 * Returns the bounding rect of the given node for directional navigation purposes. Any node that
 * is a container of a focusable node will be reduced to a strip at its very top edge.
 */
private void getAssumedRectInScreen(AccessibilityNodeInfoCompat node, Rect assumedRect) {
  node.getBoundsInScreen(assumedRect);
  if (mContainers.contains(node)) {
    assumedRect.set(assumedRect.left, assumedRect.top, assumedRect.right, assumedRect.top + 1);
  }
}
 
Example 7
Source File: ReorderedChildrenIterator.java    From talkback with Apache License 2.0 5 votes vote down vote up
private boolean needSwapNodeOrder(
    AccessibilityNodeInfoCompat leftNode, AccessibilityNodeInfoCompat rightNode) {
  if (leftNode == null || rightNode == null) {
    return false;
  }

  Rect leftBounds = mBoundsCalculator.getBounds(leftNode);
  Rect rightBounds = mBoundsCalculator.getBounds(rightNode);

  // Sometimes the bounds compare() is overzealous, so swap the items only if the adjusted
  // (mBoundsCalculator) leftBounds > rightBounds but the original leftBounds < rightBounds,
  // i.e. the compare() method returns the existing ordering for the original bounds but
  // wants a swap for the adjusted bounds.
  // Simply, if compare() says that the original system ordering is wrong, then we cannot
  // trust its judgment in the adjusted bounds case.
  //
  // Example:
  // (1) Page scrolled to top  (2) Page scrolled to bottom.
  // +----------+              +----------+
  // | App bar  |              | App bar  |
  // +----------+              +----------+
  // | Item 1   |              | Item 2   |
  // | Item 2   |              | Item 3   |
  // | Item 3   |              | (spacer) |
  // +----------+              +----------+
  // Note: App bar overlays the top part of the list; the top, left, and right edges of the
  // list line up with the app bar. Assume that the spacer is not important for accessibility.
  // In this example, the traversal order for (1) is Item 1 -> Item 2 -> Item 3 -> App bar
  // but the traversal order for (2) gets reordered to App bar -> Item 2 -> Item 3.
  // So during auto-scrolling the app bar is actually excluded from the traversal order until
  // after the wrap-around.
  if (compare(leftBounds, rightBounds) > 0) {
    leftNode.getBoundsInScreen(mTempLeftBounds);
    rightNode.getBoundsInScreen(mTempRightBounds);
    return compare(mTempLeftBounds, mTempRightBounds) < 0;
  }

  return false;
}
 
Example 8
Source File: NodeCachedBoundsCalculator.java    From talkback with Apache License 2.0 5 votes vote down vote up
/**
 * If node is not supposed to be accessibility focused by TalkBack NodeBoundsCalculator calculates
 * useful bounds of focusable children. The method checks if the node uses its children useful
 * bounds or uses its own bounds
 */
public boolean usesChildrenBounds(AccessibilityNodeInfoCompat node) {
  if (node == null) {
    return false;
  }

  Rect bounds = getBounds(node);
  if (bounds == null) {
    return false;
  }

  node.getBoundsInScreen(mTempRect);
  return !mTempRect.equals(bounds);
}
 
Example 9
Source File: ProcessorMagnification.java    From talkback with Apache License 2.0 5 votes vote down vote up
@TargetApi(Build.VERSION_CODES.N)
private void recenterMagnifier(AccessibilityNodeInfoCompat node) {
  Rect sourceNodeBounds = new Rect();
  node.getBoundsInScreen(sourceNodeBounds);
  Region magRegion = magnificationController.getMagnificationRegion();
  Rect magBounds = magRegion.getBounds();
  float magScale = magnificationController.getScale();
  float halfMagWidth = (float) magBounds.width() / (2f * magScale); // use screen coordinates
  float halfMagHeight = (float) magBounds.height() / (2f * magScale);
  float margin = 5.0f;
  float newMagCenterY = sourceNodeBounds.top + halfMagHeight - margin;
  float newMagCenterX = -1;
  if (isLeftToRight(node)) {
    // Align upper left corner of sourceNode and magnifier
    newMagCenterX = sourceNodeBounds.left + halfMagWidth - margin;
  } else {
    // Align upper right corner of sourceNode and magnifier
    newMagCenterX = sourceNodeBounds.right - halfMagWidth + margin;
  }
  // Require that magnifier center is within magnifiable region
  float tolerance = 1.0f;
  newMagCenterX = Math.max(newMagCenterX, magBounds.left + tolerance);
  newMagCenterX = Math.min(newMagCenterX, magBounds.right - tolerance);
  newMagCenterY = Math.max(newMagCenterY, magBounds.top + tolerance);
  newMagCenterY = Math.min(newMagCenterY, magBounds.bottom - tolerance);
  magnificationController.setCenter(newMagCenterX, newMagCenterY, /* animate= */ true);
}
 
Example 10
Source File: ProcessorPermissionDialogs.java    From talkback with Apache License 2.0 5 votes vote down vote up
@Override
public void onAccessibilityEvent(AccessibilityEvent event, EventId eventId) {
  switch (event.getEventType()) {
    case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
      clearNode();
      AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event);
      AccessibilityNodeInfoCompat source = record.getSource();
      if (source != null) {
        if (ALLOW_BUTTON.equals(source.getViewIdResourceName())
            && dimScreenController.isDimmingEnabled()) {
          Rect sourceRect = new Rect();
          source.getBoundsInScreen(sourceRect);
          overlay.show(sourceRect);
          allowNode = source;
        } else {
          source.recycle();
        }
      }
      break;
    case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
    case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
      clearNode();
      break;
    default: // fall out
  }

  if (allowNode != null) {
    overlay.onAccessibilityEvent(event, eventId);
  }
}
 
Example 11
Source File: DirectionalTraversalStrategy.java    From talkback with Apache License 2.0 4 votes vote down vote up
/**
 * 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 12
Source File: DirectionalTraversalStrategy.java    From talkback with Apache License 2.0 4 votes vote down vote up
/**
 * Given a focus rectangle, returns another rectangle that is placed at the beginning of the row
 * or column of the focused object, depending on the direction in which we are navigating.
 *
 * <p>Example:
 *
 * <pre>
 *  +---------+
 *  |         | node=#
 * A|      #  | When direction=TraversalStrategy.SEARCH_FOCUS_RIGHT, then a rectangle A with
 *  |         |   same width and height as node gets returned.
 *  |         | When direction=TraversalStrategy.SEARCH_FOCUS_UP, then a rectangle B with same
 *  +---------+   width and height as node gets returned.
 *         B
 * </pre>
 */
private void getSearchStartRect(AccessibilityNodeInfoCompat node, int direction, Rect rect) {
  Rect focusedRect = new Rect();
  node.getBoundsInScreen(focusedRect);

  Rect rootBounds = new Rect();
  mRoot.getBoundsInScreen(rootBounds);

  switch (direction) {
    case TraversalStrategy.SEARCH_FOCUS_LEFT: // Start from right and move leftwards.
      rect.set(
          rootBounds.right,
          focusedRect.top,
          rootBounds.right + focusedRect.width(),
          focusedRect.bottom);
      break;
    case TraversalStrategy.SEARCH_FOCUS_RIGHT: // Start from left and move rightwards.
      rect.set(
          rootBounds.left - focusedRect.width(),
          focusedRect.top,
          rootBounds.left,
          focusedRect.bottom);
      break;
    case TraversalStrategy.SEARCH_FOCUS_UP: // Start from bottom and move upwards.
      rect.set(
          focusedRect.left,
          rootBounds.bottom,
          focusedRect.right,
          rootBounds.bottom + focusedRect.height());
      break;
    case TraversalStrategy.SEARCH_FOCUS_DOWN: // Start from top and move downwards.
      rect.set(
          focusedRect.left,
          rootBounds.top - focusedRect.height(),
          focusedRect.right,
          rootBounds.top);
      break;
    default:
      throw new IllegalArgumentException("direction must be a SearchDirection");
  }
}
 
Example 13
Source File: AccessibilityNodeInfoUtils.java    From talkback with Apache License 2.0 3 votes vote down vote up
/**
 * Returns {@code true} if the height and width of the {@link AccessibilityNodeInfoCompat}'s
 * visible bounds on the screen are greater than a specified number of minimum pixels. This can be
 * used to prune tiny elements or elements off the screen.
 *
 * <p>{@link AccessibilityNodeInfo#isVisibleToUser()} sometimes returns {@code true} for {@link
 * android.webkit.WebView} items off the screen, so this method allows us to better ignore WebView
 * content off the screen.
 *
 * @param node The node that will be checked for a minimum number of pixels on the screen
 * @return {@code true} if the node has at least the number of minimum visible pixels in both
 *     width and height on the screen
 */
public static boolean hasMinimumPixelsVisibleOnScreen(AccessibilityNodeInfoCompat node) {
  Rect visibleBounds = new Rect();
  node.getBoundsInScreen(visibleBounds);
  return ((Math.abs(visibleBounds.height()) >= MIN_VISIBLE_PIXELS)
      && (Math.abs(visibleBounds.width()) >= MIN_VISIBLE_PIXELS));
}