androidx.core.view.accessibility.AccessibilityNodeInfoCompat Java Examples

The following examples show how to use androidx.core.view.accessibility.AccessibilityNodeInfoCompat. 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: TreeDebug.java    From talkback with Apache License 2.0 6 votes vote down vote up
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 #2
Source File: TextEditingUtils.java    From talkback with Apache License 2.0 6 votes vote down vote up
private static boolean selectText(
    AccessibilityNodeInfoCompat nodeCompat, int startIndex, int endIndex) {
  Bundle args = new Bundle();
  args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, startIndex);
  args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, endIndex);
  boolean selected =
      PerformActionUtils.performAction(
          nodeCompat, AccessibilityNodeInfo.ACTION_SET_SELECTION, args, null);
  // Return true if we're setting the cursor to the end of the text. This is a workaround for
  //  where setting selection returns false when setting the index at the end of the
  // text. The correct action is still performed, but the method call sometimes returns false.
  // TODO: Update this for newer API versions when  is fixed.
  CharSequence text = getNonDefaultTextForNode(nodeCompat);
  int textEnd = (text == null) ? 0 : text.length();
  return ((startIndex == textEnd) && (endIndex == textEnd)) || selected;
}
 
Example #3
Source File: DirectionNavigationActor.java    From talkback with Apache License 2.0 6 votes vote down vote up
public boolean setGranularity(
    CursorGranularity granularity,
    AccessibilityNodeInfoCompat node,
    boolean isFromUser,
    EventId eventId) {
  if (node == null) {
    return false;
  }

  if (!cursorGranularityManager.setGranularityAt(node, granularity, eventId)) {
    return false;
  }

  granularityUpdated(granularity, isFromUser, eventId);
  return true;
}
 
Example #4
Source File: AccessibilityNodeInfoRef.java    From talkback with Apache License 2.0 6 votes vote down vote up
/** Traverses to the first child of this node if any, returning {@code true} on success. */
boolean firstChild() {
  if (mNode == null) {
    return false;
  }

  ReorderedChildrenIterator iterator = ReorderedChildrenIterator.createAscendingIterator(mNode);
  try {
    while (iterator.hasNext()) {
      AccessibilityNodeInfoCompat newNode = iterator.next();
      if (newNode == null) {
        return false;
      }
      if (AccessibilityNodeInfoUtils.isVisible(newNode)) {
        reset(newNode);
        return true;
      }
      newNode.recycle();
    }
  } finally {
    iterator.recycle();
  }
  return false;
}
 
Example #5
Source File: AccessibilityUtil.java    From screenshot-tests-for-android with Apache License 2.0 6 votes vote down vote up
/**
 * Returns whether a View has any children that are visible.
 *
 * @param view The {@link View} to evaluate
 * @return {@code true} if node has any visible children
 */
public static boolean hasVisibleChildren(View view) {
  if (!(view instanceof ViewGroup)) {
    return false;
  }

  ViewGroup viewGroup = (ViewGroup) view;
  int childCount = viewGroup.getChildCount();
  for (int i = 0; i < childCount; ++i) {
    AccessibilityNodeInfoCompat childNodeInfo = createNodeInfoFromView(viewGroup.getChildAt(i));
    if (childNodeInfo != null) {
      try {
        if (childNodeInfo.isVisibleToUser()) {
          return true;
        }
      } finally {
        childNodeInfo.recycle();
      }
    }
  }

  return false;
}
 
Example #6
Source File: FocusManagerInternal.java    From talkback with Apache License 2.0 6 votes vote down vote up
private FocusActionInfo updateFocusActionInfoIfNecessary(
    FocusActionInfo focusActionInfo, AccessibilityNodeInfoCompat node) {
  if (shouldMuteFeedbackForMicroGranularityNavigation(focusActionInfo, node)) {
    LogUtils.d(TAG, "Mute node feedback for micro granularity navigation.");
    focusActionInfo = new FocusActionInfo.Builder(focusActionInfo).forceMuteFeedback().build();
  }
  if (muteNextFocus) {
    if (focusActionInfo.sourceAction == FocusActionInfo.SCREEN_STATE_CHANGE) {
      FocusActionInfo modifiedFocusActionInfo =
          new FocusActionInfo.Builder(focusActionInfo).forceMuteFeedback().build();

      if (focusActionInfo != modifiedFocusActionInfo) {
        LogUtils.d(TAG, "FocusActionInfo modified.");
        muteNextFocus = false;
        return modifiedFocusActionInfo;
      }
    }
  }

  return focusActionInfo;
}
 
Example #7
Source File: WorkingTree.java    From talkback with Apache License 2.0 6 votes vote down vote up
/** Checks whether subTree is a descendant of this WorkingTree node. */
public boolean hasDescendant(@Nullable WorkingTree tree) {

  if (ancestorsHaveLoop()) {
    LogUtils.w(TAG, "Looped ancestors line");
    return false;
  }

  // For each ancestor of target descendant node...
  WorkingTree subTree = tree;
  while (subTree != null) {
    AccessibilityNodeInfoCompat node = subTree.getNode();

    // If ancestor is this working tree node... target is descendant of this node.
    if (mNode.equals(node)) {
      return true;
    }

    subTree = subTree.getParent();
  }

  return false;
}
 
Example #8
Source File: FocusProcessorForScreenStateChange.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * Returns the last focused node in {@code window} if it's still valid on screen, otherwise
 * returns focusable node with the same position.
 *
 * <p><strong>Note:</strong> Caller is responsible for recycling the returned node.
 */
private static AccessibilityNodeInfoCompat getNodeToRestoreFocus(
    AccessibilityNodeInfoCompat root, FocusActionRecord focusActionRecord) {
  AccessibilityNodeInfoCompat lastFocusedNode = focusActionRecord.getFocusedNode();
  if (lastFocusedNode.refresh()) {
    return lastFocusedNode;
  }
  AccessibilityNodeInfoUtils.recycleNodes(lastFocusedNode);
  if (root == null) {
    return null;
  }
  AccessibilityNodeInfoCompat nodeAtSamePosition =
      NodePathDescription.findNode(root, focusActionRecord.getNodePathDescription());
  if ((nodeAtSamePosition != null)
      && AccessibilityNodeInfoUtils.shouldFocusNode(nodeAtSamePosition)) {
    return nodeAtSamePosition;
  }
  AccessibilityNodeInfoUtils.recycleNodes(nodeAtSamePosition);
  return null;
}
 
Example #9
Source File: ActionBuildingUtils.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * Returns whether the given {@link AccessibilityActionCompat} is supported by the given {@link
 * SwitchAccessNodeCompat}. If the action is a movement action, return {@code true} if the given
 * node is editable and has nonempty text. If the action is a selection action, return {@code
 * true} if the given node is an EditText and has nonempty text. Otherwise, all other supported
 * actions are possible.
 *
 * <p>Note: methods #hasMultipleActions and #getActionsForNode should be updated if the logic of
 * this one changes.
 *
 * @param action The action to check
 * @param nodeCompat The node for which we will check whether it is possible to perform the
 *     provided action
 * @return {@code true} if the given {@link AccessibilityActionCompat} is supported by the given
 *     {@link SwitchAccessNodeCompat}
 */
public static boolean isActionSupportedByNode(
    AccessibilityActionCompat action, SwitchAccessNodeCompat nodeCompat) {
  if (isActionSupportedBySwitchAccess(action)) {
    boolean isMovementOption = isMovementAction(action.getId());
    boolean isSelection = (action.getId() == AccessibilityNodeInfoCompat.ACTION_SET_SELECTION);
    if (!isMovementOption && !isSelection) {
      return true;
    }

    boolean textIsEmpty = TextUtils.isEmpty(nodeCompat.getText());
    boolean canMoveInNode = isMovementOption && nodeCompat.isEditable() && !textIsEmpty;
    if (canMoveInNode) {
      return true;
    }

    boolean isSelectingNonEmptyEditTextNode =
        isSelection && (Role.getRole(nodeCompat) == Role.ROLE_EDIT_TEXT) && !textIsEmpty;
    if (isSelectingNonEmptyEditTextNode) {
      return true;
    }
  }

  return false;
}
 
Example #10
Source File: SpannableTraversalUtils.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * Return whether the tree description of node contains target spans. Caller should recycle {@code
 * node}.
 */
public static boolean hasTargetSpanInNodeTreeDescription(
    AccessibilityNodeInfoCompat node, Class<?> targetSpanClass) {
  if (node == null) {
    return false;
  }
  Set<AccessibilityNodeInfoCompat> visitedNode = new HashSet<>();
  try {
    return searchSpannableStringsInNodeTree(
        AccessibilityNodeInfoUtils.obtain(node), // Root node. Will be recycled in visitedNodes.
        visitedNode, // Visited nodes. Should be recycled.
        null, // Result list. No need to collect result here.
        targetSpanClass // Target span class
        );
  } finally {
    AccessibilityNodeInfoUtils.recycleNodes(visitedNode);
  }
}
 
Example #11
Source File: ScrollEventInterpreter.java    From talkback with Apache License 2.0 6 votes vote down vote up
/** Returns AutoScrollRecord if the {@code event} is resulted from cached auto-scroll action. */
private @Nullable AutoScrollRecord isFromAutoScrollAction(AccessibilityEvent event) {
  @Nullable
  AutoScrollRecord autoScrollRecord = actorState.getScrollerState().getAutoScrollRecord();
  if (autoScrollRecord == null) {
    return null;
  }

  // Note that both TYPE_VIEW_SCROLLED and TYPE_WINDOW_CONTENT_CHANGED events could result from
  // auto-scroll action. And a single scroll action can trigger multiple scroll events, we'll keep
  // the autoScrollRecord until next auto scroll happened and use the time diff to distinguish if
  // the current scroll is from the same scroll action.
  long timeDiff = event.getEventTime() - autoScrollRecord.autoScrolledTime;
  if ((timeDiff < 0L) || (timeDiff > SCROLL_TIMEOUT_MS)) {
    return null;
  }

  AccessibilityNodeInfoCompat node = null;
  try {
    node = AccessibilityNodeInfoUtils.toCompat(event.getSource());
    return autoScrollRecord.scrolledNodeMatches(node) ? autoScrollRecord : null;
  } finally {
    AccessibilityNodeInfoUtils.recycleNodes(node);
  }
}
 
Example #12
Source File: NodeCachedBoundsCalculator.java    From talkback with Apache License 2.0 6 votes vote down vote up
private Rect getBoundsInternal(AccessibilityNodeInfoCompat node) {
  if (node == null) {
    return EMPTY_RECT;
  }

  if (mCalculatingNodes.contains(node)) {
    LogUtils.w(TAG, "node tree loop detected while calculating node bounds");
    return EMPTY_RECT;
  }

  Rect bounds = mBoundsMap.get(node);
  if (bounds == null) {
    mCalculatingNodes.add(node);
    bounds = fetchBound(node);
    mBoundsMap.put(node, bounds);
    mCalculatingNodes.remove(node);
  }

  return bounds;
}
 
Example #13
Source File: FocusProcessorForScreenStateChange.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * Sets initial focus in the active window.
 *
 * @return {@code true} if successfully set accessibility focus on a node.
 */
private boolean assignFocusOnWindow(
    AccessibilityWindowInfo activeWindow, @Nullable CharSequence windowTitle, EventId eventId) {
  // TODO: Initial focus is set with linear navigation strategy, which is inconsistent
  // with directional navigation strategy on TV, and introduces some bugs. Enable it when we have
  // a solid solution for this issue.
  boolean enabled = !isTv;
  AccessibilityNodeInfoCompat root =
      AccessibilityNodeInfoUtils.toCompat(AccessibilityWindowInfoUtils.getRoot(activeWindow));
  try {
    return (enabled
            && restoreLastFocusedNode(
                root, activeWindow.getType(), activeWindow.getId(), windowTitle, eventId))
        || syncA11yFocusToInputFocusedEditText(root, eventId)
        || (enabled && focusOnFirstFocusableNonTitleNode(root, windowTitle, eventId));
  } finally {
    AccessibilityNodeInfoUtils.recycleNodes(root);
  }
}
 
Example #14
Source File: SearchScreenOverlay.java    From talkback with Apache License 2.0 6 votes vote down vote up
private void updateFocusedNodeAfterScrolled(AccessibilityNode scrolledNode, int scrollAction) {
  // The focused node searching strategy is copied from
  // FocusProcessorForLogicalNavigation.handleViewScrolledForScrollNavigationAction to align
  // behavior with scrolling by gesture.
  // TODO: Try to refactor the logic into a shared method that could be used by both
  // FocusProcessorForLogicalNavigation and SearchScreenOverlay
  if (scrolledNode == null) {
    return;
  }

  int searchDirection = TraversalStrategyUtils.convertScrollActionToSearchDirection(scrollAction);

  TraversalStrategy traversalStrategy = scrolledNode.getTraversalStrategy(searchDirection);

  Filter<AccessibilityNodeInfoCompat> nodeFilter =
      NavigationTarget.createNodeFilter(
          NavigationTarget.TARGET_DEFAULT, traversalStrategy.getSpeakingNodesCache());

  AccessibilityNode nodeToFocus =
      scrolledNode.findInitialFocusInNodeTree(traversalStrategy, searchDirection, nodeFilter);
  setInitialFocusedNode(nodeToFocus);
}
 
Example #15
Source File: RadialTimePickerView.java    From DateTimePicker with Apache License 2.0 6 votes vote down vote up
@Override
protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {
    node.setClassName(getClass().getName());
    node.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK);

    final int type = getTypeFromId(virtualViewId);
    final int value = getValueFromId(virtualViewId);
    final CharSequence description = getVirtualViewDescription(type, value);
    node.setContentDescription(description);

    getBoundsForVirtualView(virtualViewId, mTempRect);
    node.setBoundsInParent(mTempRect);

    final boolean selected = isVirtualViewSelected(type, value);
    node.setSelected(selected);

    final int nextId = getVirtualViewIdAfter(type, value);
    if (nextId != INVALID_ID) {
        node.setTraversalBefore(RadialTimePickerView.this, nextId);
    }
}
 
Example #16
Source File: Chip.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Override
protected void onPopulateNodeForHost(@NonNull AccessibilityNodeInfoCompat node) {
  node.setCheckable(isCheckable());
  node.setClickable(isClickable());
  if (isCheckable() || isClickable()) {
    node.setClassName(
        isCheckable()
            ? COMPOUND_BUTTON_ACCESSIBILITY_CLASS_NAME
            : BUTTON_ACCESSIBILITY_CLASS_NAME);
  } else {
    node.setClassName(GENERIC_VIEW_ACCESSIBILITY_CLASS_NAME);
  }
  CharSequence chipText = getText();
  if (VERSION.SDK_INT >= VERSION_CODES.M) {
    node.setText(chipText);
  } else {
    // Before M, TalkBack doesn't get the text from setText, so we have to set the content
    // description instead.
    node.setContentDescription(chipText);
  }
}
 
Example #17
Source File: Chip.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
@Override
protected void onPopulateNodeForVirtualView(
    int virtualViewId, @NonNull AccessibilityNodeInfoCompat node) {
  if (virtualViewId == CLOSE_ICON_VIRTUAL_ID) {
    CharSequence closeIconContentDescription = getCloseIconContentDescription();
    if (closeIconContentDescription != null) {
      node.setContentDescription(closeIconContentDescription);
    } else {
      CharSequence chipText = getText();
      node.setContentDescription(
          getContext()
              .getString(
                  R.string.mtrl_chip_close_icon_content_description,
                  !TextUtils.isEmpty(chipText) ? chipText : "")
              .trim());
    }
    node.setBoundsInParent(getCloseIconTouchBoundsInt());
    node.addAction(AccessibilityActionCompat.ACTION_CLICK);
    node.setEnabled(isEnabled());
  } else {
    node.setContentDescription("");
    node.setBoundsInParent(EMPTY_BOUNDS);
  }
}
 
Example #18
Source File: UndoRedoManager.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * Begins tracking the history of the view that corresponds to the specified {@link
 * AccessibilityNodeInfoCompat}. If the view is already being tracked, this method will
 * essentially clear the history for that view.
 *
 * @param nodeCompat the {@link AccessibilityNodeInfoCompat} corresponding the view to track the
 *     history for
 * @param timeline the {@link ActionTimeline} to use for the given {@link
 *     AccessibilityNodeInfoCompat}
 * @return the corresponding {@link ActionTimeline} that was created to track the view
 */
public synchronized ActionTimeline beginTrackingView(
    AccessibilityNodeInfoCompat nodeCompat,
    ActionTimeline timeline) {
  // If the node is editable, we're dealing with a text view
  if ((nodeCompat == null) || (timeline == null) || !isSupportedNode(nodeCompat)) {
    return null;
  }

  if (isBeingTracked(nodeCompat)) {
    stopTrackingView(nodeCompat);
  }

  // Add the compat and timeline into the map, and all the timeline into the min heap
  nodesToTimelines.put(nodeCompat, timeline);
  timelinesToNodes.put(timeline, nodeCompat);
  leastRecentlyUsedTimelines.add(timeline);

  clearUntilTimeLimit();
  clearUntilSizeLimit();
  return timeline;
}
 
Example #19
Source File: BottomSheetBehaviorTest.java    From material-components-android with Apache License 2.0 6 votes vote down vote up
private static void assertAccessibilityActions(
    BottomSheetBehavior<?> behavior, ViewGroup bottomSheet) {
  if (VERSION.SDK_INT >= 21) {
    int state = behavior.getState();
    boolean hasExpandAction =
        state == BottomSheetBehavior.STATE_COLLAPSED
            || state == BottomSheetBehavior.STATE_HALF_EXPANDED;
    boolean hasCollapseAction =
        state == BottomSheetBehavior.STATE_EXPANDED
            || state == BottomSheetBehavior.STATE_HALF_EXPANDED;
    boolean hasDismissAction = state != BottomSheetBehavior.STATE_HIDDEN && behavior.isHideable();
    assertThat(
        AccessibilityUtils.hasAction(bottomSheet, AccessibilityNodeInfoCompat.ACTION_COLLAPSE),
        equalTo(hasCollapseAction));
    assertThat(
        AccessibilityUtils.hasAction(bottomSheet, AccessibilityNodeInfoCompat.ACTION_EXPAND),
        equalTo(hasExpandAction));
    assertThat(
        AccessibilityUtils.hasAction(bottomSheet, AccessibilityNodeInfoCompat.ACTION_DISMISS),
        equalTo(hasDismissAction));
  }
}
 
Example #20
Source File: CustomLabelManager.java    From talkback with Apache License 2.0 6 votes vote down vote up
/**
 * Gets the text of a <code>node</code> by returning the content description (if available) or by
 * returning the text. Will use the specified <code>CustomLabelManager</code> as a fall back if
 * both are null.
 *
 * @param node The node.
 * @param labelManager The label manager.
 * @return The node text.
 */
public static @Nullable CharSequence getNodeText(
    AccessibilityNodeInfoCompat node, CustomLabelManager labelManager) {
  CharSequence text = AccessibilityNodeInfoUtils.getNodeText(node);
  if (!TextUtils.isEmpty(text)) {
    return text;
  }

  if (labelManager != null && labelManager.isInitialized()) {
    Label label = labelManager.getLabelForViewIdFromCache(node.getViewIdResourceName());
    if (label != null) {
      return label.getText();
    }
  }
  return null;
}
 
Example #21
Source File: Compositor.java    From talkback with Apache License 2.0 6 votes vote down vote up
/** Handles a standard AccessibilityEvent */
public void handleEvent(
    AccessibilityEvent event, @Nullable EventId eventId, EventInterpretation eventInterpreted) {

  final AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event);
  @Event int eventType = eventInterpreted.getEvent();

  // TODO
  // Allocate source node & delegate which must be recycled.
  AccessibilityNodeInfoCompat sourceNode = record.getSource();
  ParseTree.VariableDelegate delegate =
      mVariablesFactory.createLocalVariableDelegate(event, sourceNode, eventInterpreted);

  // Compute speech and speech flags.
  HandleEventOptions options =
      new HandleEventOptions().object(event).interpretation(eventInterpreted).source(sourceNode);
  handleEvent(eventType, eventId, delegate, options);
  AccessibilityNodeInfoUtils.recycleNodes(sourceNode);
}
 
Example #22
Source File: TextEditActor.java    From talkback with Apache License 2.0 6 votes vote down vote up
/** Executes and announces move cursor to start of edit-text. */
public boolean cursorToBeginning(
    AccessibilityNodeInfoCompat node, boolean stopSelecting, EventId eventId) {

  if (node == null || Role.getRole(node) != Role.ROLE_EDIT_TEXT) {
    return false;
  }

  // Stop selecting.
  if (stopSelecting) {
    pipeline.returnFeedback(eventId, Feedback.focusDirection(SELECTION_MODE_OFF));
  }

  // Move cursor.
  boolean result = moveCursor(node, 0, eventId);

  // Announce cursor movement.
  pipeline.returnFeedback(
      eventId,
      Feedback.speech(
          context.getString(R.string.notification_type_beginning_of_field), SPEAK_OPTIONS));

  return result;
}
 
Example #23
Source File: FocusProcessorForTapAndTouchExploration.java    From talkback with Apache License 2.0 6 votes vote down vote up
private boolean performClick(AccessibilityNodeInfoCompat node, EventId eventId) {
  // Performing a click on an EditText does not show the IME, so we need
  // to place input focus on it. If the IME was already connected and is
  // hidden, there is nothing we can do.
  if (Role.getRole(node) == Role.ROLE_EDIT_TEXT) {
    return pipeline.returnFeedback(eventId, Feedback.nodeAction(node, ACTION_FOCUS.getId()));
  }

  // If a user quickly touch explores in web content (event stream <
  // TAP_TIMEOUT_MS), we'll send an unintentional ACTION_CLICK. Switch
  // off clicking on web content for now.
  // TODO: Verify if it's a legacy feature.
  if (WebInterfaceUtils.supportsWebActions(node)) {
    return false;
  }

  return pipeline.returnFeedback(eventId, Feedback.nodeAction(node, ACTION_CLICK.getId()));
}
 
Example #24
Source File: RecyclerViewAccessibilityDelegate.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
    super.onInitializeAccessibilityNodeInfo(host, info);
    if (!mRecyclerViewDelegate.shouldIgnore()
            && mRecyclerViewDelegate.mRecyclerView.getLayoutManager() != null) {
        mRecyclerViewDelegate.mRecyclerView.getLayoutManager()
                .onInitializeAccessibilityNodeInfoForItem(host, info);
    }
}
 
Example #25
Source File: OrderedTraversalController.java    From talkback with Apache License 2.0 5 votes vote down vote up
/** Searches last node to be focused */
public @Nullable AccessibilityNodeInfoCompat findLast() {
  if (mTree == null) {
    return null;
  }

  return AccessibilityNodeInfoCompat.obtain(mTree.getRoot().getLastNode().getNode());
}
 
Example #26
Source File: AccessibilityServiceCompatUtils.java    From talkback with Apache License 2.0 5 votes vote down vote up
/** @return root node of the window that currently has accessibility focus */
public static @Nullable AccessibilityNodeInfoCompat getRootInAccessibilityFocusedWindow(
    AccessibilityService service) {
  if (service == null) {
    return null;
  }

  AccessibilityNodeInfo focusedRoot = null;
  List<AccessibilityWindowInfo> windows = getWindows(service);
  // Create window manager with fake value of isInRTL = false. This is okay here since
  // isInRTL will not change the result of getCurrentWindow.
  WindowManager manager = new WindowManager(false /* isInRTL */);
  manager.setWindows(windows);
  AccessibilityWindowInfo accessibilityFocusedWindow =
      manager.getCurrentWindow(false /* useInputFocus */);

  if (accessibilityFocusedWindow != null) {
    focusedRoot = AccessibilityWindowInfoUtils.getRoot(accessibilityFocusedWindow);
  }

  if (focusedRoot == null) {
    focusedRoot = service.getRootInActiveWindow();
  }

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

  return AccessibilityNodeInfoUtils.toCompat(focusedRoot);
}
 
Example #27
Source File: Feedback.java    From talkback with Apache License 2.0 5 votes vote down vote up
/** Copies node, caller retains ownership. */
public static Part.Builder selectionModeOn(AccessibilityNodeInfoCompat node) {
  return Part.builder()
      .setFocusDirection(
          FocusDirection.builder()
              .setAction(FocusDirection.Action.SELECTION_MODE_ON)
              .setSelectionNode(AccessibilityNodeInfoCompat.obtain(node))
              .build());
}
 
Example #28
Source File: VariablesFactory.java    From talkback with Apache License 2.0 5 votes vote down vote up
VariableDelegate createLocalVariableDelegate(
    @Nullable AccessibilityEvent event,
    @Nullable AccessibilityNodeInfoCompat node,
    @Nullable EventInterpretation interpretation) {
  VariableDelegate delegate = mGlobalVariables;
  if (event != null) {
    delegate =
        new EventVariables(mContext, delegate, event, event.getSource(), mUserPreferredLocale);
  }

  if (interpretation != null) {
    delegate =
        new InterpretationVariables(mContext, delegate, interpretation, mUserPreferredLocale);
  }

  // Node variables is constructed last. This ensures that child nodes it creates have access to
  // top level global variables.
  if (node != null) {
    delegate =
        new NodeVariables(
            mContext,
            mLabelManager,
            nodeMenuProvider,
            delegate,
            AccessibilityNodeInfoCompat.obtain(node),
            mUserPreferredLocale);
  }
  return delegate;
}
 
Example #29
Source File: AccessibilityNode.java    From talkback with Apache License 2.0 5 votes vote down vote up
/** Returns all descendants that match filter. Caller must recycle returned nodes. */
public List<AccessibilityNode> getMatchingDescendantsOrRoot(
    Filter<AccessibilityNodeInfoCompat> filter) {
  List<AccessibilityNodeInfoCompat> matchesCompat =
      AccessibilityNodeInfoUtils.getMatchingDescendantsOrRoot(getCompat(), filter);
  List<AccessibilityNode> matches = new ArrayList<>(matchesCompat.size());
  for (AccessibilityNodeInfoCompat matchCompat : matchesCompat) {
    matches.add(AccessibilityNode.takeOwnership(matchCompat));
  }
  return matches;
}
 
Example #30
Source File: OrderedTraversalController.java    From talkback with Apache License 2.0 5 votes vote down vote up
/**
 * Creates tree that reproduces AccessibilityNodeInfoCompat tree hierarchy
 *
 * @param rootNode root node that is starting point for tree reproduction
 * @param parent parent WorkingTree node for subtree that would be returned in this method
 * @param includeChildrenOfNodesWithWebActions whether to calculator order for nodes that support
 *     web actions. Although TalkBack uses the naviagation order specified by the nodes, Switch
 *     Access needs to know about all nodes at the time the tree is being created.
 * @return subtree that reproduces accessibility node hierarchy
 */
private @Nullable WorkingTree createWorkingTree(
    AccessibilityNodeInfoCompat rootNode,
    @Nullable WorkingTree parent,
    NodeCachedBoundsCalculator boundsCalculator,
    boolean includeChildrenOfNodesWithWebActions) {
  if (mNodeTreeMap.containsKey(rootNode)) {
    LogUtils.w(TAG, "creating node tree with looped nodes - break the loop edge");
    return null;
  }

  WorkingTree tree = new WorkingTree(rootNode, parent);
  mNodeTreeMap.put(rootNode, tree);

  // When we reach a node that supports web navigation, we traverse using the web navigation
  // actions, so we should not try to determine the ordering of its descendants.
  if (!includeChildrenOfNodesWithWebActions && WebInterfaceUtils.supportsWebActions(rootNode)) {
    return tree;
  }

  ReorderedChildrenIterator iterator =
      ReorderedChildrenIterator.createAscendingIterator(rootNode, boundsCalculator);
  while (iterator != null && iterator.hasNext()) {
    AccessibilityNodeInfoCompat child = iterator.next();
    WorkingTree childSubTree =
        createWorkingTree(child, tree, boundsCalculator, includeChildrenOfNodesWithWebActions);
    if (childSubTree != null) {
      tree.addChild(childSubTree);
    }
  }

  if (iterator != null) {
    iterator.recycle();
  }
  return tree;
}