| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.core.view.accessibility; |
| |
| import static android.view.View.NO_ID; |
| |
| import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX; |
| |
| import android.annotation.SuppressLint; |
| import android.graphics.Rect; |
| import android.graphics.Region; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.text.InputType; |
| import android.text.Spannable; |
| import android.text.SpannableString; |
| import android.text.Spanned; |
| import android.text.TextUtils; |
| import android.text.style.ClickableSpan; |
| import android.util.Log; |
| import android.util.SparseArray; |
| import android.view.View; |
| import android.view.accessibility.AccessibilityNodeInfo; |
| import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo; |
| |
| import androidx.annotation.IntRange; |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.annotation.RestrictTo; |
| import androidx.core.R; |
| import androidx.core.accessibilityservice.AccessibilityServiceInfoCompat; |
| import androidx.core.os.BuildCompat; |
| import androidx.core.view.ViewCompat; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.MoveAtGranularityArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.MoveHtmlArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.MoveWindowArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.ScrollToPositionArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.SetProgressArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.SetSelectionArguments; |
| import androidx.core.view.accessibility.AccessibilityViewCommand.SetTextArguments; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo} in a backwards |
| * compatible fashion. |
| */ |
| public class AccessibilityNodeInfoCompat { |
| |
| /** |
| * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}. |
| * Each action has a unique id and a label. |
| * <p> |
| * There are three categories of actions: |
| * <ul> |
| * <li><strong>Standard actions</strong> - These are actions that are reported and |
| * handled by the standard UI widgets in the platform. For each standard action |
| * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}. |
| * These actions will have {@code null} labels. |
| * </li> |
| * <li><strong>Custom actions action</strong> - These are actions that are reported |
| * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For |
| * example, an application may define a custom action for clearing the user history. |
| * </li> |
| * <li><strong>Overriden standard actions</strong> - These are actions that override |
| * standard actions to customize them. For example, an app may add a label to the |
| * standard {@link #ACTION_CLICK} action to indicate to the user that this action clears |
| * browsing history. |
| * </ul> |
| * </p> |
| * <p class="note"> |
| * <strong>Note:</strong> Views which support these actions should invoke |
| * {@link View#setImportantForAccessibility(int)} with |
| * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an |
| * {@link android.accessibilityservice.AccessibilityService} can discover the set of supported |
| * actions. |
| * </p> |
| */ |
| public static class AccessibilityActionCompat { |
| |
| private static final String TAG = "A11yActionCompat"; |
| |
| /** |
| * Action that gives input focus to the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_FOCUS = |
| new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_FOCUS, null); |
| |
| /** |
| * Action that clears input focus of the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_CLEAR_FOCUS = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS, null); |
| |
| /** |
| * Action that selects the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_SELECT = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_SELECT, null); |
| |
| /** |
| * Action that deselects the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_CLEAR_SELECTION = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION, null); |
| |
| /** |
| * Action that clicks on the node info. |
| */ |
| public static final AccessibilityActionCompat ACTION_CLICK = |
| new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_CLICK, null); |
| |
| /** |
| * Action that long clicks on the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_LONG_CLICK = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_LONG_CLICK, null); |
| |
| /** |
| * Action that gives accessibility focus to the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null); |
| |
| /** |
| * Action that clears accessibility focus of the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); |
| |
| /** |
| * Action that requests to go to the next entity in this node's text |
| * at a given movement granularity. For example, move to the next character, |
| * word, etc. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> |
| * <strong>Example:</strong> Move to the previous character and do not extend selection. |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER); |
| * arguments.putBoolean( |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); |
| * info.performAction( |
| * AccessibilityActionCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(), |
| * arguments); |
| * </code></pre></p> |
| * </p> |
| * |
| * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * |
| * @see AccessibilityNodeInfoCompat#setMovementGranularities(int) |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * @see AccessibilityNodeInfoCompat#getMovementGranularities() |
| * AccessibilityNodeInfoCompat.getMovementGranularities() |
| * |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_CHARACTER |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_WORD |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_WORD |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_LINE |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_LINE |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PARAGRAPH |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PARAGRAPH |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PAGE |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PAGE |
| */ |
| public static final AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null, |
| MoveAtGranularityArguments.class); |
| |
| /** |
| * Action that requests to go to the previous entity in this node's text |
| * at a given movement granularity. For example, move to the next character, |
| * word, etc. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> |
| * <strong>Example:</strong> Move to the next character and do not extend selection. |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER); |
| * arguments.putBoolean( |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); |
| * info.performAction( |
| * AccessibilityActionCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(), |
| * arguments); |
| * </code></pre></p> |
| * </p> |
| * |
| * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * |
| * @see AccessibilityNodeInfoCompat#setMovementGranularities(int) |
| * AccessibilityNodeInfoCompat.setMovementGranularities(int) |
| * @see AccessibilityNodeInfoCompat#getMovementGranularities() |
| * AccessibilityNodeInfoCompat.getMovementGranularities() |
| * |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_CHARACTER |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_WORD |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_WORD |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_LINE |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_LINE |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PARAGRAPH |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PARAGRAPH |
| * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PAGE |
| * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PAGE |
| */ |
| public static final AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null, |
| MoveAtGranularityArguments.class); |
| |
| /** |
| * Action to move to the next HTML element of a given type. For example, move |
| * to the BUTTON, INPUT, TABLE, etc. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_HTML_ELEMENT_STRING |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putString( |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); |
| * info.performAction( |
| * AccessibilityActionCompat.ACTION_NEXT_HTML_ELEMENT.getId(), arguments); |
| * </code></pre></p> |
| * </p> |
| */ |
| public static final AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_NEXT_HTML_ELEMENT, null, |
| MoveHtmlArguments.class); |
| |
| /** |
| * Action to move to the previous HTML element of a given type. For example, move |
| * to the BUTTON, INPUT, TABLE, etc. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_HTML_ELEMENT_STRING |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putString( |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); |
| * info.performAction( |
| * AccessibilityActionCompat.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments); |
| * </code></pre></p> |
| * </p> |
| */ |
| public static final AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_PREVIOUS_HTML_ELEMENT, null, |
| MoveHtmlArguments.class); |
| |
| /** |
| * Action to scroll the node content forward. |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_FORWARD = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null); |
| |
| /** |
| * Action to scroll the node content backward. |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_BACKWARD = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null); |
| |
| /** |
| * Action to copy the current selection to the clipboard. |
| */ |
| public static final AccessibilityActionCompat ACTION_COPY = |
| new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_COPY, null); |
| |
| /** |
| * Action to paste the current clipboard content. |
| */ |
| public static final AccessibilityActionCompat ACTION_PASTE = |
| new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_PASTE, null); |
| |
| /** |
| * Action to cut the current selection and place it to the clipboard. |
| */ |
| public static final AccessibilityActionCompat ACTION_CUT = |
| new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_CUT, null); |
| |
| /** |
| * Action to set the selection. Performing this action with no arguments |
| * clears the selection. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_START_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT}, |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_END_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, 1); |
| * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, 2); |
| * info.performAction(AccessibilityActionCompat.ACTION_SET_SELECTION.getId(), arguments); |
| * </code></pre></p> |
| * </p> |
| * |
| * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_START_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT |
| * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_END_INT |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT |
| */ |
| public static final AccessibilityActionCompat ACTION_SET_SELECTION = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_SET_SELECTION, null, |
| SetSelectionArguments.class); |
| |
| /** |
| * Action to expand an expandable node. |
| */ |
| public static final AccessibilityActionCompat ACTION_EXPAND = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_EXPAND, null); |
| |
| /** |
| * Action to collapse an expandable node. |
| */ |
| public static final AccessibilityActionCompat ACTION_COLLAPSE = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_COLLAPSE, null); |
| |
| /** |
| * Action to dismiss a dismissable node. |
| */ |
| public static final AccessibilityActionCompat ACTION_DISMISS = |
| new AccessibilityActionCompat( |
| AccessibilityNodeInfoCompat.ACTION_DISMISS, null); |
| |
| /** |
| * Action that sets the text of the node. Performing the action without argument, |
| * using <code> null</code> or empty {@link CharSequence} will clear the text. This |
| * action will also put the cursor at the end of text. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE |
| * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putCharSequence(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, |
| * "android"); |
| * info.performAction(AccessibilityActionCompat.ACTION_SET_TEXT.getId(), arguments); |
| * </code></pre></p> |
| */ |
| public static final AccessibilityActionCompat ACTION_SET_TEXT = |
| new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_SET_TEXT, null, |
| SetTextArguments.class); |
| |
| /** |
| * Action that requests the node make its bounding rectangle visible |
| * on the screen, scrolling if necessary just enough. |
| * |
| * @see View#requestRectangleOnScreen(Rect) |
| */ |
| public static final AccessibilityActionCompat ACTION_SHOW_ON_SCREEN = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN : null, |
| android.R.id.accessibilityActionShowOnScreen, null, null, null); |
| |
| /** |
| * Action that scrolls the node to make the specified collection |
| * position visible on screen. |
| * <p> |
| * <strong>Arguments:</strong> |
| * <ul> |
| * <li>{@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_ROW_INT}</li> |
| * <li>{@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_COLUMN_INT}</li> |
| * <ul> |
| * |
| * @see AccessibilityNodeInfoCompat#getCollectionInfo() |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_TO_POSITION = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_TO_POSITION |
| : null, android.R.id.accessibilityActionScrollToPosition, null, null, |
| ScrollToPositionArguments.class); |
| |
| /** |
| * Action to scroll the node content up. |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_UP = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP : null, |
| android.R.id.accessibilityActionScrollUp, null, null, null); |
| /** |
| * Action to scroll the node content left. |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_LEFT = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_LEFT : null, |
| android.R.id.accessibilityActionScrollLeft, null, null, null); |
| |
| /** |
| * Action to scroll the node content down. |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_DOWN = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN : null, |
| android.R.id.accessibilityActionScrollDown, null, null, null); |
| |
| /** |
| * Action to scroll the node content right. |
| */ |
| public static final AccessibilityActionCompat ACTION_SCROLL_RIGHT = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_RIGHT : null, |
| android.R.id.accessibilityActionScrollRight, null, null, null); |
| |
| /** |
| * Action to move to the page above. |
| */ |
| @NonNull |
| public static final AccessibilityActionCompat ACTION_PAGE_UP = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP : null, |
| android.R.id.accessibilityActionPageUp, null, null, null); |
| |
| /** |
| * Action to move to the page below. |
| */ |
| @NonNull |
| public static final AccessibilityActionCompat ACTION_PAGE_DOWN = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN : null, |
| android.R.id.accessibilityActionPageDown, null, null, null); |
| |
| /** |
| * Action to move to the page left. |
| */ |
| @NonNull |
| public static final AccessibilityActionCompat ACTION_PAGE_LEFT = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT : null, |
| android.R.id.accessibilityActionPageLeft, null, null, null); |
| |
| /** |
| * Action to move to the page right. |
| */ |
| @NonNull |
| public static final AccessibilityActionCompat ACTION_PAGE_RIGHT = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT : null, |
| android.R.id.accessibilityActionPageRight, null, null, null); |
| |
| /** |
| * Action that context clicks the node. |
| */ |
| public static final AccessibilityActionCompat ACTION_CONTEXT_CLICK = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK : null, |
| android.R.id.accessibilityActionContextClick, null, null, null); |
| |
| /** |
| * Action that sets progress between {@link RangeInfoCompat#getMin() RangeInfo.getMin()} and |
| * {@link RangeInfoCompat#getMax() RangeInfo.getMax()}. It should use the same value type as |
| * {@link RangeInfoCompat#getType() RangeInfo.getType()} |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_PROGRESS_VALUE} |
| * |
| * @see RangeInfoCompat |
| */ |
| public static final AccessibilityActionCompat ACTION_SET_PROGRESS = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 24 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS : null, |
| android.R.id.accessibilityActionSetProgress, null, null, |
| SetProgressArguments.class); |
| |
| /** |
| * Action to move a window to a new location. |
| * <p> |
| * <strong>Arguments:</strong> |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_X} |
| * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_Y} |
| */ |
| public static final AccessibilityActionCompat ACTION_MOVE_WINDOW = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 26 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_MOVE_WINDOW : null, |
| android.R.id.accessibilityActionMoveWindow, null, null, |
| MoveWindowArguments.class); |
| |
| /** |
| * Action to show a tooltip. |
| */ |
| public static final AccessibilityActionCompat ACTION_SHOW_TOOLTIP = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 28 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP : null, |
| android.R.id.accessibilityActionShowTooltip, null, null, null); |
| |
| /** |
| * Action to hide a tooltip. A node should expose this action only for views that are |
| * currently showing a tooltip. |
| */ |
| public static final AccessibilityActionCompat ACTION_HIDE_TOOLTIP = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 28 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP : null, |
| android.R.id.accessibilityActionHideTooltip, null, null, null); |
| |
| /** |
| * Action that presses and holds a node. |
| * <p> |
| * This action is for nodes that have distinct behavior that depends on how long a press is |
| * held. Nodes having a single action for long press should use {@link #ACTION_LONG_CLICK} |
| * instead of this action, and nodes should not expose both actions. |
| * <p> |
| * When calling {@code performAction(ACTION_PRESS_AND_HOLD, bundle}, use |
| * {@link #ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT} to specify how long the |
| * node is pressed. The first time an accessibility service performs ACTION_PRES_AND_HOLD |
| * on a node, it must specify 0 as ACTION_ARGUMENT_PRESS_AND_HOLD, so the application is |
| * notified that the held state has started. To ensure reasonable behavior, the values |
| * must be increased incrementally and may not exceed 10,000. UIs requested |
| * to hold for times outside of this range should ignore the action. |
| * <p> |
| * The total time the element is held could be specified by an accessibility user up-front, |
| * or may depend on what happens on the UI as the user continues to request the hold. |
| * <p> |
| * <strong>Note:</strong> The time between dispatching the action and it arriving in the |
| * UI process is not guaranteed. It is possible on a busy system for the time to expire |
| * unexpectedly. For the case of holding down a key for a repeating action, a delayed |
| * arrival should be benign. Please do not use this sort of action in cases where such |
| * delays will lead to unexpected UI behavior. |
| * <p> |
| */ |
| @NonNull public static final AccessibilityActionCompat ACTION_PRESS_AND_HOLD = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 30 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PRESS_AND_HOLD : null, |
| android.R.id.accessibilityActionPressAndHold, null, null, null); |
| |
| /** |
| * Action to send an ime actionId which is from |
| * {@link android.view.inputmethod.EditorInfo#actionId}. This ime actionId sets by |
| * {@link android.widget.TextView#setImeActionLabel(CharSequence, int)}, or it would be |
| * {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED} if no specific |
| * actionId has set. A node should expose this action only for views that are currently |
| * with input focus and editable. |
| */ |
| @NonNull public static final AccessibilityActionCompat ACTION_IME_ENTER = |
| new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 30 |
| ? AccessibilityNodeInfo.AccessibilityAction.ACTION_IME_ENTER : null, |
| android.R.id.accessibilityActionImeEnter, null, null, null); |
| |
| final Object mAction; |
| private final int mId; |
| private final Class<? extends CommandArguments> mViewCommandArgumentClass; |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| protected final AccessibilityViewCommand mCommand; |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param actionId The action id. |
| * @param label The action label. |
| */ |
| public AccessibilityActionCompat(int actionId, CharSequence label) { |
| this(null, actionId, label, null, null); |
| } |
| |
| /** |
| * Creates a new instance. |
| * |
| * @param actionId The action id. |
| * @param label The action label. |
| * @param command The command performed when the service requests the action |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public AccessibilityActionCompat(int actionId, CharSequence label, |
| AccessibilityViewCommand command) { |
| this(null, actionId, label, command, null); |
| } |
| |
| AccessibilityActionCompat(Object action) { |
| this(action, 0, null, null, null); |
| } |
| |
| private AccessibilityActionCompat(int actionId, CharSequence label, |
| Class<? extends CommandArguments> viewCommandArgumentClass) { |
| this(null, actionId, label, null, viewCommandArgumentClass); |
| } |
| |
| AccessibilityActionCompat(Object action, int id, CharSequence label, |
| AccessibilityViewCommand command, |
| Class<? extends CommandArguments> viewCommandArgumentClass) { |
| mId = id; |
| mCommand = command; |
| if (Build.VERSION.SDK_INT >= 21 && action == null) { |
| mAction = new AccessibilityNodeInfo.AccessibilityAction(id, label); |
| } else { |
| mAction = action; |
| } |
| mViewCommandArgumentClass = viewCommandArgumentClass; |
| } |
| |
| /** |
| * Gets the id for this action. |
| * |
| * @return The action id. |
| */ |
| public int getId() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getId(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the label for this action. Its purpose is to describe the |
| * action to user. |
| * |
| * @return The label. |
| */ |
| public CharSequence getLabel() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getLabel(); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Performs the action. |
| * @return If the action was handled. |
| * @param view View to act upon. |
| * @param arguments Optional action arguments. |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public boolean perform(View view, Bundle arguments) { |
| if (mCommand != null) { |
| CommandArguments viewCommandArgument = null; |
| if (mViewCommandArgumentClass != null) { |
| try { |
| viewCommandArgument = |
| mViewCommandArgumentClass.getDeclaredConstructor().newInstance(); |
| viewCommandArgument.setBundle(arguments); |
| } catch (Exception e) { |
| final String className = mViewCommandArgumentClass == null |
| ? "null" : mViewCommandArgumentClass.getName(); |
| Log.e(TAG, "Failed to execute command with argument class " |
| + "ViewCommandArgument: " + className, e); |
| } |
| } |
| return mCommand.perform(view, viewCommandArgument); |
| } |
| return false; |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public AccessibilityActionCompat createReplacementAction(CharSequence label, |
| AccessibilityViewCommand command) { |
| return new AccessibilityActionCompat(null, mId, label, command, |
| mViewCommandArgumentClass); |
| } |
| |
| @Override |
| public int hashCode() { |
| return mAction != null ? mAction.hashCode() : 0; |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| if (obj == null) { |
| return false; |
| } |
| if (!(obj instanceof AccessibilityNodeInfoCompat.AccessibilityActionCompat)) { |
| return false; |
| } |
| AccessibilityNodeInfoCompat.AccessibilityActionCompat other = |
| (AccessibilityNodeInfoCompat.AccessibilityActionCompat) obj; |
| if (mAction == null) { |
| if (other.mAction != null) { |
| return false; |
| } |
| } else if (!mAction.equals(other.mAction)) { |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| /** |
| * Class with information if a node is a collection. |
| * <p> |
| * A collection of items has rows and columns and may be hierarchical. |
| * For example, a horizontal list is a collection with one column, as |
| * many rows as the list items, and is not hierarchical; A table is a |
| * collection with several rows, several columns, and is not hierarchical; |
| * A vertical tree is a hierarchical collection with one column and |
| * as many rows as the first level children. |
| * </p> |
| */ |
| public static class CollectionInfoCompat { |
| /** Selection mode where items are not selectable. */ |
| public static final int SELECTION_MODE_NONE = 0; |
| |
| /** Selection mode where a single item may be selected. */ |
| public static final int SELECTION_MODE_SINGLE = 1; |
| |
| /** Selection mode where multiple items may be selected. */ |
| public static final int SELECTION_MODE_MULTIPLE = 2; |
| |
| final Object mInfo; |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one. |
| * |
| * @param rowCount The number of rows. |
| * @param columnCount The number of columns. |
| * @param hierarchical Whether the collection is hierarchical. |
| * @param selectionMode The collection's selection mode, one of: |
| * <ul> |
| * <li>{@link #SELECTION_MODE_NONE} |
| * <li>{@link #SELECTION_MODE_SINGLE} |
| * <li>{@link #SELECTION_MODE_MULTIPLE} |
| * </ul> |
| * |
| * @return An instance. |
| */ |
| public static CollectionInfoCompat obtain(int rowCount, int columnCount, |
| boolean hierarchical, int selectionMode) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain( |
| rowCount, columnCount, hierarchical, selectionMode)); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain( |
| rowCount, columnCount, hierarchical)); |
| } else { |
| return new CollectionInfoCompat(null); |
| } |
| } |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one. |
| * |
| * @param rowCount The number of rows, or -1 if count is unknown. |
| * @param columnCount The number of columns , or -1 if count is unknown. |
| * @param hierarchical Whether the collection is hierarchical. |
| * |
| * @return An instance. |
| */ |
| public static CollectionInfoCompat obtain(int rowCount, int columnCount, |
| boolean hierarchical) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain( |
| rowCount, columnCount, hierarchical)); |
| } else { |
| return new CollectionInfoCompat(null); |
| } |
| } |
| |
| CollectionInfoCompat(Object info) { |
| mInfo = info; |
| } |
| |
| /** |
| * Gets the number of columns. |
| * |
| * @return The column count, or -1 if count is unknown. |
| */ |
| public int getColumnCount() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getColumnCount(); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * Gets the number of rows. |
| * |
| * @return The row count, or -1 if count is unknown. |
| */ |
| public int getRowCount() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getRowCount(); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * Gets if the collection is a hierarchically ordered. |
| * |
| * @return Whether the collection is hierarchical. |
| */ |
| public boolean isHierarchical() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionInfo) mInfo).isHierarchical(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Gets the collection's selection mode. |
| * |
| * @return The collection's selection mode, one of: |
| * <ul> |
| * <li>{@link #SELECTION_MODE_NONE} |
| * <li>{@link #SELECTION_MODE_SINGLE} |
| * <li>{@link #SELECTION_MODE_MULTIPLE} |
| * </ul> |
| */ |
| public int getSelectionMode() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getSelectionMode(); |
| } else { |
| return 0; |
| } |
| } |
| } |
| |
| /** |
| * Class with information if a node is a collection item. |
| * <p> |
| * A collection item is contained in a collection, it starts at |
| * a given row and column in the collection, and spans one or |
| * more rows and columns. For example, a header of two related |
| * table columns starts at the first row and the first column, |
| * spans one row and two columns. |
| * </p> |
| */ |
| public static class CollectionItemInfoCompat { |
| |
| final Object mInfo; |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one. |
| * |
| * @param rowIndex The row index at which the item is located. |
| * @param rowSpan The number of rows the item spans. |
| * @param columnIndex The column index at which the item is located. |
| * @param columnSpan The number of columns the item spans. |
| * @param heading Whether the item is a heading. This should be set to false and the newer |
| * {@link AccessibilityNodeInfoCompat#setHeading(boolean)} used to identify |
| * headings. |
| * @param selected Whether the item is selected. |
| * @return An instance. |
| */ |
| public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan, |
| int columnIndex, int columnSpan, boolean heading, boolean selected) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain( |
| rowIndex, rowSpan, columnIndex, columnSpan, heading, selected)); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain( |
| rowIndex, rowSpan, columnIndex, columnSpan, heading)); |
| } else { |
| return new CollectionItemInfoCompat(null); |
| } |
| } |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one. |
| * |
| * @param rowIndex The row index at which the item is located. |
| * @param rowSpan The number of rows the item spans. |
| * @param columnIndex The column index at which the item is located. |
| * @param columnSpan The number of columns the item spans. |
| * @param heading Whether the item is a heading. This should be set to false and the newer |
| * {@link AccessibilityNodeInfoCompat#setHeading(boolean)} used to identify |
| * headings. |
| * @return An instance. |
| */ |
| public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan, |
| int columnIndex, int columnSpan, boolean heading) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain( |
| rowIndex, rowSpan, columnIndex, columnSpan, heading)); |
| } else { |
| return new CollectionItemInfoCompat(null); |
| } |
| } |
| |
| CollectionItemInfoCompat(Object info) { |
| mInfo = info; |
| } |
| |
| /** |
| * Gets the column index at which the item is located. |
| * |
| * @return The column index. |
| */ |
| public int getColumnIndex() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnIndex(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the number of columns the item spans. |
| * |
| * @return The column span. |
| */ |
| public int getColumnSpan() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnSpan(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the row index at which the item is located. |
| * |
| * @return The row index. |
| */ |
| public int getRowIndex() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowIndex(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the number of rows the item spans. |
| * |
| * @return The row span. |
| */ |
| public int getRowSpan() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowSpan(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets if the collection item is a heading. For example, section |
| * heading, table header, etc. |
| * |
| * @return If the item is a heading. |
| * @deprecated Use {@link AccessibilityNodeInfoCompat#isHeading()} |
| */ |
| @SuppressWarnings("deprecation") |
| @Deprecated |
| public boolean isHeading() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isHeading(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Gets if the collection item is selected. |
| * |
| * @return If the item is selected. |
| */ |
| public boolean isSelected() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isSelected(); |
| } else { |
| return false; |
| } |
| } |
| } |
| |
| /** |
| * Class with information if a node is a range. |
| */ |
| public static class RangeInfoCompat { |
| /** Range type: integer. */ |
| public static final int RANGE_TYPE_INT = 0; |
| /** Range type: float. */ |
| public static final int RANGE_TYPE_FLOAT = 1; |
| /** Range type: percent with values from zero to one.*/ |
| public static final int RANGE_TYPE_PERCENT = 2; |
| |
| /** |
| * Obtains a cached instance if such is available otherwise a new one. |
| * |
| * @param type The type of the range. |
| * @param min The min value. |
| * @param max The max value. |
| * @param current The current value. |
| * @return The instance |
| */ |
| public static RangeInfoCompat obtain(int type, float min, float max, float current) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return new RangeInfoCompat( |
| AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current)); |
| } else { |
| return new RangeInfoCompat(null); |
| } |
| } |
| |
| final Object mInfo; |
| |
| RangeInfoCompat(Object info) { |
| mInfo = info; |
| } |
| |
| /** |
| * Gets the current value. |
| * |
| * @return The current value. |
| */ |
| public float getCurrent() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.RangeInfo) mInfo).getCurrent(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the max value. |
| * |
| * @return The max value. |
| */ |
| public float getMax() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMax(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the min value. |
| * |
| * @return The min value. |
| */ |
| public float getMin() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMin(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Gets the range type. |
| * |
| * @return The range type. |
| * |
| * @see #RANGE_TYPE_INT |
| * @see #RANGE_TYPE_FLOAT |
| * @see #RANGE_TYPE_PERCENT |
| */ |
| public int getType() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return ((AccessibilityNodeInfo.RangeInfo) mInfo).getType(); |
| } else { |
| return RANGE_TYPE_INT; |
| } |
| } |
| } |
| |
| /** |
| * Class with information of touch delegated views and regions. |
| */ |
| public static final class TouchDelegateInfoCompat { |
| final TouchDelegateInfo mInfo; |
| |
| /** |
| * Create a new instance of {@link TouchDelegateInfoCompat}. |
| * |
| * @param targetMap A map from regions (in view coordinates) to delegated views. |
| */ |
| public TouchDelegateInfoCompat(@NonNull Map<Region, View> targetMap) { |
| if (Build.VERSION.SDK_INT >= 29) { |
| mInfo = new TouchDelegateInfo(targetMap); |
| } else { |
| mInfo = null; |
| } |
| } |
| |
| TouchDelegateInfoCompat(@NonNull TouchDelegateInfo info) { |
| mInfo = info; |
| } |
| |
| /** |
| * Returns the number of touch delegate target region. |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 29: Always returns {@code 0}</li> |
| * </ul> |
| * |
| * @return Number of touch delegate target region. |
| */ |
| public @IntRange(from = 0) int getRegionCount() { |
| if (Build.VERSION.SDK_INT >= 29) { |
| return mInfo.getRegionCount(); |
| } |
| return 0; |
| } |
| |
| /** |
| * Return the {@link Region} at the given index. |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 29: Always returns {@code null}</li> |
| * </ul> |
| * |
| * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1. |
| * @return Returns the {@link Region} stored at the given index. |
| */ |
| @Nullable |
| public Region getRegionAt(@IntRange(from = 0) int index) { |
| if (Build.VERSION.SDK_INT >= 29) { |
| return mInfo.getRegionAt(index); |
| } |
| return null; |
| } |
| |
| /** |
| * Return the target {@link AccessibilityNodeInfoCompat} for the given {@link Region}. |
| * <p> |
| * <strong>Note:</strong> This api can only be called from |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * </p> |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link AccessibilityNodeInfo#recycle()} |
| * to avoid creating of multiple instances. |
| * </p> |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 29: Always returns {@code null}</li> |
| * </ul> |
| * |
| * @param region The region retrieved from {@link #getRegionAt(int)}. |
| * @return The target node associates with the given region. |
| */ |
| @Nullable |
| public AccessibilityNodeInfoCompat getTargetForRegion(@NonNull Region region) { |
| if (Build.VERSION.SDK_INT >= 29) { |
| AccessibilityNodeInfo info = mInfo.getTargetForRegion(region); |
| if (info != null) { |
| return AccessibilityNodeInfoCompat.wrap(info); |
| } |
| } |
| return null; |
| } |
| } |
| |
| private static final String ROLE_DESCRIPTION_KEY = |
| "AccessibilityNodeInfo.roleDescription"; |
| |
| private static final String PANE_TITLE_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.PANE_TITLE_KEY"; |
| |
| private static final String TOOLTIP_TEXT_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.TOOLTIP_TEXT_KEY"; |
| |
| private static final String HINT_TEXT_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.HINT_TEXT_KEY"; |
| |
| private static final String BOOLEAN_PROPERTY_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.BOOLEAN_PROPERTY_KEY"; |
| |
| private static final String SPANS_ID_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_ID_KEY"; |
| |
| private static final String SPANS_START_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_START_KEY"; |
| |
| private static final String SPANS_END_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_END_KEY"; |
| |
| private static final String SPANS_FLAGS_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_FLAGS_KEY"; |
| |
| private static final String SPANS_ACTION_ID_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_ACTION_ID_KEY"; |
| |
| private static final String STATE_DESCRIPTION_KEY = |
| "androidx.view.accessibility.AccessibilityNodeInfoCompat.STATE_DESCRIPTION_KEY"; |
| |
| // These don't line up with the internal framework constants, since they are independent |
| // and we might as well get all 32 bits of utility here. |
| private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x00000001; |
| private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x00000002; |
| private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x00000004; |
| private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 0x00000008; |
| |
| private final AccessibilityNodeInfo mInfo; |
| |
| /** |
| * androidx.customview.widget.ExploreByTouchHelper.HOST_ID = -1; |
| * |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public int mParentVirtualDescendantId = NO_ID; |
| |
| private int mVirtualDescendantId = NO_ID; |
| |
| // Actions introduced in IceCreamSandwich |
| |
| /** |
| * Action that focuses the node. |
| */ |
| public static final int ACTION_FOCUS = 0x00000001; |
| |
| /** |
| * Action that unfocuses the node. |
| */ |
| public static final int ACTION_CLEAR_FOCUS = 0x00000002; |
| |
| /** |
| * Action that selects the node. |
| */ |
| public static final int ACTION_SELECT = 0x00000004; |
| |
| /** |
| * Action that unselects the node. |
| */ |
| public static final int ACTION_CLEAR_SELECTION = 0x00000008; |
| |
| /** |
| * Action that clicks on the node info. |
| */ |
| public static final int ACTION_CLICK = 0x00000010; |
| |
| /** |
| * Action that long clicks on the node. |
| */ |
| public static final int ACTION_LONG_CLICK = 0x00000020; |
| |
| // Actions introduced in JellyBean |
| |
| /** |
| * Action that gives accessibility focus to the node. |
| */ |
| public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040; |
| |
| /** |
| * Action that clears accessibility focus of the node. |
| */ |
| public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080; |
| |
| /** |
| * Action that requests to go to the next entity in this node's text |
| * at a given movement granularity. For example, move to the next character, |
| * word, etc. |
| * <p> |
| * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, |
| * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> |
| * <strong>Example:</strong> Move to the previous character and do not extend selection. |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, |
| * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); |
| * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, |
| * false); |
| * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments); |
| * </code></pre></p> |
| * </p> |
| * |
| * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * |
| * @see #setMovementGranularities(int) |
| * @see #getMovementGranularities() |
| * |
| * @see #MOVEMENT_GRANULARITY_CHARACTER |
| * @see #MOVEMENT_GRANULARITY_WORD |
| * @see #MOVEMENT_GRANULARITY_LINE |
| * @see #MOVEMENT_GRANULARITY_PARAGRAPH |
| * @see #MOVEMENT_GRANULARITY_PAGE |
| */ |
| public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100; |
| |
| /** |
| * Action that requests to go to the previous entity in this node's text |
| * at a given movement granularity. For example, move to the next character, |
| * word, etc. |
| * <p> |
| * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, |
| * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> |
| * <strong>Example:</strong> Move to the next character and do not extend selection. |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, |
| * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); |
| * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, |
| * false); |
| * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, |
| * arguments); |
| * </code></pre></p> |
| * </p> |
| * |
| * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT |
| * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN |
| * |
| * @see #setMovementGranularities(int) |
| * @see #getMovementGranularities() |
| * |
| * @see #MOVEMENT_GRANULARITY_CHARACTER |
| * @see #MOVEMENT_GRANULARITY_WORD |
| * @see #MOVEMENT_GRANULARITY_LINE |
| * @see #MOVEMENT_GRANULARITY_PARAGRAPH |
| * @see #MOVEMENT_GRANULARITY_PAGE |
| */ |
| public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200; |
| |
| /** |
| * Action to move to the next HTML element of a given type. For example, move |
| * to the BUTTON, INPUT, TABLE, etc. |
| * <p> |
| * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); |
| * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments); |
| * </code></pre></p> |
| * </p> |
| */ |
| public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400; |
| |
| /** |
| * Action to move to the previous HTML element of a given type. For example, move |
| * to the BUTTON, INPUT, TABLE, etc. |
| * <p> |
| * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); |
| * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments); |
| * </code></pre></p> |
| * </p> |
| */ |
| public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800; |
| |
| /** |
| * Action to scroll the node content forward. |
| */ |
| public static final int ACTION_SCROLL_FORWARD = 0x00001000; |
| |
| /** |
| * Action to scroll the node content backward. |
| */ |
| public static final int ACTION_SCROLL_BACKWARD = 0x00002000; |
| |
| // Actions introduced in JellyBeanMr2 |
| |
| /** |
| * Action to copy the current selection to the clipboard. |
| */ |
| public static final int ACTION_COPY = 0x00004000; |
| |
| /** |
| * Action to paste the current clipboard content. |
| */ |
| public static final int ACTION_PASTE = 0x00008000; |
| |
| /** |
| * Action to cut the current selection and place it to the clipboard. |
| */ |
| public static final int ACTION_CUT = 0x00010000; |
| |
| /** |
| * Action to set the selection. Performing this action with no arguments |
| * clears the selection. |
| * <p> |
| * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT}, |
| * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1); |
| * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2); |
| * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments); |
| * </code></pre></p> |
| * </p> |
| * |
| * @see #ACTION_ARGUMENT_SELECTION_START_INT |
| * @see #ACTION_ARGUMENT_SELECTION_END_INT |
| */ |
| public static final int ACTION_SET_SELECTION = 0x00020000; |
| |
| /** |
| * Action to expand an expandable node. |
| */ |
| public static final int ACTION_EXPAND = 0x00040000; |
| |
| /** |
| * Action to collapse an expandable node. |
| */ |
| public static final int ACTION_COLLAPSE = 0x00080000; |
| |
| /** |
| * Action to dismiss a dismissable node. |
| */ |
| public static final int ACTION_DISMISS = 0x00100000; |
| |
| /** |
| * Action that sets the text of the node. Performing the action without argument, using <code> |
| * null</code> or empty {@link CharSequence} will clear the text. This action will also put the |
| * cursor at the end of text. |
| * <p> |
| * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> |
| * <strong>Example:</strong> |
| * <code><pre><p> |
| * Bundle arguments = new Bundle(); |
| * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, |
| * "android"); |
| * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); |
| * </code></pre></p> |
| */ |
| public static final int ACTION_SET_TEXT = 0x00200000; |
| |
| // Action arguments |
| |
| /** |
| * Argument for which movement granularity to be used when traversing the node text. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY}, |
| * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY} |
| * </p> |
| */ |
| public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = |
| "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; |
| |
| /** |
| * Argument for which HTML element to get moving to the next/previous HTML element. |
| * <p> |
| * <strong>Type:</strong> String<br> |
| * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT}, |
| * {@link #ACTION_PREVIOUS_HTML_ELEMENT} |
| * </p> |
| */ |
| public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = |
| "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; |
| |
| /** |
| * Argument for whether when moving at granularity to extend the selection |
| * or to move it otherwise. |
| * <p> |
| * <strong>Type:</strong> boolean<br> |
| * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY}, |
| * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY} |
| * </p> |
| * |
| * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY |
| * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY |
| */ |
| public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = |
| "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN"; |
| |
| /** |
| * Argument for specifying the selection start. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION} |
| * </p> |
| * |
| * @see #ACTION_SET_SELECTION |
| */ |
| public static final String ACTION_ARGUMENT_SELECTION_START_INT = |
| "ACTION_ARGUMENT_SELECTION_START_INT"; |
| |
| /** |
| * Argument for specifying the selection end. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION} |
| * </p> |
| * |
| * @see #ACTION_SET_SELECTION |
| */ |
| public static final String ACTION_ARGUMENT_SELECTION_END_INT = |
| "ACTION_ARGUMENT_SELECTION_END_INT"; |
| |
| /** |
| * Argument for specifying the text content to set |
| * <p> |
| * <strong>Type:</strong> CharSequence<br> |
| * <strong>Actions:</strong> {@link #ACTION_SET_TEXT} |
| * </p> |
| * |
| * @see #ACTION_SET_TEXT |
| */ |
| public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = |
| "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE"; |
| |
| /** |
| * Argument for specifying the collection row to make visible on screen. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> |
| * <ul> |
| * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li> |
| * </ul> |
| * |
| * @see AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION |
| */ |
| public static final String ACTION_ARGUMENT_ROW_INT = |
| "android.view.accessibility.action.ARGUMENT_ROW_INT"; |
| |
| /** |
| * Argument for specifying the collection column to make visible on screen. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> |
| * <ul> |
| * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li> |
| * </ul> |
| * |
| * @see AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION |
| */ |
| public static final String ACTION_ARGUMENT_COLUMN_INT = |
| "android.view.accessibility.action.ARGUMENT_COLUMN_INT"; |
| |
| /** |
| * Argument for specifying the progress value to set. |
| * <p> |
| * <strong>Type:</strong> float<br> |
| * <strong>Actions:</strong> |
| * <ul> |
| * <li>{@link AccessibilityActionCompat#ACTION_SET_PROGRESS}</li> |
| * </ul> |
| * |
| * @see AccessibilityActionCompat#ACTION_SET_PROGRESS |
| */ |
| public static final String ACTION_ARGUMENT_PROGRESS_VALUE = |
| "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE"; |
| |
| /** |
| * Argument for specifying the x coordinate to which to move a window. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> |
| * <ul> |
| * <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li> |
| * </ul> |
| * |
| * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW |
| */ |
| public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = |
| "ACTION_ARGUMENT_MOVE_WINDOW_X"; |
| |
| /** |
| * Argument for specifying the y coordinate to which to move a window. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> |
| * <ul> |
| * <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li> |
| * </ul> |
| * |
| * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW |
| */ |
| public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = |
| "ACTION_ARGUMENT_MOVE_WINDOW_Y"; |
| |
| /** |
| * Argument to represent the duration in milliseconds to press and hold a node. |
| * <p> |
| * <strong>Type:</strong> int<br> |
| * <strong>Actions:</strong> |
| * <ul> |
| * <li>{@link AccessibilityActionCompat#ACTION_PRESS_AND_HOLD}</li> |
| * </ul> |
| * |
| * @see AccessibilityActionCompat#ACTION_PRESS_AND_HOLD |
| */ |
| @SuppressLint("ActionValue") |
| public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = |
| "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT"; |
| |
| // Focus types |
| |
| /** |
| * The input focus. |
| */ |
| public static final int FOCUS_INPUT = 1; |
| |
| /** |
| * The accessibility focus. |
| */ |
| public static final int FOCUS_ACCESSIBILITY = 2; |
| |
| // Movement granularities |
| |
| /** |
| * Movement granularity bit for traversing the text of a node by character. |
| */ |
| public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001; |
| |
| /** |
| * Movement granularity bit for traversing the text of a node by word. |
| */ |
| public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002; |
| |
| /** |
| * Movement granularity bit for traversing the text of a node by line. |
| */ |
| public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004; |
| |
| /** |
| * Movement granularity bit for traversing the text of a node by paragraph. |
| */ |
| public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008; |
| |
| /** |
| * Movement granularity bit for traversing the text of a node by page. |
| */ |
| public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010; |
| |
| private static int sClickableSpanId = 0; |
| |
| /** |
| * Creates a wrapper for info implementation. |
| * |
| * @param object The info to wrap. |
| * @return A wrapper for if the object is not null, null otherwise. |
| */ |
| @SuppressWarnings("deprecation") |
| static AccessibilityNodeInfoCompat wrapNonNullInstance(Object object) { |
| if (object != null) { |
| return new AccessibilityNodeInfoCompat(object); |
| } |
| return null; |
| } |
| |
| /** |
| * Creates a new instance wrapping an |
| * {@link android.view.accessibility.AccessibilityNodeInfo}. |
| * |
| * @param info The info. |
| * |
| * @deprecated Use {@link #wrap(AccessibilityNodeInfo)} instead. |
| */ |
| @Deprecated |
| public AccessibilityNodeInfoCompat(Object info) { |
| mInfo = (AccessibilityNodeInfo) info; |
| } |
| |
| private AccessibilityNodeInfoCompat(AccessibilityNodeInfo info) { |
| mInfo = info; |
| } |
| |
| /** |
| * Creates a new instance wrapping an |
| * {@link android.view.accessibility.AccessibilityNodeInfo}. |
| * |
| * @param info The info. |
| */ |
| public static AccessibilityNodeInfoCompat wrap(@NonNull AccessibilityNodeInfo info) { |
| return new AccessibilityNodeInfoCompat(info); |
| } |
| |
| /** |
| * @return The unwrapped {@link android.view.accessibility.AccessibilityNodeInfo}. |
| */ |
| public AccessibilityNodeInfo unwrap() { |
| return mInfo; |
| } |
| |
| /** |
| * @return The wrapped {@link android.view.accessibility.AccessibilityNodeInfo}. |
| * |
| * @deprecated Use {@link #unwrap()} instead. |
| */ |
| @Deprecated |
| public Object getInfo() { |
| return mInfo; |
| } |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one and |
| * sets the source. |
| * |
| * @return An instance. |
| * @see #setSource(View) |
| */ |
| public static AccessibilityNodeInfoCompat obtain(View source) { |
| return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(source)); |
| } |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one |
| * and sets the source. |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual descendant. |
| * @return An instance. |
| * |
| * @see #setSource(View, int) |
| */ |
| public static AccessibilityNodeInfoCompat obtain(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance( |
| AccessibilityNodeInfo.obtain(root, virtualDescendantId)); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns a cached instance if such is available otherwise a new one. |
| * |
| * @return An instance. |
| */ |
| public static AccessibilityNodeInfoCompat obtain() { |
| return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain()); |
| } |
| |
| /** |
| * Returns a cached instance if such is available or a new one is create. |
| * The returned instance is initialized from the given <code>info</code>. |
| * |
| * @param info The other info. |
| * @return An instance. |
| */ |
| public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) { |
| return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(info.mInfo)); |
| } |
| |
| /** |
| * Sets the source. |
| * |
| * @param source The info source. |
| */ |
| public void setSource(View source) { |
| mVirtualDescendantId = NO_ID; |
| |
| mInfo.setSource(source); |
| } |
| |
| /** |
| * Sets the source to be a virtual descendant of the given <code>root</code>. |
| * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root |
| * is set as the source. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report themselves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * <p> |
| * This method is not supported on devices running API level < 16 since the platform did |
| * not support virtual descendants of real views. |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual descendant. |
| */ |
| public void setSource(View root, int virtualDescendantId) { |
| // Store the ID anyway, since we may need it for equality checks. |
| mVirtualDescendantId = virtualDescendantId; |
| |
| if (Build.VERSION.SDK_INT >= 16) { |
| mInfo.setSource(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Find the view that has the specified focus type. The search starts from |
| * the view represented by this node info. |
| * |
| * @param focus The focus to find. One of {@link #FOCUS_INPUT} or |
| * {@link #FOCUS_ACCESSIBILITY}. |
| * @return The node info of the focused view or null. |
| * |
| * @see #FOCUS_INPUT |
| * @see #FOCUS_ACCESSIBILITY |
| */ |
| public AccessibilityNodeInfoCompat findFocus(int focus) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.findFocus(focus)); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Searches for the nearest view in the specified direction that can take |
| * input focus. |
| * |
| * @param direction The direction. Can be one of: |
| * {@link View#FOCUS_DOWN}, |
| * {@link View#FOCUS_UP}, |
| * {@link View#FOCUS_LEFT}, |
| * {@link View#FOCUS_RIGHT}, |
| * {@link View#FOCUS_FORWARD}, |
| * {@link View#FOCUS_BACKWARD}. |
| * |
| * @return The node info for the view that can take accessibility focus. |
| */ |
| public AccessibilityNodeInfoCompat focusSearch(int direction) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.focusSearch(direction)); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Gets the id of the window from which the info comes from. |
| * |
| * @return The window id. |
| */ |
| public int getWindowId() { |
| return mInfo.getWindowId(); |
| } |
| |
| /** |
| * Gets the number of children. |
| * |
| * @return The child count. |
| */ |
| public int getChildCount() { |
| return mInfo.getChildCount(); |
| } |
| |
| /** |
| * Get the child at given index. |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} to |
| * avoid creating of multiple instances. |
| * </p> |
| * |
| * @param index The child index. |
| * @return The child node. |
| * @throws IllegalStateException If called outside of an |
| * AccessibilityService. |
| */ |
| public AccessibilityNodeInfoCompat getChild(int index) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getChild(index)); |
| } |
| |
| /** |
| * Adds a child. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param child The child. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void addChild(View child) { |
| mInfo.addChild(child); |
| } |
| |
| /** |
| * Adds a virtual child which is a descendant of the given <code>root</code>. |
| * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root |
| * is added as a child. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report them selves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * </p> |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual child. |
| */ |
| public void addChild(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| mInfo.addChild(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Removes a child. If the child was not previously added to the node, |
| * calling this method has no effect. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param child The child. |
| * @return true if the child was present |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public boolean removeChild(View child) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return mInfo.removeChild(child); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Removes a virtual child which is a descendant of the given |
| * <code>root</code>. If the child was not previously added to the node, |
| * calling this method has no effect. |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual child. |
| * @return true if the child was present |
| * @see #addChild(View, int) |
| */ |
| public boolean removeChild(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return mInfo.removeChild(root, virtualDescendantId); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Gets the actions that can be performed on the node. |
| * |
| * @return The bit mask of with actions. |
| * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS |
| * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS |
| * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT |
| * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION |
| */ |
| public int getActions() { |
| return mInfo.getActions(); |
| } |
| |
| /** |
| * Adds an action that can be performed on the node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param action The action. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void addAction(int action) { |
| mInfo.addAction(action); |
| } |
| |
| private List<Integer> extrasIntList(String key) { |
| if (Build.VERSION.SDK_INT < 19) { |
| return new ArrayList<Integer>(); |
| } |
| ArrayList<Integer> list = mInfo.getExtras() |
| .getIntegerArrayList(key); |
| if (list == null) { |
| list = new ArrayList<Integer>(); |
| mInfo.getExtras().putIntegerArrayList(key, list); |
| } |
| return list; |
| } |
| |
| /** |
| * Adds an action that can be performed on the node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param action The action. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 21: No-op</li> |
| * </ul> |
| */ |
| public void addAction(AccessibilityActionCompat action) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| mInfo.addAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction); |
| } |
| } |
| |
| /** |
| * Removes an action that can be performed on the node. If the action was |
| * not already added to the node, calling this method has no effect. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param action The action to be removed. |
| * @return The action removed from the list of actions. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 21: Always returns {@code false}</li> |
| * </ul> |
| */ |
| public boolean removeAction(AccessibilityActionCompat action) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return mInfo.removeAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Performs an action on the node. |
| * <p> |
| * <strong>Note:</strong> An action can be performed only if the request is |
| * made from an {@link android.accessibilityservice.AccessibilityService}. |
| * </p> |
| * |
| * @param action The action to perform. |
| * @return True if the action was performed. |
| * @throws IllegalStateException If called outside of an |
| * AccessibilityService. |
| */ |
| public boolean performAction(int action) { |
| return mInfo.performAction(action); |
| } |
| |
| /** |
| * Performs an action on the node. |
| * <p> |
| * <strong>Note:</strong> An action can be performed only if the request is made |
| * from an {@link android.accessibilityservice.AccessibilityService}. |
| * </p> |
| * |
| * @param action The action to perform. |
| * @param arguments A bundle with additional arguments. |
| * @return True if the action was performed. |
| * |
| * @throws IllegalStateException If called outside of an AccessibilityService. |
| */ |
| public boolean performAction(int action, Bundle arguments) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return mInfo.performAction(action, arguments); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets the movement granularities for traversing the text of this node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param granularities The bit mask with granularities. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setMovementGranularities(int granularities) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| mInfo.setMovementGranularities(granularities); |
| } |
| } |
| |
| /** |
| * Gets the movement granularities for traversing the text of this node. |
| * |
| * @return The bit mask with granularities. |
| */ |
| public int getMovementGranularities() { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return mInfo.getMovementGranularities(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by text. The match |
| * is case insensitive containment. The search is relative to this info i.e. this |
| * info is the root of the traversed tree. |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()} |
| * to avoid creating of multiple instances. |
| * </p> |
| * |
| * @param text The searched text. |
| * @return A list of node info. |
| */ |
| public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(String text) { |
| List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>(); |
| List<AccessibilityNodeInfo> infos = mInfo.findAccessibilityNodeInfosByText(text); |
| final int infoCount = infos.size(); |
| for (int i = 0; i < infoCount; i++) { |
| AccessibilityNodeInfo info = infos.get(i); |
| result.add(AccessibilityNodeInfoCompat.wrap(info)); |
| } |
| return result; |
| } |
| |
| /** |
| * Gets the parent. |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()} |
| * to avoid creating of multiple instances. |
| * </p> |
| * |
| * @return The parent. |
| */ |
| public AccessibilityNodeInfoCompat getParent() { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getParent()); |
| } |
| |
| /** |
| * Sets the parent. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param parent The parent. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setParent(View parent) { |
| mParentVirtualDescendantId = NO_ID; |
| |
| mInfo.setParent(parent); |
| } |
| |
| /** |
| * Sets the parent to be a virtual descendant of the given <code>root</code>. |
| * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root |
| * is set as the parent. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report them selves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * <p> |
| * This method is not supported on devices running API level < 16 since the platform did |
| * not support virtual descendants of real views. |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual descendant. |
| */ |
| public void setParent(View root, int virtualDescendantId) { |
| // Store the ID anyway, since we may need it for equality checks. |
| mParentVirtualDescendantId = virtualDescendantId; |
| |
| if (Build.VERSION.SDK_INT >= 16) { |
| mInfo.setParent(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Gets the node bounds in the viewParent's coordinates. |
| * {@link #getParent()} does not represent the source's viewParent. |
| * Instead it represents the result of {@link View#getParentForAccessibility()}, |
| * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true. |
| * So this method is not reliable. |
| * |
| * @param outBounds The output node bounds. |
| * |
| * @deprecated Use {@link #getBoundsInScreen(Rect)} instead. |
| */ |
| @Deprecated |
| public void getBoundsInParent(Rect outBounds) { |
| mInfo.getBoundsInParent(outBounds); |
| } |
| |
| /** |
| * Sets the node bounds in the viewParent's coordinates. |
| * {@link #getParent()} does not represent the source's viewParent. |
| * Instead it represents the result of {@link View#getParentForAccessibility()}, |
| * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true. |
| * So this method is not reliable. |
| * |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param bounds The node bounds. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| * |
| * @deprecated Accessibility services should not care about these bounds. |
| */ |
| @Deprecated |
| public void setBoundsInParent(Rect bounds) { |
| mInfo.setBoundsInParent(bounds); |
| } |
| |
| /** |
| * Gets the node bounds in screen coordinates. |
| * |
| * @param outBounds The output node bounds. |
| */ |
| public void getBoundsInScreen(Rect outBounds) { |
| mInfo.getBoundsInScreen(outBounds); |
| } |
| |
| /** |
| * Sets the node bounds in screen coordinates. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param bounds The node bounds. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setBoundsInScreen(Rect bounds) { |
| mInfo.setBoundsInScreen(bounds); |
| } |
| |
| /** |
| * Gets whether this node is checkable. |
| * |
| * @return True if the node is checkable. |
| */ |
| public boolean isCheckable() { |
| return mInfo.isCheckable(); |
| } |
| |
| /** |
| * Sets whether this node is checkable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param checkable True if the node is checkable. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setCheckable(boolean checkable) { |
| mInfo.setCheckable(checkable); |
| } |
| |
| /** |
| * Gets whether this node is checked. |
| * |
| * @return True if the node is checked. |
| */ |
| public boolean isChecked() { |
| return mInfo.isChecked(); |
| } |
| |
| /** |
| * Sets whether this node is checked. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param checked True if the node is checked. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setChecked(boolean checked) { |
| mInfo.setChecked(checked); |
| } |
| |
| /** |
| * Gets whether this node is focusable. |
| * |
| * @return True if the node is focusable. |
| */ |
| public boolean isFocusable() { |
| return mInfo.isFocusable(); |
| } |
| |
| /** |
| * Sets whether this node is focusable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param focusable True if the node is focusable. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setFocusable(boolean focusable) { |
| mInfo.setFocusable(focusable); |
| } |
| |
| /** |
| * Gets whether this node is focused. |
| * |
| * @return True if the node is focused. |
| */ |
| public boolean isFocused() { |
| return mInfo.isFocused(); |
| } |
| |
| /** |
| * Sets whether this node is focused. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param focused True if the node is focused. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setFocused(boolean focused) { |
| mInfo.setFocused(focused); |
| } |
| |
| /** |
| * Gets whether this node is visible to the user. |
| * |
| * @return Whether the node is visible to the user. |
| */ |
| public boolean isVisibleToUser() { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return mInfo.isVisibleToUser(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets whether this node is visible to the user. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param visibleToUser Whether the node is visible to the user. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setVisibleToUser(boolean visibleToUser) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| mInfo.setVisibleToUser(visibleToUser); |
| } |
| } |
| |
| /** |
| * Gets whether this node is accessibility focused. |
| * |
| * @return True if the node is accessibility focused. |
| */ |
| public boolean isAccessibilityFocused() { |
| if (Build.VERSION.SDK_INT >= 16) { |
| return mInfo.isAccessibilityFocused(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets whether this node is accessibility focused. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param focused True if the node is accessibility focused. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setAccessibilityFocused(boolean focused) { |
| if (Build.VERSION.SDK_INT >= 16) { |
| mInfo.setAccessibilityFocused(focused); |
| } |
| } |
| |
| /** |
| * Gets whether this node is selected. |
| * |
| * @return True if the node is selected. |
| */ |
| public boolean isSelected() { |
| return mInfo.isSelected(); |
| } |
| |
| /** |
| * Sets whether this node is selected. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param selected True if the node is selected. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setSelected(boolean selected) { |
| mInfo.setSelected(selected); |
| } |
| |
| /** |
| * Gets whether this node is clickable. |
| * |
| * @return True if the node is clickable. |
| */ |
| public boolean isClickable() { |
| return mInfo.isClickable(); |
| } |
| |
| /** |
| * Sets whether this node is clickable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param clickable True if the node is clickable. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setClickable(boolean clickable) { |
| mInfo.setClickable(clickable); |
| } |
| |
| /** |
| * Gets whether this node is long clickable. |
| * |
| * @return True if the node is long clickable. |
| */ |
| public boolean isLongClickable() { |
| return mInfo.isLongClickable(); |
| } |
| |
| /** |
| * Sets whether this node is long clickable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param longClickable True if the node is long clickable. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setLongClickable(boolean longClickable) { |
| mInfo.setLongClickable(longClickable); |
| } |
| |
| /** |
| * Gets whether this node is enabled. |
| * |
| * @return True if the node is enabled. |
| */ |
| public boolean isEnabled() { |
| return mInfo.isEnabled(); |
| } |
| |
| /** |
| * Sets whether this node is enabled. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param enabled True if the node is enabled. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setEnabled(boolean enabled) { |
| mInfo.setEnabled(enabled); |
| } |
| |
| /** |
| * Gets whether this node is a password. |
| * |
| * @return True if the node is a password. |
| */ |
| public boolean isPassword() { |
| return mInfo.isPassword(); |
| } |
| |
| /** |
| * Sets whether this node is a password. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param password True if the node is a password. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setPassword(boolean password) { |
| mInfo.setPassword(password); |
| } |
| |
| /** |
| * Gets if the node is scrollable. |
| * |
| * @return True if the node is scrollable, false otherwise. |
| */ |
| public boolean isScrollable() { |
| return mInfo.isScrollable(); |
| } |
| |
| /** |
| * Sets if the node is scrollable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param scrollable True if the node is scrollable, false otherwise. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setScrollable(boolean scrollable) { |
| mInfo.setScrollable(scrollable); |
| } |
| |
| /** |
| * Returns whether the node originates from a view considered important for accessibility. |
| * |
| * @return {@code true} if the node originates from a view considered important for |
| * accessibility, {@code false} otherwise |
| * |
| * @see View#isImportantForAccessibility() |
| */ |
| public boolean isImportantForAccessibility() { |
| if (Build.VERSION.SDK_INT >= 24) { |
| return mInfo.isImportantForAccessibility(); |
| } else { |
| return true; |
| } |
| } |
| |
| /** |
| * Sets whether the node is considered important for accessibility. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param important {@code true} if the node is considered important for accessibility, |
| * {@code false} otherwise |
| */ |
| public void setImportantForAccessibility(boolean important) { |
| if (Build.VERSION.SDK_INT >= 24) { |
| mInfo.setImportantForAccessibility(important); |
| } |
| } |
| |
| /** |
| * Gets the package this node comes from. |
| * |
| * @return The package name. |
| */ |
| public CharSequence getPackageName() { |
| return mInfo.getPackageName(); |
| } |
| |
| /** |
| * Sets the package this node comes from. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param packageName The package name. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setPackageName(CharSequence packageName) { |
| mInfo.setPackageName(packageName); |
| } |
| |
| /** |
| * Gets the class this node comes from. |
| * |
| * @return The class name. |
| */ |
| public CharSequence getClassName() { |
| return mInfo.getClassName(); |
| } |
| |
| /** |
| * Sets the class this node comes from. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param className The class name. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setClassName(CharSequence className) { |
| mInfo.setClassName(className); |
| } |
| |
| /** |
| * Gets the text of this node. |
| * |
| * @return The text. |
| */ |
| public CharSequence getText() { |
| if (hasSpans()) { |
| List<Integer> starts = extrasIntList(SPANS_START_KEY); |
| List<Integer> ends = extrasIntList(SPANS_END_KEY); |
| List<Integer> flags = extrasIntList(SPANS_FLAGS_KEY); |
| List<Integer> ids = extrasIntList(SPANS_ID_KEY); |
| Spannable spannable = new SpannableString(TextUtils.substring(mInfo.getText(), |
| 0, mInfo.getText().length())); |
| for (int i = 0; i < starts.size(); i++) { |
| spannable.setSpan(new AccessibilityClickableSpanCompat(ids.get(i), this, |
| getExtras().getInt(SPANS_ACTION_ID_KEY)), |
| starts.get(i), ends.get(i), flags.get(i)); |
| } |
| return spannable; |
| } else { |
| return mInfo.getText(); |
| } |
| } |
| |
| /** |
| * Sets the text of this node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param text The text. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setText(CharSequence text) { |
| mInfo.setText(text); |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public void addSpansToExtras(CharSequence text, View view) { |
| if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 26) { |
| clearExtrasSpans(); |
| removeCollectedSpans(view); |
| ClickableSpan[] spans = getClickableSpans(text); |
| if (spans != null && spans.length > 0) { |
| getExtras().putInt(SPANS_ACTION_ID_KEY, R.id.accessibility_action_clickable_span); |
| SparseArray<WeakReference<ClickableSpan>> tagSpans = |
| getOrCreateSpansFromViewTags(view); |
| for (int i = 0; spans != null && i < spans.length; i++) { |
| int id = idForClickableSpan(spans[i], tagSpans); |
| tagSpans.put(id, new WeakReference<>(spans[i])); |
| addSpanLocationToExtras(spans[i], (Spanned) text, id); |
| } |
| } |
| } |
| } |
| |
| private SparseArray<WeakReference<ClickableSpan>> getOrCreateSpansFromViewTags(View host) { |
| SparseArray<WeakReference<ClickableSpan>> spans = getSpansFromViewTags(host); |
| if (spans == null) { |
| spans = new SparseArray<>(); |
| host.setTag(R.id.tag_accessibility_clickable_spans, spans); |
| } |
| return spans; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private SparseArray<WeakReference<ClickableSpan>> getSpansFromViewTags(View host) { |
| return (SparseArray<WeakReference<ClickableSpan>>) host.getTag( |
| R.id.tag_accessibility_clickable_spans); |
| } |
| |
| /** |
| * @hide |
| */ |
| @RestrictTo(LIBRARY_GROUP_PREFIX) |
| public static ClickableSpan[] getClickableSpans(CharSequence text) { |
| if (text instanceof Spanned) { |
| Spanned spanned = (Spanned) text; |
| return spanned.getSpans(0, text.length(), ClickableSpan.class); |
| } |
| return null; |
| } |
| |
| private int idForClickableSpan(ClickableSpan span, |
| SparseArray<WeakReference<ClickableSpan>> spans) { |
| if (spans != null) { |
| for (int i = 0; i < spans.size(); i++) { |
| ClickableSpan aSpan = spans.valueAt(i).get(); |
| if (span.equals(aSpan)) { |
| return spans.keyAt(i); |
| } |
| } |
| } |
| return sClickableSpanId++; |
| } |
| |
| private boolean hasSpans() { |
| return !extrasIntList(SPANS_START_KEY).isEmpty(); |
| } |
| |
| private void clearExtrasSpans() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.getExtras().remove(SPANS_START_KEY); |
| mInfo.getExtras().remove(SPANS_END_KEY); |
| mInfo.getExtras().remove(SPANS_FLAGS_KEY); |
| mInfo.getExtras().remove(SPANS_ID_KEY); |
| } |
| } |
| |
| private void addSpanLocationToExtras(ClickableSpan span, Spanned spanned, int id) { |
| extrasIntList(SPANS_START_KEY).add(spanned.getSpanStart(span)); |
| extrasIntList(SPANS_END_KEY).add(spanned.getSpanEnd(span)); |
| extrasIntList(SPANS_FLAGS_KEY).add(spanned.getSpanFlags(span)); |
| extrasIntList(SPANS_ID_KEY).add(id); |
| } |
| |
| private void removeCollectedSpans(View view) { |
| SparseArray<WeakReference<ClickableSpan>> spans = getSpansFromViewTags(view); |
| if (spans != null) { |
| List<Integer> toBeRemovedIndices = new ArrayList<>(); |
| for (int i = 0; i < spans.size(); i++) { |
| if (spans.valueAt(i).get() == null) { |
| toBeRemovedIndices.add(i); |
| } |
| } |
| for (int i = 0; i < toBeRemovedIndices.size(); i++) { |
| spans.remove(toBeRemovedIndices.get(i)); |
| } |
| } |
| } |
| |
| /** |
| * Gets the content description of this node. |
| * |
| * @return The content description. |
| */ |
| public CharSequence getContentDescription() { |
| return mInfo.getContentDescription(); |
| } |
| |
| /** |
| * Gets the state description of this node. |
| * |
| * @return the state description or null if android version smaller |
| * than 19. |
| */ |
| public @Nullable CharSequence getStateDescription() { |
| if (BuildCompat.isAtLeastR()) { |
| return mInfo.getStateDescription(); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getExtras().getCharSequence(STATE_DESCRIPTION_KEY); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the content description of this node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param contentDescription The content description. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setContentDescription(CharSequence contentDescription) { |
| mInfo.setContentDescription(contentDescription); |
| } |
| |
| /** |
| * Sets the state description of this node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param stateDescription the state description of this node. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setStateDescription(@Nullable CharSequence stateDescription) { |
| if (BuildCompat.isAtLeastR()) { |
| mInfo.setStateDescription(stateDescription); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.getExtras().putCharSequence(STATE_DESCRIPTION_KEY, stateDescription); |
| } |
| } |
| |
| /** |
| * Return an instance back to be reused. |
| * <p> |
| * <strong>Note:</strong> You must not touch the object after calling this function. |
| * |
| * @throws IllegalStateException If the info is already recycled. |
| */ |
| public void recycle() { |
| mInfo.recycle(); |
| } |
| |
| /** |
| * Sets the fully qualified resource name of the source view's id. |
| * |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param viewId The id resource name. |
| */ |
| public void setViewIdResourceName(String viewId) { |
| if (Build.VERSION.SDK_INT >= 18) { |
| mInfo.setViewIdResourceName(viewId); |
| } |
| } |
| |
| /** |
| * Gets the fully qualified resource name of the source view's id. |
| * |
| * <p> |
| * <strong>Note:</strong> The primary usage of this API is for UI test automation |
| * and in order to report the source view id of an {@link AccessibilityNodeInfoCompat} |
| * the client has to set the {@link AccessibilityServiceInfoCompat#FLAG_REPORT_VIEW_IDS} |
| * flag when configuring his {@link android.accessibilityservice.AccessibilityService}. |
| * </p> |
| * |
| * @return The id resource name. |
| */ |
| public String getViewIdResourceName() { |
| if (Build.VERSION.SDK_INT >= 18) { |
| return mInfo.getViewIdResourceName(); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Gets the node's live region mode. |
| * <p> |
| * A live region is a node that contains information that is important for |
| * the user and when it changes the user should be notified. For example, |
| * in a login screen with a TextView that displays an "incorrect password" |
| * notification, that view should be marked as a live region with mode |
| * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_POLITE}. |
| * <p> |
| * It is the responsibility of the accessibility service to monitor |
| * {@link AccessibilityEventCompat#TYPE_WINDOW_CONTENT_CHANGED} events |
| * indicating changes to live region nodes and their children. |
| * |
| * @return The live region mode, or |
| * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_NONE} if the view is |
| * not a live region. |
| * @see ViewCompat#getAccessibilityLiveRegion(View) |
| */ |
| public int getLiveRegion() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getLiveRegion(); |
| } else { |
| return ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE; |
| } |
| } |
| |
| /** |
| * Sets the node's live region mode. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is |
| * made immutable before being delivered to an AccessibilityService. |
| * |
| * @param mode The live region mode, or |
| * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_NONE} if the view is |
| * not a live region. |
| * @see ViewCompat#setAccessibilityLiveRegion(View, int) |
| */ |
| public void setLiveRegion(int mode) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setLiveRegion(mode); |
| } |
| } |
| |
| /** |
| * Get the drawing order of the view corresponding it this node. |
| * <p> |
| * Drawing order is determined only within the node's parent, so this index is only relative |
| * to its siblings. |
| * <p> |
| * In some cases, the drawing order is essentially simultaneous, so it is possible for two |
| * siblings to return the same value. It is also possible that values will be skipped. |
| * |
| * @return The drawing position of the view corresponding to this node relative to its siblings. |
| */ |
| public int getDrawingOrder() { |
| if (Build.VERSION.SDK_INT >= 24) { |
| return mInfo.getDrawingOrder(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * Set the drawing order of the view corresponding it this node. |
| * |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * @param drawingOrderInParent |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setDrawingOrder(int drawingOrderInParent) { |
| if (Build.VERSION.SDK_INT >= 24) { |
| mInfo.setDrawingOrder(drawingOrderInParent); |
| } |
| } |
| |
| /** |
| * Gets the collection info if the node is a collection. A collection |
| * child is always a collection item. |
| * |
| * @return The collection info. |
| */ |
| public CollectionInfoCompat getCollectionInfo() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| AccessibilityNodeInfo.CollectionInfo info = mInfo.getCollectionInfo(); |
| if (info != null) { |
| return new CollectionInfoCompat(info); |
| } |
| } |
| return null; |
| } |
| |
| public void setCollectionInfo(Object collectionInfo) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setCollectionInfo((collectionInfo == null) ? null |
| : (AccessibilityNodeInfo.CollectionInfo) ((CollectionInfoCompat) |
| collectionInfo).mInfo); |
| } |
| |
| } |
| |
| public void setCollectionItemInfo(Object collectionItemInfo) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null |
| : (AccessibilityNodeInfo.CollectionItemInfo) ((CollectionItemInfoCompat) |
| collectionItemInfo).mInfo); |
| } |
| } |
| |
| /** |
| * Gets the collection item info if the node is a collection item. A collection |
| * item is always a child of a collection. |
| * |
| * @return The collection item info. |
| */ |
| public CollectionItemInfoCompat getCollectionItemInfo() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| AccessibilityNodeInfo.CollectionItemInfo info = mInfo.getCollectionItemInfo(); |
| if (info != null) { |
| return new CollectionItemInfoCompat(info); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Gets the range info if this node is a range. |
| * |
| * @return The range. |
| */ |
| public RangeInfoCompat getRangeInfo() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| AccessibilityNodeInfo.RangeInfo info = mInfo.getRangeInfo(); |
| if (info != null) { |
| return new RangeInfoCompat(info); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the range info if this node is a range. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param rangeInfo The range info. |
| */ |
| public void setRangeInfo(RangeInfoCompat rangeInfo) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo.mInfo); |
| } |
| } |
| |
| /** |
| * Gets the actions that can be performed on the node. |
| * |
| * @return A list of AccessibilityActions. |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 21: Always returns {@code null}</li> |
| * </ul> |
| */ |
| @SuppressWarnings("unchecked") |
| public List<AccessibilityActionCompat> getActionList() { |
| List<Object> actions = null; |
| if (Build.VERSION.SDK_INT >= 21) { |
| actions = (List<Object>) (List<?>) mInfo.getActionList(); |
| } |
| if (actions != null) { |
| List<AccessibilityActionCompat> result = new ArrayList<AccessibilityActionCompat>(); |
| final int actionCount = actions.size(); |
| for (int i = 0; i < actionCount; i++) { |
| Object action = actions.get(i); |
| result.add(new AccessibilityActionCompat(action)); |
| } |
| return result; |
| } else { |
| return Collections.<AccessibilityActionCompat>emptyList(); |
| } |
| } |
| |
| /** |
| * Sets if the content of this node is invalid. For example, |
| * a date is not well-formed. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param contentInvalid If the node content is invalid. |
| */ |
| public void setContentInvalid(boolean contentInvalid) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setContentInvalid(contentInvalid); |
| } |
| } |
| |
| /** |
| * Gets if the content of this node is invalid. For example, |
| * a date is not well-formed. |
| * |
| * @return If the node content is invalid. |
| */ |
| public boolean isContentInvalid() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.isContentInvalid(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Gets whether this node is context clickable. |
| * |
| * @return True if the node is context clickable. |
| */ |
| public boolean isContextClickable() { |
| if (Build.VERSION.SDK_INT >= 23) { |
| return mInfo.isContextClickable(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets whether this node is context clickable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable |
| * before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param contextClickable True if the node is context clickable. |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setContextClickable(boolean contextClickable) { |
| if (Build.VERSION.SDK_INT >= 23) { |
| mInfo.setContextClickable(contextClickable); |
| } |
| } |
| |
| /** |
| * Gets the hint text of this node. Only applies to nodes where text can be entered. |
| * |
| * @return The hint text. |
| */ |
| public @Nullable CharSequence getHintText() { |
| if (Build.VERSION.SDK_INT >= 26) { |
| return mInfo.getHintText(); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getExtras().getCharSequence(HINT_TEXT_KEY); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the hint text of this node. Only applies to nodes where text can be entered. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param hintText The hint text for this mode. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setHintText(@Nullable CharSequence hintText) { |
| if (Build.VERSION.SDK_INT >= 26) { |
| mInfo.setHintText(hintText); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.getExtras().putCharSequence(HINT_TEXT_KEY, hintText); |
| } |
| } |
| |
| |
| /** |
| * Sets the error text of this node. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param error The error text. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setError(CharSequence error) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| mInfo.setError(error); |
| } |
| } |
| |
| /** |
| * Gets the error text of this node. |
| * |
| * @return The error text. |
| */ |
| public CharSequence getError() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return mInfo.getError(); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the view for which the view represented by this info serves as a |
| * label for accessibility purposes. |
| * |
| * @param labeled The view for which this info serves as a label. |
| */ |
| public void setLabelFor(View labeled) { |
| if (Build.VERSION.SDK_INT >= 17) { |
| mInfo.setLabelFor(labeled); |
| } |
| } |
| |
| /** |
| * Sets the view for which the view represented by this info serves as a |
| * label for accessibility purposes. If <code>virtualDescendantId</code> |
| * is {@link View#NO_ID} the root is set as the labeled. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report themselves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * </p> |
| * |
| * @param root The root whose virtual descendant serves as a label. |
| * @param virtualDescendantId The id of the virtual descendant. |
| */ |
| public void setLabelFor(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 17) { |
| mInfo.setLabelFor(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Gets the node info for which the view represented by this info serves as |
| * a label for accessibility purposes. |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} |
| * to avoid creating of multiple instances. |
| * </p> |
| * |
| * @return The labeled info. |
| */ |
| public AccessibilityNodeInfoCompat getLabelFor() { |
| if (Build.VERSION.SDK_INT >= 17) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabelFor()); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the view which serves as the label of the view represented by |
| * this info for accessibility purposes. |
| * |
| * @param label The view that labels this node's source. |
| */ |
| public void setLabeledBy(View label) { |
| if (Build.VERSION.SDK_INT >= 17) { |
| mInfo.setLabeledBy(label); |
| } |
| } |
| |
| /** |
| * Sets the view which serves as the label of the view represented by |
| * this info for accessibility purposes. If <code>virtualDescendantId</code> |
| * is {@link View#NO_ID} the root is set as the label. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report themselves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * </p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param root The root whose virtual descendant labels this node's source. |
| * @param virtualDescendantId The id of the virtual descendant. |
| */ |
| public void setLabeledBy(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 17) { |
| mInfo.setLabeledBy(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Gets the node info which serves as the label of the view represented by |
| * this info for accessibility purposes. |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} |
| * to avoid creating of multiple instances. |
| * </p> |
| * |
| * @return The label. |
| */ |
| public AccessibilityNodeInfoCompat getLabeledBy() { |
| if (Build.VERSION.SDK_INT >= 17) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabeledBy()); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Gets if this node opens a popup or a dialog. |
| * |
| * @return If the the node opens a popup. |
| */ |
| public boolean canOpenPopup() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.canOpenPopup(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets if this node opens a popup or a dialog. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param opensPopup If the the node opens a popup. |
| */ |
| public void setCanOpenPopup(boolean opensPopup) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setCanOpenPopup(opensPopup); |
| } |
| } |
| |
| /** |
| * Finds {@link AccessibilityNodeInfoCompat}s by the fully qualified view id's resource |
| * name where a fully qualified id is of the from "package:id/id_resource_name". |
| * For example, if the target application's package is "foo.bar" and the id |
| * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz". |
| * |
| * <p> |
| * <strong>Note:</strong> It is a client responsibility to recycle the |
| * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} |
| * to avoid creating of multiple instances. |
| * </p> |
| * <p> |
| * <strong>Note:</strong> The primary usage of this API is for UI test automation |
| * and in order to report the fully qualified view id if an |
| * {@link AccessibilityNodeInfoCompat} the client has to set the |
| * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} |
| * flag when configuring his {@link android.accessibilityservice.AccessibilityService}. |
| * </p> |
| * |
| * @param viewId The fully qualified resource name of the view id to find. |
| * @return A list of node info. |
| */ |
| public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(String viewId) { |
| if (Build.VERSION.SDK_INT >= 18) { |
| List<AccessibilityNodeInfo> nodes = mInfo.findAccessibilityNodeInfosByViewId(viewId); |
| List<AccessibilityNodeInfoCompat> result = new ArrayList<>(); |
| for (AccessibilityNodeInfo node : nodes) { |
| result.add(AccessibilityNodeInfoCompat.wrap(node)); |
| } |
| return result; |
| } else { |
| return Collections.emptyList(); |
| } |
| } |
| |
| /** |
| * Gets an optional bundle with extra data. The bundle |
| * is lazily created and never <code>null</code>. |
| * <p> |
| * <strong>Note:</strong> It is recommended to use the package |
| * name of your application as a prefix for the keys to avoid |
| * collisions which may confuse an accessibility service if the |
| * same key has different meaning when emitted from different |
| * applications. |
| * </p> |
| * |
| * @return The bundle. |
| */ |
| public Bundle getExtras() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getExtras(); |
| } else { |
| return new Bundle(); |
| } |
| } |
| |
| /** |
| * Gets the input type of the source as defined by {@link InputType}. |
| * |
| * @return The input type. |
| */ |
| public int getInputType() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getInputType(); |
| } else { |
| return InputType.TYPE_NULL; |
| } |
| } |
| |
| /** |
| * Sets the input type of the source as defined by {@link InputType}. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an |
| * AccessibilityService. |
| * </p> |
| * |
| * @param inputType The input type. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setInputType(int inputType) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setInputType(inputType); |
| } |
| } |
| |
| /** |
| * Sets the maximum text length, or -1 for no limit. |
| * <p> |
| * Typically used to indicate that an editable text field has a limit on |
| * the number of characters entered. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * |
| * @param max The maximum text length. |
| * @see #getMaxTextLength() |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setMaxTextLength(int max) { |
| if (Build.VERSION.SDK_INT >= 21) { |
| mInfo.setMaxTextLength(max); |
| } |
| } |
| |
| /** |
| * Returns the maximum text length for this node. |
| * |
| * @return The maximum text length, or -1 for no limit. |
| * @see #setMaxTextLength(int) |
| */ |
| public int getMaxTextLength() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return mInfo.getMaxTextLength(); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * Sets the text selection start and end. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param start The text selection start. |
| * @param end The text selection end. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setTextSelection(int start, int end) { |
| if (Build.VERSION.SDK_INT >= 18) { |
| mInfo.setTextSelection(start, end); |
| } |
| } |
| |
| /** |
| * Gets the text selection start. |
| * |
| * @return The text selection start if there is selection or -1. |
| */ |
| public int getTextSelectionStart() { |
| if (Build.VERSION.SDK_INT >= 18) { |
| return mInfo.getTextSelectionStart(); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * Gets the text selection end. |
| * |
| * @return The text selection end if there is selection or -1. |
| */ |
| public int getTextSelectionEnd() { |
| if (Build.VERSION.SDK_INT >= 18) { |
| return mInfo.getTextSelectionEnd(); |
| } else { |
| return -1; |
| } |
| } |
| |
| /** |
| * Gets the node before which this one is visited during traversal. A screen-reader |
| * must visit the content of this node before the content of the one it precedes. |
| * |
| * @return The succeeding node if such or <code>null</code>. |
| * |
| * @see #setTraversalBefore(android.view.View) |
| * @see #setTraversalBefore(android.view.View, int) |
| */ |
| public AccessibilityNodeInfoCompat getTraversalBefore() { |
| if (Build.VERSION.SDK_INT >= 22) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalBefore()); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the view before whose node this one should be visited during traversal. A |
| * screen-reader must visit the content of this node before the content of the one |
| * it precedes. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param view The view providing the preceding node. |
| * |
| * @see #getTraversalBefore() |
| */ |
| public void setTraversalBefore(View view) { |
| if (Build.VERSION.SDK_INT >= 22) { |
| mInfo.setTraversalBefore(view); |
| } |
| } |
| |
| /** |
| * Sets the node before which this one is visited during traversal. A screen-reader |
| * must visit the content of this node before the content of the one it precedes. |
| * The successor is a virtual descendant of the given <code>root</code>. If |
| * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set |
| * as the successor. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report them selves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * </p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual descendant. |
| */ |
| public void setTraversalBefore(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 22) { |
| mInfo.setTraversalBefore(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Gets the node after which this one is visited in accessibility traversal. |
| * A screen-reader must visit the content of the other node before the content |
| * of this one. |
| * |
| * @return The succeeding node if such or <code>null</code>. |
| * |
| * @see #setTraversalAfter(android.view.View) |
| * @see #setTraversalAfter(android.view.View, int) |
| */ |
| public AccessibilityNodeInfoCompat getTraversalAfter() { |
| if (Build.VERSION.SDK_INT >= 22) { |
| return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalAfter()); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the view whose node is visited after this one in accessibility traversal. |
| * A screen-reader must visit the content of the other node before the content |
| * of this one. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param view The previous view. |
| * |
| * @see #getTraversalAfter() |
| */ |
| public void setTraversalAfter(View view) { |
| if (Build.VERSION.SDK_INT >= 22) { |
| mInfo.setTraversalAfter(view); |
| } |
| } |
| |
| /** |
| * Sets the node after which this one is visited in accessibility traversal. |
| * A screen-reader must visit the content of the other node before the content |
| * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID} |
| * the root is set as the predecessor. |
| * <p> |
| * A virtual descendant is an imaginary View that is reported as a part of the view |
| * hierarchy for accessibility purposes. This enables custom views that draw complex |
| * content to report them selves as a tree of virtual views, thus conveying their |
| * logical structure. |
| * </p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param root The root of the virtual subtree. |
| * @param virtualDescendantId The id of the virtual descendant. |
| */ |
| public void setTraversalAfter(View root, int virtualDescendantId) { |
| if (Build.VERSION.SDK_INT >= 22) { |
| mInfo.setTraversalAfter(root, virtualDescendantId); |
| } |
| } |
| |
| /** |
| * Gets the window to which this node belongs. |
| * |
| * @return The window. |
| * |
| * @see android.accessibilityservice.AccessibilityService#getWindows() |
| */ |
| public AccessibilityWindowInfoCompat getWindow() { |
| if (Build.VERSION.SDK_INT >= 21) { |
| return AccessibilityWindowInfoCompat.wrapNonNullInstance(mInfo.getWindow()); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Gets if the node can be dismissed. |
| * |
| * @return If the node can be dismissed. |
| */ |
| public boolean isDismissable() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.isDismissable(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets if the node can be dismissed. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param dismissable If the node can be dismissed. |
| */ |
| public void setDismissable(boolean dismissable) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setDismissable(dismissable); |
| } |
| } |
| |
| /** |
| * Gets if the node is editable. |
| * |
| * @return True if the node is editable, false otherwise. |
| */ |
| public boolean isEditable() { |
| if (Build.VERSION.SDK_INT >= 18) { |
| return mInfo.isEditable(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets whether this node is editable. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param editable True if the node is editable. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setEditable(boolean editable) { |
| if (Build.VERSION.SDK_INT >= 18) { |
| mInfo.setEditable(editable); |
| } |
| } |
| |
| /** |
| * Gets if the node is a multi line editable text. |
| * |
| * @return True if the node is multi line. |
| */ |
| public boolean isMultiLine() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.isMultiLine(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Sets if the node is a multi line editable text. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param multiLine True if the node is multi line. |
| */ |
| public void setMultiLine(boolean multiLine) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.setMultiLine(multiLine); |
| } |
| } |
| |
| /** |
| * Gets the tooltip text of this node. |
| * |
| * @return The tooltip text. |
| */ |
| @Nullable |
| public CharSequence getTooltipText() { |
| if (Build.VERSION.SDK_INT >= 28) { |
| return mInfo.getTooltipText(); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getExtras().getCharSequence(TOOLTIP_TEXT_KEY); |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the tooltip text of this node. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param tooltipText The tooltip text. |
| * |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setTooltipText(@Nullable CharSequence tooltipText) { |
| if (Build.VERSION.SDK_INT >= 28) { |
| mInfo.setTooltipText(tooltipText); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.getExtras().putCharSequence(TOOLTIP_TEXT_KEY, tooltipText); |
| } |
| } |
| |
| /** |
| * If this node represents a visually distinct region of the screen that may update separately |
| * from the rest of the window, it is considered a pane. Set the pane title to indicate that |
| * the node is a pane, and to provide a title for it. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * @param paneTitle The title of the window represented by this node. |
| */ |
| public void setPaneTitle(@Nullable CharSequence paneTitle) { |
| if (Build.VERSION.SDK_INT >= 28) { |
| mInfo.setPaneTitle(paneTitle); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.getExtras().putCharSequence(PANE_TITLE_KEY, paneTitle); |
| } |
| } |
| |
| /** |
| * Get the title of the pane represented by this node. |
| * |
| * @return The title of the pane represented by this node, or {@code null} if this node does |
| * not represent a pane. |
| */ |
| public @Nullable CharSequence getPaneTitle() { |
| if (Build.VERSION.SDK_INT >= 28) { |
| return mInfo.getPaneTitle(); |
| } else if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getExtras().getCharSequence(PANE_TITLE_KEY); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note |
| * that {@code false} indicates that it is not explicitly marked, not that the node is not |
| * a focusable unit. Screen readers should generally use other signals, such as |
| * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive |
| * focus. |
| * |
| * @return {@code true} if the node is specifically marked as a focusable unit for screen |
| * readers, {@code false} otherwise. |
| */ |
| public boolean isScreenReaderFocusable() { |
| if (Build.VERSION.SDK_INT >= 28) { |
| return mInfo.isScreenReaderFocusable(); |
| } |
| return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE); |
| } |
| |
| /** |
| * Sets whether the node should be considered a focusable unit by a screen reader. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers, |
| * {@code false} otherwise. |
| */ |
| public void setScreenReaderFocusable(boolean screenReaderFocusable) { |
| if (Build.VERSION.SDK_INT >= 28) { |
| mInfo.setScreenReaderFocusable(screenReaderFocusable); |
| } else { |
| setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable); |
| } |
| } |
| |
| /** |
| * Returns whether the node's text represents a hint for the user to enter text. It should only |
| * be {@code true} if the node has editable text. |
| * |
| * @return {@code true} if the text in the node represents a hint to the user, {@code false} |
| * otherwise. |
| */ |
| public boolean isShowingHintText() { |
| if (Build.VERSION.SDK_INT >= 26) { |
| return mInfo.isShowingHintText(); |
| } |
| return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT); |
| } |
| |
| /** |
| * Sets whether the node's text represents a hint for the user to enter text. It should only |
| * be {@code true} if the node has editable text. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param showingHintText {@code true} if the text in the node represents a hint to the user, |
| * {@code false} otherwise. |
| */ |
| public void setShowingHintText(boolean showingHintText) { |
| if (Build.VERSION.SDK_INT >= 26) { |
| mInfo.setShowingHintText(showingHintText); |
| } else { |
| setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText); |
| } |
| } |
| |
| /** |
| * Returns whether node represents a heading. |
| * <p><strong>Note:</strong> Returns {@code true} if either {@link #setHeading(boolean)} |
| * marks this node as a heading or if the node has a {@link CollectionItemInfoCompat} that marks |
| * it as such, to accomodate apps that use the now-deprecated API.</p> |
| * |
| * @return {@code true} if the node is a heading, {@code false} otherwise. |
| */ |
| @SuppressWarnings("deprecation") |
| public boolean isHeading() { |
| if (Build.VERSION.SDK_INT >= 28) { |
| return mInfo.isHeading(); |
| } |
| if (getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING)) return true; |
| CollectionItemInfoCompat collectionItemInfo = getCollectionItemInfo(); |
| return (collectionItemInfo != null) && collectionItemInfo.isHeading(); |
| } |
| |
| /** |
| * Sets whether the node represents a heading. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param isHeading {@code true} if the node is a heading, {@code false} otherwise. |
| */ |
| public void setHeading(boolean isHeading) { |
| if (Build.VERSION.SDK_INT >= 28) { |
| mInfo.setHeading(isHeading); |
| } else { |
| setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading); |
| } |
| } |
| |
| /** |
| * Returns whether node represents a text entry key that is part of a keyboard or keypad. |
| * |
| * @return {@code true} if the node is a text entry key, {@code false} otherwise. |
| */ |
| public boolean isTextEntryKey() { |
| if (Build.VERSION.SDK_INT >= 29) { |
| return mInfo.isTextEntryKey(); |
| } |
| return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY); |
| } |
| |
| /** |
| * Sets whether the node represents a text entry key that is part of a keyboard or keypad. |
| * <p>This method has no effect below API 19</p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param isTextEntryKey {@code true} if the node is a text entry key, {@code false} otherwise. |
| */ |
| public void setTextEntryKey(boolean isTextEntryKey) { |
| if (Build.VERSION.SDK_INT >= 29) { |
| mInfo.setTextEntryKey(isTextEntryKey); |
| } else { |
| setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY, isTextEntryKey); |
| } |
| } |
| |
| /** |
| * Refreshes this info with the latest state of the view it represents. |
| * <p> |
| * <strong>Note:</strong> If this method returns false this info is obsolete |
| * since it represents a view that is no longer in the view tree and should |
| * be recycled. |
| * </p> |
| * @return Whether the refresh succeeded. |
| */ |
| public boolean refresh() { |
| if (Build.VERSION.SDK_INT >= 18) { |
| return mInfo.refresh(); |
| } else { |
| return false; |
| } |
| } |
| |
| /** |
| * Gets the custom role description. |
| * @return The role description. |
| */ |
| public @Nullable CharSequence getRoleDescription() { |
| if (Build.VERSION.SDK_INT >= 19) { |
| return mInfo.getExtras().getCharSequence(ROLE_DESCRIPTION_KEY); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Sets the custom role description. |
| * |
| * <p> |
| * The role description allows you to customize the name for the view's semantic |
| * role. For example, if you create a custom subclass of {@link android.view.View} |
| * to display a menu bar, you could assign it the role description of "menu bar". |
| * </p> |
| * <p> |
| * <strong>Warning:</strong> For consistency with other applications, you should |
| * not use the role description to force accessibility services to describe |
| * standard views (such as buttons or checkboxes) using specific wording. For |
| * example, you should not set a role description of "check box" or "tick box" for |
| * a standard {@link android.widget.CheckBox}. Instead let accessibility services |
| * decide what feedback to provide. |
| * </p> |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an AccessibilityService. |
| * </p> |
| * |
| * @param roleDescription The role description. |
| */ |
| public void setRoleDescription(@Nullable CharSequence roleDescription) { |
| if (Build.VERSION.SDK_INT >= 19) { |
| mInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription); |
| } |
| } |
| |
| /** |
| * Get the {@link TouchDelegateInfoCompat} for touch delegate behavior with the represented |
| * view. It is possible for the same node to be pointed to by several regions. Use |
| * {@link TouchDelegateInfoCompat#getRegionAt(int)} to get touch delegate target |
| * {@link Region}, and {@link TouchDelegateInfoCompat#getTargetForRegion(Region)} |
| * for {@link AccessibilityNodeInfoCompat} from the given region. |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 29: Always returns {@code null}</li> |
| * </ul> |
| * |
| * @return {@link TouchDelegateInfoCompat} or {@code null} if there are no touch delegates |
| * in this node. |
| */ |
| @Nullable |
| public TouchDelegateInfoCompat getTouchDelegateInfo() { |
| if (Build.VERSION.SDK_INT >= 29) { |
| TouchDelegateInfo delegateInfo = mInfo.getTouchDelegateInfo(); |
| if (delegateInfo != null) { |
| return new TouchDelegateInfoCompat(delegateInfo); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Set touch delegate info if the represented view has a {@link android.view.TouchDelegate}. |
| * <p> |
| * <strong>Note:</strong> Cannot be called from an |
| * {@link android.accessibilityservice.AccessibilityService}. |
| * This class is made immutable before being delivered to an |
| * AccessibilityService. |
| * </p> |
| * <p> |
| * Compatibility: |
| * <ul> |
| * <li>API < 29: No-op</li> |
| * </ul> |
| * |
| * @param delegatedInfo {@link TouchDelegateInfoCompat} |
| * @throws IllegalStateException If called from an AccessibilityService. |
| */ |
| public void setTouchDelegateInfo(@NonNull TouchDelegateInfoCompat delegatedInfo) { |
| if (Build.VERSION.SDK_INT >= 29) { |
| mInfo.setTouchDelegateInfo(delegatedInfo.mInfo); |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| return (mInfo == null) ? 0 : mInfo.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (!(obj instanceof AccessibilityNodeInfoCompat)) { |
| return false; |
| } |
| AccessibilityNodeInfoCompat other = (AccessibilityNodeInfoCompat) obj; |
| if (mInfo == null) { |
| if (other.mInfo != null) { |
| return false; |
| } |
| } else if (!mInfo.equals(other.mInfo)) { |
| return false; |
| } |
| if (mVirtualDescendantId != other.mVirtualDescendantId) { |
| return false; |
| } |
| if (mParentVirtualDescendantId != other.mParentVirtualDescendantId) { |
| return false; |
| } |
| return true; |
| } |
| |
| @SuppressWarnings("deprecation") |
| @NonNull |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| builder.append(super.toString()); |
| |
| Rect bounds = new Rect(); |
| |
| getBoundsInParent(bounds); |
| builder.append("; boundsInParent: " + bounds); |
| |
| getBoundsInScreen(bounds); |
| builder.append("; boundsInScreen: " + bounds); |
| |
| builder.append("; packageName: ").append(getPackageName()); |
| builder.append("; className: ").append(getClassName()); |
| builder.append("; text: ").append(getText()); |
| builder.append("; contentDescription: ").append(getContentDescription()); |
| builder.append("; viewId: ").append(getViewIdResourceName()); |
| |
| builder.append("; checkable: ").append(isCheckable()); |
| builder.append("; checked: ").append(isChecked()); |
| builder.append("; focusable: ").append(isFocusable()); |
| builder.append("; focused: ").append(isFocused()); |
| builder.append("; selected: ").append(isSelected()); |
| builder.append("; clickable: ").append(isClickable()); |
| builder.append("; longClickable: ").append(isLongClickable()); |
| builder.append("; enabled: ").append(isEnabled()); |
| builder.append("; password: ").append(isPassword()); |
| builder.append("; scrollable: " + isScrollable()); |
| |
| builder.append("; ["); |
| if (Build.VERSION.SDK_INT >= 21) { |
| List<AccessibilityActionCompat> actions = getActionList(); |
| for (int i = 0; i < actions.size(); i++) { |
| AccessibilityActionCompat action = actions.get(i); |
| String actionName = getActionSymbolicName(action.getId()); |
| if (actionName.equals("ACTION_UNKNOWN") && action.getLabel() != null) { |
| actionName = action.getLabel().toString(); |
| } |
| builder.append(actionName); |
| if (i != actions.size() - 1) { |
| builder.append(", "); |
| } |
| } |
| } else { |
| for (int actionBits = getActions(); actionBits != 0;) { |
| final int action = 1 << Integer.numberOfTrailingZeros(actionBits); |
| actionBits &= ~action; |
| builder.append(getActionSymbolicName(action)); |
| if (actionBits != 0) { |
| builder.append(", "); |
| } |
| } |
| } |
| builder.append("]"); |
| |
| return builder.toString(); |
| } |
| |
| private void setBooleanProperty(int property, boolean value) { |
| Bundle extras = getExtras(); |
| if (extras != null) { |
| int booleanProperties = extras.getInt(BOOLEAN_PROPERTY_KEY, 0); |
| booleanProperties &= ~property; |
| booleanProperties |= value ? property : 0; |
| extras.putInt(BOOLEAN_PROPERTY_KEY, booleanProperties); |
| } |
| } |
| |
| private boolean getBooleanProperty(int property) { |
| Bundle extras = getExtras(); |
| if (extras == null) return false; |
| return (extras.getInt(BOOLEAN_PROPERTY_KEY, 0) & property) == property; |
| } |
| |
| private static String getActionSymbolicName(int action) { |
| switch (action) { |
| case ACTION_FOCUS: |
| return "ACTION_FOCUS"; |
| case ACTION_CLEAR_FOCUS: |
| return "ACTION_CLEAR_FOCUS"; |
| case ACTION_SELECT: |
| return "ACTION_SELECT"; |
| case ACTION_CLEAR_SELECTION: |
| return "ACTION_CLEAR_SELECTION"; |
| case ACTION_CLICK: |
| return "ACTION_CLICK"; |
| case ACTION_LONG_CLICK: |
| return "ACTION_LONG_CLICK"; |
| case ACTION_ACCESSIBILITY_FOCUS: |
| return "ACTION_ACCESSIBILITY_FOCUS"; |
| case ACTION_CLEAR_ACCESSIBILITY_FOCUS: |
| return "ACTION_CLEAR_ACCESSIBILITY_FOCUS"; |
| case ACTION_NEXT_AT_MOVEMENT_GRANULARITY: |
| return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY"; |
| case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: |
| return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY"; |
| case ACTION_NEXT_HTML_ELEMENT: |
| return "ACTION_NEXT_HTML_ELEMENT"; |
| case ACTION_PREVIOUS_HTML_ELEMENT: |
| return "ACTION_PREVIOUS_HTML_ELEMENT"; |
| case ACTION_SCROLL_FORWARD: |
| return "ACTION_SCROLL_FORWARD"; |
| case ACTION_SCROLL_BACKWARD: |
| return "ACTION_SCROLL_BACKWARD"; |
| case ACTION_CUT: |
| return "ACTION_CUT"; |
| case ACTION_COPY: |
| return "ACTION_COPY"; |
| case ACTION_PASTE: |
| return "ACTION_PASTE"; |
| case ACTION_SET_SELECTION: |
| return "ACTION_SET_SELECTION"; |
| case ACTION_EXPAND: |
| return "ACTION_EXPAND"; |
| case ACTION_COLLAPSE: |
| return "ACTION_COLLAPSE"; |
| case ACTION_SET_TEXT: |
| return "ACTION_SET_TEXT"; |
| case android.R.id.accessibilityActionScrollUp: |
| return "ACTION_SCROLL_UP"; |
| case android.R.id.accessibilityActionScrollLeft: |
| return "ACTION_SCROLL_LEFT"; |
| case android.R.id.accessibilityActionScrollDown: |
| return "ACTION_SCROLL_DOWN"; |
| case android.R.id.accessibilityActionScrollRight: |
| return "ACTION_SCROLL_RIGHT"; |
| case android.R.id.accessibilityActionPageDown: |
| return "ACTION_PAGE_DOWN"; |
| case android.R.id.accessibilityActionPageUp: |
| return "ACTION_PAGE_UP"; |
| case android.R.id.accessibilityActionPageLeft: |
| return "ACTION_PAGE_LEFT"; |
| case android.R.id.accessibilityActionPageRight: |
| return "ACTION_PAGE_RIGHT"; |
| case android.R.id.accessibilityActionShowOnScreen: |
| return "ACTION_SHOW_ON_SCREEN"; |
| case android.R.id.accessibilityActionScrollToPosition: |
| return "ACTION_SCROLL_TO_POSITION"; |
| case android.R.id.accessibilityActionContextClick: |
| return "ACTION_CONTEXT_CLICK"; |
| case android.R.id.accessibilityActionSetProgress: |
| return "ACTION_SET_PROGRESS"; |
| case android.R.id.accessibilityActionMoveWindow: |
| return "ACTION_MOVE_WINDOW"; |
| case android.R.id.accessibilityActionShowTooltip: |
| return "ACTION_SHOW_TOOLTIP"; |
| case android.R.id.accessibilityActionHideTooltip: |
| return "ACTION_HIDE_TOOLTIP"; |
| case android.R.id.accessibilityActionPressAndHold: |
| return "ACTION_PRESS_AND_HOLD"; |
| case android.R.id.accessibilityActionImeEnter: |
| return "ACTION_IME_ENTER"; |
| default: |
| return"ACTION_UNKNOWN"; |
| } |
| } |
| } |