Home | History | Annotate | Download | only in accessibility
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.core.view.accessibility;
     18 
     19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     20 
     21 import android.graphics.Rect;
     22 import android.os.Build;
     23 import android.os.Bundle;
     24 import android.text.InputType;
     25 import android.view.View;
     26 import android.view.accessibility.AccessibilityNodeInfo;
     27 
     28 import androidx.annotation.NonNull;
     29 import androidx.annotation.Nullable;
     30 import androidx.annotation.RestrictTo;
     31 import androidx.core.accessibilityservice.AccessibilityServiceInfoCompat;
     32 import androidx.core.os.BuildCompat;
     33 import androidx.core.view.ViewCompat;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.List;
     38 
     39 /**
     40  * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo} in a backwards
     41  * compatible fashion.
     42  */
     43 @SuppressWarnings("NewApi")
     44 public class AccessibilityNodeInfoCompat {
     45 
     46     public static class AccessibilityActionCompat {
     47 
     48         /**
     49          * Action that gives input focus to the node.
     50          */
     51         public static final AccessibilityActionCompat ACTION_FOCUS =
     52                 new AccessibilityActionCompat(
     53                         AccessibilityNodeInfoCompat.ACTION_FOCUS, null);
     54 
     55         /**
     56          * Action that clears input focus of the node.
     57          */
     58         public static final AccessibilityActionCompat ACTION_CLEAR_FOCUS =
     59                 new AccessibilityActionCompat(
     60                         AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS, null);
     61 
     62         /**
     63          *  Action that selects the node.
     64          */
     65         public static final AccessibilityActionCompat ACTION_SELECT =
     66                 new AccessibilityActionCompat(
     67                         AccessibilityNodeInfoCompat.ACTION_SELECT, null);
     68 
     69         /**
     70          * Action that deselects the node.
     71          */
     72         public static final AccessibilityActionCompat ACTION_CLEAR_SELECTION =
     73                 new AccessibilityActionCompat(
     74                         AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION, null);
     75 
     76         /**
     77          * Action that clicks on the node info.
     78          */
     79         public static final AccessibilityActionCompat ACTION_CLICK =
     80                 new AccessibilityActionCompat(
     81                         AccessibilityNodeInfoCompat.ACTION_CLICK, null);
     82 
     83         /**
     84          * Action that long clicks on the node.
     85          */
     86         public static final AccessibilityActionCompat ACTION_LONG_CLICK =
     87                 new AccessibilityActionCompat(
     88                         AccessibilityNodeInfoCompat.ACTION_LONG_CLICK, null);
     89 
     90         /**
     91          * Action that gives accessibility focus to the node.
     92          */
     93         public static final AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS =
     94                 new AccessibilityActionCompat(
     95                         AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null);
     96 
     97         /**
     98          * Action that clears accessibility focus of the node.
     99          */
    100         public static final AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS =
    101                 new AccessibilityActionCompat(
    102                         AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
    103 
    104         /**
    105          * Action that requests to go to the next entity in this node's text
    106          * at a given movement granularity. For example, move to the next character,
    107          * word, etc.
    108          * <p>
    109          * <strong>Arguments:</strong>
    110          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    111          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
    112          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    113          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    114          * <strong>Example:</strong> Move to the previous character and do not extend selection.
    115          * <code><pre><p>
    116          *   Bundle arguments = new Bundle();
    117          *   arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    118          *           AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER);
    119          *   arguments.putBoolean(
    120          *           AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false);
    121          *   info.performAction(
    122          *           AccessibilityActionCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(),
    123          *           arguments);
    124          * </code></pre></p>
    125          * </p>
    126          *
    127          * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    128          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    129          * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    130          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    131          *
    132          * @see AccessibilityNodeInfoCompat#setMovementGranularities(int)
    133          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    134          * @see AccessibilityNodeInfoCompat#getMovementGranularities()
    135          *  AccessibilityNodeInfoCompat.getMovementGranularities()
    136          *
    137          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_CHARACTER
    138          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER
    139          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_WORD
    140          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_WORD
    141          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_LINE
    142          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_LINE
    143          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PARAGRAPH
    144          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PARAGRAPH
    145          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PAGE
    146          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PAGE
    147          */
    148         public static final AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
    149                 new AccessibilityActionCompat(
    150                         AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
    151 
    152         /**
    153          * Action that requests to go to the previous entity in this node's text
    154          * at a given movement granularity. For example, move to the next character,
    155          * word, etc.
    156          * <p>
    157          * <strong>Arguments:</strong>
    158          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    159          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT},
    160          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    161          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    162          * <strong>Example:</strong> Move to the next character and do not extend selection.
    163          * <code><pre><p>
    164          *   Bundle arguments = new Bundle();
    165          *   arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    166          *           AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER);
    167          *   arguments.putBoolean(
    168          *           AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false);
    169          *   info.performAction(
    170          *           AccessibilityActionCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(),
    171          *           arguments);
    172          * </code></pre></p>
    173          * </p>
    174          *
    175          * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    176          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    177          * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    178          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    179          *
    180          * @see AccessibilityNodeInfoCompat#setMovementGranularities(int)
    181          *   AccessibilityNodeInfoCompat.setMovementGranularities(int)
    182          * @see AccessibilityNodeInfoCompat#getMovementGranularities()
    183          *  AccessibilityNodeInfoCompat.getMovementGranularities()
    184          *
    185          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_CHARACTER
    186          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER
    187          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_WORD
    188          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_WORD
    189          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_LINE
    190          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_LINE
    191          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PARAGRAPH
    192          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PARAGRAPH
    193          * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PAGE
    194          *  AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PAGE
    195          */
    196         public static final AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
    197                 new AccessibilityActionCompat(
    198                         AccessibilityNodeInfoCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
    199 
    200         /**
    201          * Action to move to the next HTML element of a given type. For example, move
    202          * to the BUTTON, INPUT, TABLE, etc.
    203          * <p>
    204          * <strong>Arguments:</strong>
    205          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_HTML_ELEMENT_STRING
    206          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    207          * <strong>Example:</strong>
    208          * <code><pre><p>
    209          *   Bundle arguments = new Bundle();
    210          *   arguments.putString(
    211          *           AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    212          *   info.performAction(
    213          *           AccessibilityActionCompat.ACTION_NEXT_HTML_ELEMENT.getId(), arguments);
    214          * </code></pre></p>
    215          * </p>
    216          */
    217         public static final AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT =
    218                 new AccessibilityActionCompat(
    219                         AccessibilityNodeInfoCompat.ACTION_NEXT_HTML_ELEMENT, null);
    220 
    221         /**
    222          * Action to move to the previous HTML element of a given type. For example, move
    223          * to the BUTTON, INPUT, TABLE, etc.
    224          * <p>
    225          * <strong>Arguments:</strong>
    226          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_HTML_ELEMENT_STRING
    227          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
    228          * <strong>Example:</strong>
    229          * <code><pre><p>
    230          *   Bundle arguments = new Bundle();
    231          *   arguments.putString(
    232          *           AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
    233          *   info.performAction(
    234          *           AccessibilityActionCompat.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments);
    235          * </code></pre></p>
    236          * </p>
    237          */
    238         public static final AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT =
    239                 new AccessibilityActionCompat(
    240                         AccessibilityNodeInfoCompat.ACTION_PREVIOUS_HTML_ELEMENT, null);
    241 
    242         /**
    243          * Action to scroll the node content forward.
    244          */
    245         public static final AccessibilityActionCompat ACTION_SCROLL_FORWARD =
    246                 new AccessibilityActionCompat(
    247                         AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null);
    248 
    249         /**
    250          * Action to scroll the node content backward.
    251          */
    252         public static final AccessibilityActionCompat ACTION_SCROLL_BACKWARD =
    253                 new AccessibilityActionCompat(
    254                         AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null);
    255 
    256         /**
    257          * Action to copy the current selection to the clipboard.
    258          */
    259         public static final AccessibilityActionCompat ACTION_COPY =
    260                 new AccessibilityActionCompat(
    261                         AccessibilityNodeInfoCompat.ACTION_COPY, null);
    262 
    263         /**
    264          * Action to paste the current clipboard content.
    265          */
    266         public static final AccessibilityActionCompat ACTION_PASTE =
    267                 new AccessibilityActionCompat(
    268                         AccessibilityNodeInfoCompat.ACTION_PASTE, null);
    269 
    270         /**
    271          * Action to cut the current selection and place it to the clipboard.
    272          */
    273         public static final AccessibilityActionCompat ACTION_CUT =
    274                 new AccessibilityActionCompat(
    275                         AccessibilityNodeInfoCompat.ACTION_CUT, null);
    276 
    277         /**
    278          * Action to set the selection. Performing this action with no arguments
    279          * clears the selection.
    280          * <p>
    281          * <strong>Arguments:</strong>
    282          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_START_INT
    283          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT},
    284          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_END_INT
    285          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT}<br>
    286          * <strong>Example:</strong>
    287          * <code><pre><p>
    288          *   Bundle arguments = new Bundle();
    289          *   arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, 1);
    290          *   arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, 2);
    291          *   info.performAction(AccessibilityActionCompat.ACTION_SET_SELECTION.getId(), arguments);
    292          * </code></pre></p>
    293          * </p>
    294          *
    295          * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_START_INT
    296          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT
    297          * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_END_INT
    298          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT
    299          */
    300         public static final AccessibilityActionCompat ACTION_SET_SELECTION =
    301                 new AccessibilityActionCompat(
    302                         AccessibilityNodeInfoCompat.ACTION_SET_SELECTION, null);
    303 
    304         /**
    305          * Action to expand an expandable node.
    306          */
    307         public static final AccessibilityActionCompat ACTION_EXPAND =
    308                 new AccessibilityActionCompat(
    309                         AccessibilityNodeInfoCompat.ACTION_EXPAND, null);
    310 
    311         /**
    312          * Action to collapse an expandable node.
    313          */
    314         public static final AccessibilityActionCompat ACTION_COLLAPSE =
    315                 new AccessibilityActionCompat(
    316                         AccessibilityNodeInfoCompat.ACTION_COLLAPSE, null);
    317 
    318         /**
    319          * Action to dismiss a dismissable node.
    320          */
    321         public static final AccessibilityActionCompat ACTION_DISMISS =
    322                 new AccessibilityActionCompat(
    323                         AccessibilityNodeInfoCompat.ACTION_DISMISS, null);
    324 
    325         /**
    326          * Action that sets the text of the node. Performing the action without argument,
    327          * using <code> null</code> or empty {@link CharSequence} will clear the text. This
    328          * action will also put the cursor at the end of text.
    329          * <p>
    330          * <strong>Arguments:</strong>
    331          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
    332          *  AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
    333          * <strong>Example:</strong>
    334          * <code><pre><p>
    335          *   Bundle arguments = new Bundle();
    336          *   arguments.putCharSequence(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
    337          *       "android");
    338          *   info.performAction(AccessibilityActionCompat.ACTION_SET_TEXT.getId(), arguments);
    339          * </code></pre></p>
    340          */
    341         public static final AccessibilityActionCompat ACTION_SET_TEXT =
    342                 new AccessibilityActionCompat(
    343                         AccessibilityNodeInfoCompat.ACTION_SET_TEXT, null);
    344 
    345         /**
    346          * Action that requests the node make its bounding rectangle visible
    347          * on the screen, scrolling if necessary just enough.
    348          *
    349          * @see View#requestRectangleOnScreen(Rect)
    350          */
    351         public static final AccessibilityActionCompat ACTION_SHOW_ON_SCREEN =
    352                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    353                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN : null);
    354 
    355         /**
    356          * Action that scrolls the node to make the specified collection
    357          * position visible on screen.
    358          * <p>
    359          * <strong>Arguments:</strong>
    360          * <ul>
    361          *     <li>{@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_ROW_INT}</li>
    362          *     <li>{@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_COLUMN_INT}</li>
    363          * <ul>
    364          *
    365          * @see AccessibilityNodeInfoCompat#getCollectionInfo()
    366          */
    367         public static final AccessibilityActionCompat ACTION_SCROLL_TO_POSITION =
    368                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    369                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_TO_POSITION
    370                         : null);
    371 
    372         /**
    373          * Action to scroll the node content up.
    374          */
    375         public static final AccessibilityActionCompat ACTION_SCROLL_UP =
    376                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    377                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP : null);
    378 
    379         /**
    380          * Action to scroll the node content left.
    381          */
    382         public static final AccessibilityActionCompat ACTION_SCROLL_LEFT =
    383                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    384                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_LEFT : null);
    385 
    386         /**
    387          * Action to scroll the node content down.
    388          */
    389         public static final AccessibilityActionCompat ACTION_SCROLL_DOWN =
    390                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    391                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN : null);
    392 
    393         /**
    394          * Action to scroll the node content right.
    395          */
    396         public static final AccessibilityActionCompat ACTION_SCROLL_RIGHT =
    397                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    398                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_RIGHT : null);
    399 
    400         /**
    401          * Action that context clicks the node.
    402          */
    403         public static final AccessibilityActionCompat ACTION_CONTEXT_CLICK =
    404                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23
    405                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK : null);
    406 
    407         /**
    408          * Action that sets progress between {@link  RangeInfoCompat#getMin() RangeInfo.getMin()} and
    409          * {@link  RangeInfoCompat#getMax() RangeInfo.getMax()}. It should use the same value type as
    410          * {@link RangeInfoCompat#getType() RangeInfo.getType()}
    411          * <p>
    412          * <strong>Arguments:</strong>
    413          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_PROGRESS_VALUE}
    414          *
    415          * @see RangeInfoCompat
    416          */
    417         public static final AccessibilityActionCompat ACTION_SET_PROGRESS =
    418                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 24
    419                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS : null);
    420 
    421         /**
    422          * Action to move a window to a new location.
    423          * <p>
    424          * <strong>Arguments:</strong>
    425          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_X}
    426          * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_Y}
    427          */
    428         public static final AccessibilityActionCompat ACTION_MOVE_WINDOW =
    429                 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 26
    430                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_MOVE_WINDOW : null);
    431 
    432         /**
    433          * Action to show a tooltip.
    434          */
    435         public static final AccessibilityActionCompat ACTION_SHOW_TOOLTIP =
    436                 new AccessibilityActionCompat(BuildCompat.isAtLeastP()
    437                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP : null);
    438 
    439         /**
    440          * Action to hide a tooltip. A node should expose this action only for views that are
    441          * currently showing a tooltip.
    442          */
    443         public static final AccessibilityActionCompat ACTION_HIDE_TOOLTIP =
    444                 new AccessibilityActionCompat(BuildCompat.isAtLeastP()
    445                         ? AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP : null);
    446 
    447         final Object mAction;
    448 
    449         /**
    450          * Creates a new instance.
    451          *
    452          * @param actionId The action id.
    453          * @param label The action label.
    454          */
    455         public AccessibilityActionCompat(int actionId, CharSequence label) {
    456             this(Build.VERSION.SDK_INT >= 21
    457                     ? new AccessibilityNodeInfo.AccessibilityAction(actionId, label) : null);
    458         }
    459 
    460         AccessibilityActionCompat(Object action) {
    461             mAction = action;
    462         }
    463 
    464         /**
    465          * Gets the id for this action.
    466          *
    467          * @return The action id.
    468          */
    469         public int getId() {
    470             if (Build.VERSION.SDK_INT >= 21) {
    471                 return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getId();
    472             } else {
    473                 return 0;
    474             }
    475         }
    476 
    477         /**
    478          * Gets the label for this action. Its purpose is to describe the
    479          * action to user.
    480          *
    481          * @return The label.
    482          */
    483         public CharSequence getLabel() {
    484             if (Build.VERSION.SDK_INT >= 21) {
    485                 return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getLabel();
    486             } else {
    487                 return null;
    488             }
    489         }
    490     }
    491 
    492     /**
    493      * Class with information if a node is a collection.
    494      * <p>
    495      * A collection of items has rows and columns and may be hierarchical.
    496      * For example, a horizontal list is a collection with one column, as
    497      * many rows as the list items, and is not hierarchical; A table is a
    498      * collection with several rows, several columns, and is not hierarchical;
    499      * A vertical tree is a hierarchical collection with one column and
    500      * as many rows as the first level children.
    501      * </p>
    502      */
    503     public static class CollectionInfoCompat {
    504         /** Selection mode where items are not selectable. */
    505         public static final int SELECTION_MODE_NONE = 0;
    506 
    507         /** Selection mode where a single item may be selected. */
    508         public static final int SELECTION_MODE_SINGLE = 1;
    509 
    510         /** Selection mode where multiple items may be selected. */
    511         public static final int SELECTION_MODE_MULTIPLE = 2;
    512 
    513         final Object mInfo;
    514 
    515         /**
    516          * Returns a cached instance if such is available otherwise a new one.
    517          *
    518          * @param rowCount The number of rows.
    519          * @param columnCount The number of columns.
    520          * @param hierarchical Whether the collection is hierarchical.
    521          * @param selectionMode The collection's selection mode, one of:
    522          *            <ul>
    523          *            <li>{@link #SELECTION_MODE_NONE}
    524          *            <li>{@link #SELECTION_MODE_SINGLE}
    525          *            <li>{@link #SELECTION_MODE_MULTIPLE}
    526          *            </ul>
    527          *
    528          * @return An instance.
    529          */
    530         public static CollectionInfoCompat obtain(int rowCount, int columnCount,
    531                 boolean hierarchical, int selectionMode) {
    532             if (Build.VERSION.SDK_INT >= 21) {
    533                 return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
    534                         rowCount, columnCount, hierarchical, selectionMode));
    535             } else if (Build.VERSION.SDK_INT >= 19) {
    536                 return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
    537                         rowCount, columnCount, hierarchical));
    538             } else {
    539                 return new CollectionInfoCompat(null);
    540             }
    541         }
    542 
    543         /**
    544          * Returns a cached instance if such is available otherwise a new one.
    545          *
    546          * @param rowCount The number of rows.
    547          * @param columnCount The number of columns.
    548          * @param hierarchical Whether the collection is hierarchical.
    549          *
    550          * @return An instance.
    551          */
    552         public static CollectionInfoCompat obtain(int rowCount, int columnCount,
    553                 boolean hierarchical) {
    554             if (Build.VERSION.SDK_INT >= 19) {
    555                 return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain(
    556                         rowCount, columnCount, hierarchical));
    557             } else {
    558                 return new CollectionInfoCompat(null);
    559             }
    560         }
    561 
    562         CollectionInfoCompat(Object info) {
    563             mInfo = info;
    564         }
    565 
    566         /**
    567          * Gets the number of columns.
    568          *
    569          * @return The column count.
    570          */
    571         public int getColumnCount() {
    572             if (Build.VERSION.SDK_INT >= 19) {
    573                 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getColumnCount();
    574             } else {
    575                 return 0;
    576             }
    577         }
    578 
    579         /**
    580          * Gets the number of rows.
    581          *
    582          * @return The row count.
    583          */
    584         public int getRowCount() {
    585             if (Build.VERSION.SDK_INT >= 19) {
    586                 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getRowCount();
    587             } else {
    588                 return 0;
    589             }
    590         }
    591 
    592         /**
    593          * Gets if the collection is a hierarchically ordered.
    594          *
    595          * @return Whether the collection is hierarchical.
    596          */
    597         public boolean isHierarchical() {
    598             if (Build.VERSION.SDK_INT >= 19) {
    599                 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).isHierarchical();
    600             } else {
    601                 return false;
    602             }
    603         }
    604 
    605         /**
    606          * Gets the collection's selection mode.
    607          *
    608          * @return The collection's selection mode, one of:
    609          *         <ul>
    610          *         <li>{@link #SELECTION_MODE_NONE}
    611          *         <li>{@link #SELECTION_MODE_SINGLE}
    612          *         <li>{@link #SELECTION_MODE_MULTIPLE}
    613          *         </ul>
    614          */
    615         public int getSelectionMode() {
    616             if (Build.VERSION.SDK_INT >= 21) {
    617                 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getSelectionMode();
    618             } else {
    619                 return 0;
    620             }
    621         }
    622     }
    623 
    624     /**
    625      * Class with information if a node is a collection item.
    626      * <p>
    627      * A collection item is contained in a collection, it starts at
    628      * a given row and column in the collection, and spans one or
    629      * more rows and columns. For example, a header of two related
    630      * table columns starts at the first row and the first column,
    631      * spans one row and two columns.
    632      * </p>
    633      */
    634     public static class CollectionItemInfoCompat {
    635 
    636         final Object mInfo;
    637 
    638         /**
    639          * Returns a cached instance if such is available otherwise a new one.
    640          *
    641          * @param rowIndex The row index at which the item is located.
    642          * @param rowSpan The number of rows the item spans.
    643          * @param columnIndex The column index at which the item is located.
    644          * @param columnSpan The number of columns the item spans.
    645          * @param heading Whether the item is a heading. This should be set to false and the newer
    646          *                {@link AccessibilityNodeInfoCompat#setHeading(boolean)} used to identify
    647          *                headings.
    648          * @param selected Whether the item is selected.
    649          * @return An instance.
    650          */
    651         public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan,
    652                 int columnIndex, int columnSpan, boolean heading, boolean selected) {
    653             if (Build.VERSION.SDK_INT >= 21) {
    654                 return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
    655                         rowIndex, rowSpan, columnIndex, columnSpan, heading, selected));
    656             } else if (Build.VERSION.SDK_INT >= 19) {
    657                 return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
    658                         rowIndex, rowSpan, columnIndex, columnSpan, heading));
    659             } else {
    660                 return new CollectionItemInfoCompat(null);
    661             }
    662         }
    663 
    664         /**
    665          * Returns a cached instance if such is available otherwise a new one.
    666          *
    667          * @param rowIndex The row index at which the item is located.
    668          * @param rowSpan The number of rows the item spans.
    669          * @param columnIndex The column index at which the item is located.
    670          * @param columnSpan The number of columns the item spans.
    671          * @param heading Whether the item is a heading. This should be set to false and the newer
    672          *                {@link AccessibilityNodeInfoCompat#setHeading(boolean)} used to identify
    673          *                headings.
    674          * @return An instance.
    675          */
    676         public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan,
    677                 int columnIndex, int columnSpan, boolean heading) {
    678             if (Build.VERSION.SDK_INT >= 19) {
    679                 return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain(
    680                         rowIndex, rowSpan, columnIndex, columnSpan, heading));
    681             } else {
    682                 return new CollectionItemInfoCompat(null);
    683             }
    684         }
    685 
    686         CollectionItemInfoCompat(Object info) {
    687             mInfo = info;
    688         }
    689 
    690         /**
    691          * Gets the column index at which the item is located.
    692          *
    693          * @return The column index.
    694          */
    695         public int getColumnIndex() {
    696             if (Build.VERSION.SDK_INT >= 19) {
    697                 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnIndex();
    698             } else {
    699                 return 0;
    700             }
    701         }
    702 
    703         /**
    704          * Gets the number of columns the item spans.
    705          *
    706          * @return The column span.
    707          */
    708         public int getColumnSpan() {
    709             if (Build.VERSION.SDK_INT >= 19) {
    710                 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnSpan();
    711             } else {
    712                 return 0;
    713             }
    714         }
    715 
    716         /**
    717          * Gets the row index at which the item is located.
    718          *
    719          * @return The row index.
    720          */
    721         public int getRowIndex() {
    722             if (Build.VERSION.SDK_INT >= 19) {
    723                 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowIndex();
    724             } else {
    725                 return 0;
    726             }
    727         }
    728 
    729         /**
    730          * Gets the number of rows the item spans.
    731          *
    732          * @return The row span.
    733          */
    734         public int getRowSpan() {
    735             if (Build.VERSION.SDK_INT >= 19) {
    736                 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowSpan();
    737             } else {
    738                 return 0;
    739             }
    740         }
    741 
    742         /**
    743          * Gets if the collection item is a heading. For example, section
    744          * heading, table header, etc.
    745          *
    746          * @return If the item is a heading.
    747          * @deprecated Use {@link AccessibilityNodeInfoCompat#isHeading()}
    748          */
    749         public boolean isHeading() {
    750             if (Build.VERSION.SDK_INT >= 19) {
    751                 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isHeading();
    752             } else {
    753                 return false;
    754             }
    755         }
    756 
    757         /**
    758          * Gets if the collection item is selected.
    759          *
    760          * @return If the item is selected.
    761          */
    762         public boolean isSelected() {
    763             if (Build.VERSION.SDK_INT >= 21) {
    764                 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isSelected();
    765             } else {
    766                 return false;
    767             }
    768         }
    769     }
    770 
    771     /**
    772      * Class with information if a node is a range.
    773      */
    774     public static class RangeInfoCompat {
    775         /** Range type: integer. */
    776         public static final int RANGE_TYPE_INT = 0;
    777         /** Range type: float. */
    778         public static final int RANGE_TYPE_FLOAT = 1;
    779         /** Range type: percent with values from zero to one.*/
    780         public static final int RANGE_TYPE_PERCENT = 2;
    781 
    782         /**
    783          * Obtains a cached instance if such is available otherwise a new one.
    784          *
    785          * @param type The type of the range.
    786          * @param min The min value.
    787          * @param max The max value.
    788          * @param current The current value.
    789          * @return The instance
    790          */
    791         public static RangeInfoCompat obtain(int type, float min, float max, float current) {
    792             if (Build.VERSION.SDK_INT >= 19) {
    793                 return new RangeInfoCompat(
    794                         AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current));
    795             } else {
    796                 return new RangeInfoCompat(null);
    797             }
    798         }
    799 
    800         final Object mInfo;
    801 
    802         RangeInfoCompat(Object info) {
    803             mInfo = info;
    804         }
    805 
    806         /**
    807          * Gets the current value.
    808          *
    809          * @return The current value.
    810          */
    811         public float getCurrent() {
    812             if (Build.VERSION.SDK_INT >= 19) {
    813                 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getCurrent();
    814             } else {
    815                 return 0;
    816             }
    817         }
    818 
    819         /**
    820          * Gets the max value.
    821          *
    822          * @return The max value.
    823          */
    824         public float getMax() {
    825             if (Build.VERSION.SDK_INT >= 19) {
    826                 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMax();
    827             } else {
    828                 return 0;
    829             }
    830         }
    831 
    832         /**
    833          * Gets the min value.
    834          *
    835          * @return The min value.
    836          */
    837         public float getMin() {
    838             if (Build.VERSION.SDK_INT >= 19) {
    839                 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMin();
    840             } else {
    841                 return 0;
    842             }
    843         }
    844 
    845         /**
    846          * Gets the range type.
    847          *
    848          * @return The range type.
    849          *
    850          * @see #RANGE_TYPE_INT
    851          * @see #RANGE_TYPE_FLOAT
    852          * @see #RANGE_TYPE_PERCENT
    853          */
    854         public int getType() {
    855             if (Build.VERSION.SDK_INT >= 19) {
    856                 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getType();
    857             } else {
    858                 return RANGE_TYPE_INT;
    859             }
    860         }
    861     }
    862 
    863     private static final String ROLE_DESCRIPTION_KEY =
    864             "AccessibilityNodeInfo.roleDescription";
    865 
    866     private static final String PANE_TITLE_KEY =
    867             "androidx.view.accessibility.AccessibilityNodeInfoCompat.PANE_TITLE_KEY";
    868 
    869     private static final String TOOLTIP_TEXT_KEY =
    870             "androidx.view.accessibility.AccessibilityNodeInfoCompat.TOOLTIP_TEXT_KEY";
    871 
    872     private static final String HINT_TEXT_KEY =
    873             "androidx.view.accessibility.AccessibilityNodeInfoCompat.HINT_TEXT_KEY";
    874 
    875     private static final String BOOLEAN_PROPERTY_KEY =
    876             "androidx.view.accessibility.AccessibilityNodeInfoCompat.BOOLEAN_PROPERTY_KEY";
    877 
    878     // These don't line up with the internal framework constants, since they are independent
    879     // and we might as well get all 32 bits of utility here.
    880     private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x00000001;
    881     private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x00000002;
    882     private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x00000004;
    883 
    884     private final AccessibilityNodeInfo mInfo;
    885 
    886     /**
    887      *  androidx.customview.widget.ExploreByTouchHelper.HOST_ID = -1;
    888      *
    889      *  @hide
    890      */
    891     @RestrictTo(LIBRARY_GROUP)
    892     public int mParentVirtualDescendantId = -1;
    893 
    894     // Actions introduced in IceCreamSandwich
    895 
    896     /**
    897      * Action that focuses the node.
    898      */
    899     public static final int ACTION_FOCUS = 0x00000001;
    900 
    901     /**
    902      * Action that unfocuses the node.
    903      */
    904     public static final int ACTION_CLEAR_FOCUS = 0x00000002;
    905 
    906     /**
    907      * Action that selects the node.
    908      */
    909     public static final int ACTION_SELECT = 0x00000004;
    910 
    911     /**
    912      * Action that unselects the node.
    913      */
    914     public static final int ACTION_CLEAR_SELECTION = 0x00000008;
    915 
    916     /**
    917      * Action that clicks on the node info.
    918      */
    919     public static final int ACTION_CLICK = 0x00000010;
    920 
    921     /**
    922      * Action that long clicks on the node.
    923      */
    924     public static final int ACTION_LONG_CLICK = 0x00000020;
    925 
    926     // Actions introduced in JellyBean
    927 
    928     /**
    929      * Action that gives accessibility focus to the node.
    930      */
    931     public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040;
    932 
    933     /**
    934      * Action that clears accessibility focus of the node.
    935      */
    936     public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080;
    937 
    938     /**
    939      * Action that requests to go to the next entity in this node's text
    940      * at a given movement granularity. For example, move to the next character,
    941      * word, etc.
    942      * <p>
    943      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    944      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    945      * <strong>Example:</strong> Move to the previous character and do not extend selection.
    946      * <code><pre><p>
    947      *   Bundle arguments = new Bundle();
    948      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    949      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    950      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    951      *           false);
    952      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
    953      * </code></pre></p>
    954      * </p>
    955      *
    956      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    957      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    958      *
    959      * @see #setMovementGranularities(int)
    960      * @see #getMovementGranularities()
    961      *
    962      * @see #MOVEMENT_GRANULARITY_CHARACTER
    963      * @see #MOVEMENT_GRANULARITY_WORD
    964      * @see #MOVEMENT_GRANULARITY_LINE
    965      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    966      * @see #MOVEMENT_GRANULARITY_PAGE
    967      */
    968     public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100;
    969 
    970     /**
    971      * Action that requests to go to the previous entity in this node's text
    972      * at a given movement granularity. For example, move to the next character,
    973      * word, etc.
    974      * <p>
    975      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
    976      * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br>
    977      * <strong>Example:</strong> Move to the next character and do not extend selection.
    978      * <code><pre><p>
    979      *   Bundle arguments = new Bundle();
    980      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
    981      *           AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
    982      *   arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
    983      *           false);
    984      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
    985      *           arguments);
    986      * </code></pre></p>
    987      * </p>
    988      *
    989      * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
    990      * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
    991      *
    992      * @see #setMovementGranularities(int)
    993      * @see #getMovementGranularities()
    994      *
    995      * @see #MOVEMENT_GRANULARITY_CHARACTER
    996      * @see #MOVEMENT_GRANULARITY_WORD
    997      * @see #MOVEMENT_GRANULARITY_LINE
    998      * @see #MOVEMENT_GRANULARITY_PARAGRAPH
    999      * @see #MOVEMENT_GRANULARITY_PAGE
   1000      */
   1001     public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200;
   1002 
   1003     /**
   1004      * Action to move to the next HTML element of a given type. For example, move
   1005      * to the BUTTON, INPUT, TABLE, etc.
   1006      * <p>
   1007      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
   1008      * <strong>Example:</strong>
   1009      * <code><pre><p>
   1010      *   Bundle arguments = new Bundle();
   1011      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
   1012      *   info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments);
   1013      * </code></pre></p>
   1014      * </p>
   1015      */
   1016     public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400;
   1017 
   1018     /**
   1019      * Action to move to the previous HTML element of a given type. For example, move
   1020      * to the BUTTON, INPUT, TABLE, etc.
   1021      * <p>
   1022      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br>
   1023      * <strong>Example:</strong>
   1024      * <code><pre><p>
   1025      *   Bundle arguments = new Bundle();
   1026      *   arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON");
   1027      *   info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments);
   1028      * </code></pre></p>
   1029      * </p>
   1030      */
   1031     public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800;
   1032 
   1033     /**
   1034      * Action to scroll the node content forward.
   1035      */
   1036     public static final int ACTION_SCROLL_FORWARD = 0x00001000;
   1037 
   1038     /**
   1039      * Action to scroll the node content backward.
   1040      */
   1041     public static final int ACTION_SCROLL_BACKWARD = 0x00002000;
   1042 
   1043     // Actions introduced in JellyBeanMr2
   1044 
   1045     /**
   1046      * Action to copy the current selection to the clipboard.
   1047      */
   1048     public static final int ACTION_COPY = 0x00004000;
   1049 
   1050     /**
   1051      * Action to paste the current clipboard content.
   1052      */
   1053     public static final int ACTION_PASTE = 0x00008000;
   1054 
   1055     /**
   1056      * Action to cut the current selection and place it to the clipboard.
   1057      */
   1058     public static final int ACTION_CUT = 0x00010000;
   1059 
   1060     /**
   1061      * Action to set the selection. Performing this action with no arguments
   1062      * clears the selection.
   1063      * <p>
   1064      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT},
   1065      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
   1066      * <strong>Example:</strong>
   1067      * <code><pre><p>
   1068      *   Bundle arguments = new Bundle();
   1069      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
   1070      *   arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
   1071      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
   1072      * </code></pre></p>
   1073      * </p>
   1074      *
   1075      * @see #ACTION_ARGUMENT_SELECTION_START_INT
   1076      * @see #ACTION_ARGUMENT_SELECTION_END_INT
   1077      */
   1078     public static final int ACTION_SET_SELECTION = 0x00020000;
   1079 
   1080     /**
   1081      * Action to expand an expandable node.
   1082      */
   1083     public static final int ACTION_EXPAND = 0x00040000;
   1084 
   1085     /**
   1086      * Action to collapse an expandable node.
   1087      */
   1088     public static final int ACTION_COLLAPSE = 0x00080000;
   1089 
   1090     /**
   1091      * Action to dismiss a dismissable node.
   1092      */
   1093     public static final int ACTION_DISMISS = 0x00100000;
   1094 
   1095     /**
   1096      * Action that sets the text of the node. Performing the action without argument, using <code>
   1097      * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
   1098      * cursor at the end of text.
   1099      * <p>
   1100      * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
   1101      * <strong>Example:</strong>
   1102      * <code><pre><p>
   1103      *   Bundle arguments = new Bundle();
   1104      *   arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
   1105      *       "android");
   1106      *   info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
   1107      * </code></pre></p>
   1108      */
   1109     public static final int ACTION_SET_TEXT = 0x00200000;
   1110 
   1111     // Action arguments
   1112 
   1113     /**
   1114      * Argument for which movement granularity to be used when traversing the node text.
   1115      * <p>
   1116      * <strong>Type:</strong> int<br>
   1117      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
   1118      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
   1119      * </p>
   1120      */
   1121     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
   1122         "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
   1123 
   1124     /**
   1125      * Argument for which HTML element to get moving to the next/previous HTML element.
   1126      * <p>
   1127      * <strong>Type:</strong> String<br>
   1128      * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
   1129      *         {@link #ACTION_PREVIOUS_HTML_ELEMENT}
   1130      * </p>
   1131      */
   1132     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
   1133         "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
   1134 
   1135     /**
   1136      * Argument for whether when moving at granularity to extend the selection
   1137      * or to move it otherwise.
   1138      * <p>
   1139      * <strong>Type:</strong> boolean<br>
   1140      * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
   1141      * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
   1142      * </p>
   1143      *
   1144      * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
   1145      * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
   1146      */
   1147     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
   1148             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
   1149 
   1150     /**
   1151      * Argument for specifying the selection start.
   1152      * <p>
   1153      * <strong>Type:</strong> int<br>
   1154      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
   1155      * </p>
   1156      *
   1157      * @see #ACTION_SET_SELECTION
   1158      */
   1159     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
   1160             "ACTION_ARGUMENT_SELECTION_START_INT";
   1161 
   1162     /**
   1163      * Argument for specifying the selection end.
   1164      * <p>
   1165      * <strong>Type:</strong> int<br>
   1166      * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
   1167      * </p>
   1168      *
   1169      * @see #ACTION_SET_SELECTION
   1170      */
   1171     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
   1172             "ACTION_ARGUMENT_SELECTION_END_INT";
   1173 
   1174     /**
   1175      * Argument for specifying the text content to set
   1176      * <p>
   1177      * <strong>Type:</strong> CharSequence<br>
   1178      * <strong>Actions:</strong> {@link #ACTION_SET_TEXT}
   1179      * </p>
   1180      *
   1181      * @see #ACTION_SET_TEXT
   1182      */
   1183     public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
   1184             "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
   1185 
   1186     /**
   1187      * Argument for specifying the collection row to make visible on screen.
   1188      * <p>
   1189      * <strong>Type:</strong> int<br>
   1190      * <strong>Actions:</strong>
   1191      * <ul>
   1192      *     <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li>
   1193      * </ul>
   1194      *
   1195      * @see AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION
   1196      */
   1197     public static final String ACTION_ARGUMENT_ROW_INT =
   1198             "android.view.accessibility.action.ARGUMENT_ROW_INT";
   1199 
   1200     /**
   1201      * Argument for specifying the collection column to make visible on screen.
   1202      * <p>
   1203      * <strong>Type:</strong> int<br>
   1204      * <strong>Actions:</strong>
   1205      * <ul>
   1206      *     <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li>
   1207      * </ul>
   1208      *
   1209      * @see AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION
   1210      */
   1211     public static final String ACTION_ARGUMENT_COLUMN_INT =
   1212             "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
   1213 
   1214     /**
   1215      * Argument for specifying the progress value to set.
   1216      * <p>
   1217      * <strong>Type:</strong> float<br>
   1218      * <strong>Actions:</strong>
   1219      * <ul>
   1220      *     <li>{@link AccessibilityActionCompat#ACTION_SET_PROGRESS}</li>
   1221      * </ul>
   1222      *
   1223      * @see AccessibilityActionCompat#ACTION_SET_PROGRESS
   1224      */
   1225     public static final String ACTION_ARGUMENT_PROGRESS_VALUE =
   1226             "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
   1227 
   1228     /**
   1229      * Argument for specifying the x coordinate to which to move a window.
   1230      * <p>
   1231      * <strong>Type:</strong> int<br>
   1232      * <strong>Actions:</strong>
   1233      * <ul>
   1234      *     <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li>
   1235      * </ul>
   1236      *
   1237      * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW
   1238      */
   1239     public static final String ACTION_ARGUMENT_MOVE_WINDOW_X =
   1240             "ACTION_ARGUMENT_MOVE_WINDOW_X";
   1241 
   1242     /**
   1243      * Argument for specifying the y coordinate to which to move a window.
   1244      * <p>
   1245      * <strong>Type:</strong> int<br>
   1246      * <strong>Actions:</strong>
   1247      * <ul>
   1248      *     <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li>
   1249      * </ul>
   1250      *
   1251      * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW
   1252      */
   1253     public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y =
   1254             "ACTION_ARGUMENT_MOVE_WINDOW_Y";
   1255 
   1256     // Focus types
   1257 
   1258     /**
   1259      * The input focus.
   1260      */
   1261     public static final int FOCUS_INPUT = 1;
   1262 
   1263     /**
   1264      * The accessibility focus.
   1265      */
   1266     public static final int FOCUS_ACCESSIBILITY = 2;
   1267 
   1268     // Movement granularities
   1269 
   1270     /**
   1271      * Movement granularity bit for traversing the text of a node by character.
   1272      */
   1273     public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001;
   1274 
   1275     /**
   1276      * Movement granularity bit for traversing the text of a node by word.
   1277      */
   1278     public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002;
   1279 
   1280     /**
   1281      * Movement granularity bit for traversing the text of a node by line.
   1282      */
   1283     public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004;
   1284 
   1285     /**
   1286      * Movement granularity bit for traversing the text of a node by paragraph.
   1287      */
   1288     public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008;
   1289 
   1290     /**
   1291      * Movement granularity bit for traversing the text of a node by page.
   1292      */
   1293     public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010;
   1294 
   1295     /**
   1296      * Creates a wrapper for info implementation.
   1297      *
   1298      * @param object The info to wrap.
   1299      * @return A wrapper for if the object is not null, null otherwise.
   1300      */
   1301     static AccessibilityNodeInfoCompat wrapNonNullInstance(Object object) {
   1302         if (object != null) {
   1303             return new AccessibilityNodeInfoCompat(object);
   1304         }
   1305         return null;
   1306     }
   1307 
   1308     /**
   1309      * Creates a new instance wrapping an
   1310      * {@link android.view.accessibility.AccessibilityNodeInfo}.
   1311      *
   1312      * @param info The info.
   1313      *
   1314      * @deprecated Use {@link #wrap(AccessibilityNodeInfo)} instead.
   1315      */
   1316     @Deprecated
   1317     public AccessibilityNodeInfoCompat(Object info) {
   1318         mInfo = (AccessibilityNodeInfo) info;
   1319     }
   1320 
   1321     private AccessibilityNodeInfoCompat(AccessibilityNodeInfo info) {
   1322         mInfo = info;
   1323     }
   1324 
   1325     /**
   1326      * Creates a new instance wrapping an
   1327      * {@link android.view.accessibility.AccessibilityNodeInfo}.
   1328      *
   1329      * @param info The info.
   1330      */
   1331     public static AccessibilityNodeInfoCompat wrap(@NonNull AccessibilityNodeInfo info) {
   1332         return new AccessibilityNodeInfoCompat(info);
   1333     }
   1334 
   1335     /**
   1336      * @return The unwrapped {@link android.view.accessibility.AccessibilityNodeInfo}.
   1337      */
   1338     public AccessibilityNodeInfo unwrap() {
   1339         return mInfo;
   1340     }
   1341 
   1342     /**
   1343      * @return The wrapped {@link android.view.accessibility.AccessibilityNodeInfo}.
   1344      *
   1345      * @deprecated Use {@link #unwrap()} instead.
   1346      */
   1347     @Deprecated
   1348     public Object getInfo() {
   1349         return mInfo;
   1350     }
   1351 
   1352     /**
   1353      * Returns a cached instance if such is available otherwise a new one and
   1354      * sets the source.
   1355      *
   1356      * @return An instance.
   1357      * @see #setSource(View)
   1358      */
   1359     public static AccessibilityNodeInfoCompat obtain(View source) {
   1360         return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(source));
   1361     }
   1362 
   1363     /**
   1364      * Returns a cached instance if such is available otherwise a new one
   1365      * and sets the source.
   1366      *
   1367      * @param root The root of the virtual subtree.
   1368      * @param virtualDescendantId The id of the virtual descendant.
   1369      * @return An instance.
   1370      *
   1371      * @see #setSource(View, int)
   1372      */
   1373     public static AccessibilityNodeInfoCompat obtain(View root, int virtualDescendantId) {
   1374         if (Build.VERSION.SDK_INT >= 16) {
   1375             return AccessibilityNodeInfoCompat.wrapNonNullInstance(
   1376                     AccessibilityNodeInfo.obtain(root, virtualDescendantId));
   1377         } else {
   1378             return null;
   1379         }
   1380     }
   1381 
   1382     /**
   1383      * Returns a cached instance if such is available otherwise a new one.
   1384      *
   1385      * @return An instance.
   1386      */
   1387     public static AccessibilityNodeInfoCompat obtain() {
   1388         return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain());
   1389     }
   1390 
   1391     /**
   1392      * Returns a cached instance if such is available or a new one is create.
   1393      * The returned instance is initialized from the given <code>info</code>.
   1394      *
   1395      * @param info The other info.
   1396      * @return An instance.
   1397      */
   1398     public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) {
   1399         return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(info.mInfo));
   1400     }
   1401 
   1402     /**
   1403      * Sets the source.
   1404      *
   1405      * @param source The info source.
   1406      */
   1407     public void setSource(View source) {
   1408         mInfo.setSource(source);
   1409     }
   1410 
   1411     /**
   1412      * Sets the source to be a virtual descendant of the given <code>root</code>.
   1413      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
   1414      * is set as the source.
   1415      * <p>
   1416      * A virtual descendant is an imaginary View that is reported as a part of the view
   1417      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1418      * content to report themselves as a tree of virtual views, thus conveying their
   1419      * logical structure.
   1420      * </p>
   1421      * <p>
   1422      *   <strong>Note:</strong> Cannot be called from an
   1423      *   {@link android.accessibilityservice.AccessibilityService}.
   1424      *   This class is made immutable before being delivered to an AccessibilityService.
   1425      * </p>
   1426      *
   1427      * @param root The root of the virtual subtree.
   1428      * @param virtualDescendantId The id of the virtual descendant.
   1429      */
   1430     public void setSource(View root, int virtualDescendantId) {
   1431         if (Build.VERSION.SDK_INT >= 16) {
   1432             mInfo.setSource(root, virtualDescendantId);
   1433         }
   1434     }
   1435 
   1436     /**
   1437      * Find the view that has the specified focus type. The search starts from
   1438      * the view represented by this node info.
   1439      *
   1440      * @param focus The focus to find. One of {@link #FOCUS_INPUT} or
   1441      *         {@link #FOCUS_ACCESSIBILITY}.
   1442      * @return The node info of the focused view or null.
   1443      *
   1444      * @see #FOCUS_INPUT
   1445      * @see #FOCUS_ACCESSIBILITY
   1446      */
   1447     public AccessibilityNodeInfoCompat findFocus(int focus) {
   1448         if (Build.VERSION.SDK_INT >= 16) {
   1449             return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.findFocus(focus));
   1450         } else {
   1451             return null;
   1452         }
   1453     }
   1454 
   1455     /**
   1456      * Searches for the nearest view in the specified direction that can take
   1457      * input focus.
   1458      *
   1459      * @param direction The direction. Can be one of:
   1460      *     {@link View#FOCUS_DOWN},
   1461      *     {@link View#FOCUS_UP},
   1462      *     {@link View#FOCUS_LEFT},
   1463      *     {@link View#FOCUS_RIGHT},
   1464      *     {@link View#FOCUS_FORWARD},
   1465      *     {@link View#FOCUS_BACKWARD}.
   1466      *
   1467      * @return The node info for the view that can take accessibility focus.
   1468      */
   1469     public AccessibilityNodeInfoCompat focusSearch(int direction) {
   1470         if (Build.VERSION.SDK_INT >= 16) {
   1471             return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.focusSearch(direction));
   1472         } else {
   1473             return null;
   1474         }
   1475     }
   1476 
   1477     /**
   1478      * Gets the id of the window from which the info comes from.
   1479      *
   1480      * @return The window id.
   1481      */
   1482     public int getWindowId() {
   1483         return mInfo.getWindowId();
   1484     }
   1485 
   1486     /**
   1487      * Gets the number of children.
   1488      *
   1489      * @return The child count.
   1490      */
   1491     public int getChildCount() {
   1492         return mInfo.getChildCount();
   1493     }
   1494 
   1495     /**
   1496      * Get the child at given index.
   1497      * <p>
   1498      * <strong>Note:</strong> It is a client responsibility to recycle the
   1499      * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} to
   1500      * avoid creating of multiple instances.
   1501      * </p>
   1502      *
   1503      * @param index The child index.
   1504      * @return The child node.
   1505      * @throws IllegalStateException If called outside of an
   1506      *             AccessibilityService.
   1507      */
   1508     public AccessibilityNodeInfoCompat getChild(int index) {
   1509         return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getChild(index));
   1510     }
   1511 
   1512     /**
   1513      * Adds a child.
   1514      * <p>
   1515      * <strong>Note:</strong> Cannot be called from an
   1516      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1517      * made immutable before being delivered to an AccessibilityService.
   1518      * </p>
   1519      *
   1520      * @param child The child.
   1521      * @throws IllegalStateException If called from an AccessibilityService.
   1522      */
   1523     public void addChild(View child) {
   1524         mInfo.addChild(child);
   1525     }
   1526 
   1527     /**
   1528      * Adds a virtual child which is a descendant of the given <code>root</code>.
   1529      * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root
   1530      * is added as a child.
   1531      * <p>
   1532      * A virtual descendant is an imaginary View that is reported as a part of the view
   1533      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1534      * content to report them selves as a tree of virtual views, thus conveying their
   1535      * logical structure.
   1536      * </p>
   1537      *
   1538      * @param root The root of the virtual subtree.
   1539      * @param virtualDescendantId The id of the virtual child.
   1540      */
   1541     public void addChild(View root, int virtualDescendantId) {
   1542         if (Build.VERSION.SDK_INT >= 16) {
   1543             mInfo.addChild(root, virtualDescendantId);
   1544         }
   1545     }
   1546 
   1547     /**
   1548      * Removes a child. If the child was not previously added to the node,
   1549      * calling this method has no effect.
   1550      * <p>
   1551      * <strong>Note:</strong> Cannot be called from an
   1552      * {@link android.accessibilityservice.AccessibilityService}.
   1553      * This class is made immutable before being delivered to an AccessibilityService.
   1554      * </p>
   1555      *
   1556      * @param child The child.
   1557      * @return true if the child was present
   1558      *
   1559      * @throws IllegalStateException If called from an AccessibilityService.
   1560      */
   1561     public boolean removeChild(View child) {
   1562         if (Build.VERSION.SDK_INT >= 21) {
   1563             return mInfo.removeChild(child);
   1564         } else {
   1565             return false;
   1566         }
   1567     }
   1568 
   1569     /**
   1570      * Removes a virtual child which is a descendant of the given
   1571      * <code>root</code>. If the child was not previously added to the node,
   1572      * calling this method has no effect.
   1573      *
   1574      * @param root The root of the virtual subtree.
   1575      * @param virtualDescendantId The id of the virtual child.
   1576      * @return true if the child was present
   1577      * @see #addChild(View, int)
   1578      */
   1579     public boolean removeChild(View root, int virtualDescendantId) {
   1580         if (Build.VERSION.SDK_INT >= 21) {
   1581             return mInfo.removeChild(root, virtualDescendantId);
   1582         } else {
   1583             return false;
   1584         }
   1585     }
   1586 
   1587     /**
   1588      * Gets the actions that can be performed on the node.
   1589      *
   1590      * @return The bit mask of with actions.
   1591      * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS
   1592      * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS
   1593      * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT
   1594      * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION
   1595      */
   1596     public int getActions() {
   1597         return mInfo.getActions();
   1598     }
   1599 
   1600     /**
   1601      * Adds an action that can be performed on the node.
   1602      * <p>
   1603      * <strong>Note:</strong> Cannot be called from an
   1604      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1605      * made immutable before being delivered to an AccessibilityService.
   1606      * </p>
   1607      *
   1608      * @param action The action.
   1609      * @throws IllegalStateException If called from an AccessibilityService.
   1610      */
   1611     public void addAction(int action) {
   1612         mInfo.addAction(action);
   1613     }
   1614 
   1615     /**
   1616      * Adds an action that can be performed on the node.
   1617      * <p>
   1618      * <strong>Note:</strong> Cannot be called from an
   1619      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1620      * made immutable before being delivered to an AccessibilityService.
   1621      * </p>
   1622      *
   1623      * @param action The action.
   1624      * @throws IllegalStateException If called from an AccessibilityService.
   1625      */
   1626     public void addAction(AccessibilityActionCompat action) {
   1627         if (Build.VERSION.SDK_INT >= 21) {
   1628             mInfo.addAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction);
   1629         }
   1630     }
   1631 
   1632     /**
   1633      * Removes an action that can be performed on the node. If the action was
   1634      * not already added to the node, calling this method has no effect.
   1635      * <p>
   1636      *   <strong>Note:</strong> Cannot be called from an
   1637      *   {@link android.accessibilityservice.AccessibilityService}.
   1638      *   This class is made immutable before being delivered to an AccessibilityService.
   1639      * </p>
   1640      *
   1641      * @param action The action to be removed.
   1642      * @return The action removed from the list of actions.
   1643      *
   1644      * @throws IllegalStateException If called from an AccessibilityService.
   1645      */
   1646     public boolean removeAction(AccessibilityActionCompat action) {
   1647         if (Build.VERSION.SDK_INT >= 21) {
   1648             return mInfo.removeAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction);
   1649         } else {
   1650             return false;
   1651         }
   1652     }
   1653 
   1654     /**
   1655      * Performs an action on the node.
   1656      * <p>
   1657      * <strong>Note:</strong> An action can be performed only if the request is
   1658      * made from an {@link android.accessibilityservice.AccessibilityService}.
   1659      * </p>
   1660      *
   1661      * @param action The action to perform.
   1662      * @return True if the action was performed.
   1663      * @throws IllegalStateException If called outside of an
   1664      *             AccessibilityService.
   1665      */
   1666     public boolean performAction(int action) {
   1667         return mInfo.performAction(action);
   1668     }
   1669 
   1670     /**
   1671      * Performs an action on the node.
   1672      * <p>
   1673      *   <strong>Note:</strong> An action can be performed only if the request is made
   1674      *   from an {@link android.accessibilityservice.AccessibilityService}.
   1675      * </p>
   1676      *
   1677      * @param action The action to perform.
   1678      * @param arguments A bundle with additional arguments.
   1679      * @return True if the action was performed.
   1680      *
   1681      * @throws IllegalStateException If called outside of an AccessibilityService.
   1682      */
   1683     public boolean performAction(int action, Bundle arguments) {
   1684         if (Build.VERSION.SDK_INT >= 16) {
   1685             return mInfo.performAction(action, arguments);
   1686         } else {
   1687             return false;
   1688         }
   1689     }
   1690 
   1691     /**
   1692      * Sets the movement granularities for traversing the text of this node.
   1693      * <p>
   1694      *   <strong>Note:</strong> Cannot be called from an
   1695      *   {@link android.accessibilityservice.AccessibilityService}.
   1696      *   This class is made immutable before being delivered to an AccessibilityService.
   1697      * </p>
   1698      *
   1699      * @param granularities The bit mask with granularities.
   1700      *
   1701      * @throws IllegalStateException If called from an AccessibilityService.
   1702      */
   1703     public void setMovementGranularities(int granularities) {
   1704         if (Build.VERSION.SDK_INT >= 16) {
   1705             mInfo.setMovementGranularities(granularities);
   1706         }
   1707     }
   1708 
   1709     /**
   1710      * Gets the movement granularities for traversing the text of this node.
   1711      *
   1712      * @return The bit mask with granularities.
   1713      */
   1714     public int getMovementGranularities() {
   1715         if (Build.VERSION.SDK_INT >= 16) {
   1716             return mInfo.getMovementGranularities();
   1717         } else {
   1718             return 0;
   1719         }
   1720     }
   1721 
   1722     /**
   1723      * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by text. The match
   1724      * is case insensitive containment. The search is relative to this info i.e. this
   1725      * info is the root of the traversed tree.
   1726      * <p>
   1727      * <strong>Note:</strong> It is a client responsibility to recycle the
   1728      * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()}
   1729      * to avoid creating of multiple instances.
   1730      * </p>
   1731      *
   1732      * @param text The searched text.
   1733      * @return A list of node info.
   1734      */
   1735     public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(String text) {
   1736         List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>();
   1737         List<AccessibilityNodeInfo> infos = mInfo.findAccessibilityNodeInfosByText(text);
   1738         final int infoCount = infos.size();
   1739         for (int i = 0; i < infoCount; i++) {
   1740             AccessibilityNodeInfo info = infos.get(i);
   1741             result.add(AccessibilityNodeInfoCompat.wrap(info));
   1742         }
   1743         return result;
   1744     }
   1745 
   1746     /**
   1747      * Gets the parent.
   1748      * <p>
   1749      * <strong>Note:</strong> It is a client responsibility to recycle the
   1750      * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()}
   1751      * to avoid creating of multiple instances.
   1752      * </p>
   1753      *
   1754      * @return The parent.
   1755      */
   1756     public AccessibilityNodeInfoCompat getParent() {
   1757         return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getParent());
   1758     }
   1759 
   1760     /**
   1761      * Sets the parent.
   1762      * <p>
   1763      * <strong>Note:</strong> Cannot be called from an
   1764      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1765      * made immutable before being delivered to an AccessibilityService.
   1766      * </p>
   1767      *
   1768      * @param parent The parent.
   1769      * @throws IllegalStateException If called from an AccessibilityService.
   1770      */
   1771     public void setParent(View parent) {
   1772         mInfo.setParent(parent);
   1773     }
   1774 
   1775     /**
   1776      * Sets the parent to be a virtual descendant of the given <code>root</code>.
   1777      * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root
   1778      * is set as the parent.
   1779      * <p>
   1780      * A virtual descendant is an imaginary View that is reported as a part of the view
   1781      * hierarchy for accessibility purposes. This enables custom views that draw complex
   1782      * content to report them selves as a tree of virtual views, thus conveying their
   1783      * logical structure.
   1784      * </p>
   1785      * <p>
   1786      *   <strong>Note:</strong> Cannot be called from an
   1787      *   {@link android.accessibilityservice.AccessibilityService}.
   1788      *   This class is made immutable before being delivered to an AccessibilityService.
   1789      * </p>
   1790      *
   1791      * @param root The root of the virtual subtree.
   1792      * @param virtualDescendantId The id of the virtual descendant.
   1793      */
   1794     public void setParent(View root, int virtualDescendantId) {
   1795         mParentVirtualDescendantId = virtualDescendantId;
   1796         if (Build.VERSION.SDK_INT >= 16) {
   1797             mInfo.setParent(root, virtualDescendantId);
   1798         }
   1799     }
   1800 
   1801     /**
   1802      * Gets the node bounds in parent coordinates.
   1803      *
   1804      * @param outBounds The output node bounds.
   1805      */
   1806     public void getBoundsInParent(Rect outBounds) {
   1807         mInfo.getBoundsInParent(outBounds);
   1808     }
   1809 
   1810     /**
   1811      * Sets the node bounds in parent coordinates.
   1812      * <p>
   1813      * <strong>Note:</strong> Cannot be called from an
   1814      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1815      * made immutable before being delivered to an AccessibilityService.
   1816      * </p>
   1817      *
   1818      * @param bounds The node bounds.
   1819      * @throws IllegalStateException If called from an AccessibilityService.
   1820      */
   1821     public void setBoundsInParent(Rect bounds) {
   1822         mInfo.setBoundsInParent(bounds);
   1823     }
   1824 
   1825     /**
   1826      * Gets the node bounds in screen coordinates.
   1827      *
   1828      * @param outBounds The output node bounds.
   1829      */
   1830     public void getBoundsInScreen(Rect outBounds) {
   1831         mInfo.getBoundsInScreen(outBounds);
   1832     }
   1833 
   1834     /**
   1835      * Sets the node bounds in screen coordinates.
   1836      * <p>
   1837      * <strong>Note:</strong> Cannot be called from an
   1838      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1839      * made immutable before being delivered to an AccessibilityService.
   1840      * </p>
   1841      *
   1842      * @param bounds The node bounds.
   1843      * @throws IllegalStateException If called from an AccessibilityService.
   1844      */
   1845     public void setBoundsInScreen(Rect bounds) {
   1846         mInfo.setBoundsInScreen(bounds);
   1847     }
   1848 
   1849     /**
   1850      * Gets whether this node is checkable.
   1851      *
   1852      * @return True if the node is checkable.
   1853      */
   1854     public boolean isCheckable() {
   1855         return mInfo.isCheckable();
   1856     }
   1857 
   1858     /**
   1859      * Sets whether this node is checkable.
   1860      * <p>
   1861      * <strong>Note:</strong> Cannot be called from an
   1862      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1863      * made immutable before being delivered to an AccessibilityService.
   1864      * </p>
   1865      *
   1866      * @param checkable True if the node is checkable.
   1867      * @throws IllegalStateException If called from an AccessibilityService.
   1868      */
   1869     public void setCheckable(boolean checkable) {
   1870         mInfo.setCheckable(checkable);
   1871     }
   1872 
   1873     /**
   1874      * Gets whether this node is checked.
   1875      *
   1876      * @return True if the node is checked.
   1877      */
   1878     public boolean isChecked() {
   1879         return mInfo.isChecked();
   1880     }
   1881 
   1882     /**
   1883      * Sets whether this node is checked.
   1884      * <p>
   1885      * <strong>Note:</strong> Cannot be called from an
   1886      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1887      * made immutable before being delivered to an AccessibilityService.
   1888      * </p>
   1889      *
   1890      * @param checked True if the node is checked.
   1891      * @throws IllegalStateException If called from an AccessibilityService.
   1892      */
   1893     public void setChecked(boolean checked) {
   1894         mInfo.setChecked(checked);
   1895     }
   1896 
   1897     /**
   1898      * Gets whether this node is focusable.
   1899      *
   1900      * @return True if the node is focusable.
   1901      */
   1902     public boolean isFocusable() {
   1903         return mInfo.isFocusable();
   1904     }
   1905 
   1906     /**
   1907      * Sets whether this node is focusable.
   1908      * <p>
   1909      * <strong>Note:</strong> Cannot be called from an
   1910      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1911      * made immutable before being delivered to an AccessibilityService.
   1912      * </p>
   1913      *
   1914      * @param focusable True if the node is focusable.
   1915      * @throws IllegalStateException If called from an AccessibilityService.
   1916      */
   1917     public void setFocusable(boolean focusable) {
   1918         mInfo.setFocusable(focusable);
   1919     }
   1920 
   1921     /**
   1922      * Gets whether this node is focused.
   1923      *
   1924      * @return True if the node is focused.
   1925      */
   1926     public boolean isFocused() {
   1927         return mInfo.isFocused();
   1928     }
   1929 
   1930     /**
   1931      * Sets whether this node is focused.
   1932      * <p>
   1933      * <strong>Note:</strong> Cannot be called from an
   1934      * {@link android.accessibilityservice.AccessibilityService}. This class is
   1935      * made immutable before being delivered to an AccessibilityService.
   1936      * </p>
   1937      *
   1938      * @param focused True if the node is focused.
   1939      * @throws IllegalStateException If called from an AccessibilityService.
   1940      */
   1941     public void setFocused(boolean focused) {
   1942         mInfo.setFocused(focused);
   1943     }
   1944 
   1945     /**
   1946      * Gets whether this node is visible to the user.
   1947      *
   1948      * @return Whether the node is visible to the user.
   1949      */
   1950     public boolean isVisibleToUser() {
   1951         if (Build.VERSION.SDK_INT >= 16) {
   1952             return mInfo.isVisibleToUser();
   1953         } else {
   1954             return false;
   1955         }
   1956     }
   1957 
   1958     /**
   1959      * Sets whether this node is visible to the user.
   1960      * <p>
   1961      *   <strong>Note:</strong> Cannot be called from an
   1962      *   {@link android.accessibilityservice.AccessibilityService}.
   1963      *   This class is made immutable before being delivered to an AccessibilityService.
   1964      * </p>
   1965      *
   1966      * @param visibleToUser Whether the node is visible to the user.
   1967      *
   1968      * @throws IllegalStateException If called from an AccessibilityService.
   1969      */
   1970     public void setVisibleToUser(boolean visibleToUser) {
   1971         if (Build.VERSION.SDK_INT >= 16) {
   1972             mInfo.setVisibleToUser(visibleToUser);
   1973         }
   1974     }
   1975 
   1976     /**
   1977      * Gets whether this node is accessibility focused.
   1978      *
   1979      * @return True if the node is accessibility focused.
   1980      */
   1981     public boolean isAccessibilityFocused() {
   1982         if (Build.VERSION.SDK_INT >= 16) {
   1983             return mInfo.isAccessibilityFocused();
   1984         } else {
   1985             return false;
   1986         }
   1987     }
   1988 
   1989     /**
   1990      * Sets whether this node is accessibility focused.
   1991      * <p>
   1992      *   <strong>Note:</strong> Cannot be called from an
   1993      *   {@link android.accessibilityservice.AccessibilityService}.
   1994      *   This class is made immutable before being delivered to an AccessibilityService.
   1995      * </p>
   1996      *
   1997      * @param focused True if the node is accessibility focused.
   1998      *
   1999      * @throws IllegalStateException If called from an AccessibilityService.
   2000      */
   2001     public void setAccessibilityFocused(boolean focused) {
   2002         if (Build.VERSION.SDK_INT >= 16) {
   2003             mInfo.setAccessibilityFocused(focused);
   2004         }
   2005     }
   2006 
   2007     /**
   2008      * Gets whether this node is selected.
   2009      *
   2010      * @return True if the node is selected.
   2011      */
   2012     public boolean isSelected() {
   2013         return mInfo.isSelected();
   2014     }
   2015 
   2016     /**
   2017      * Sets whether this node is selected.
   2018      * <p>
   2019      * <strong>Note:</strong> Cannot be called from an
   2020      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2021      * made immutable before being delivered to an AccessibilityService.
   2022      * </p>
   2023      *
   2024      * @param selected True if the node is selected.
   2025      * @throws IllegalStateException If called from an AccessibilityService.
   2026      */
   2027     public void setSelected(boolean selected) {
   2028         mInfo.setSelected(selected);
   2029     }
   2030 
   2031     /**
   2032      * Gets whether this node is clickable.
   2033      *
   2034      * @return True if the node is clickable.
   2035      */
   2036     public boolean isClickable() {
   2037         return mInfo.isClickable();
   2038     }
   2039 
   2040     /**
   2041      * Sets whether this node is clickable.
   2042      * <p>
   2043      * <strong>Note:</strong> Cannot be called from an
   2044      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2045      * made immutable before being delivered to an AccessibilityService.
   2046      * </p>
   2047      *
   2048      * @param clickable True if the node is clickable.
   2049      * @throws IllegalStateException If called from an AccessibilityService.
   2050      */
   2051     public void setClickable(boolean clickable) {
   2052         mInfo.setClickable(clickable);
   2053     }
   2054 
   2055     /**
   2056      * Gets whether this node is long clickable.
   2057      *
   2058      * @return True if the node is long clickable.
   2059      */
   2060     public boolean isLongClickable() {
   2061         return mInfo.isLongClickable();
   2062     }
   2063 
   2064     /**
   2065      * Sets whether this node is long clickable.
   2066      * <p>
   2067      * <strong>Note:</strong> Cannot be called from an
   2068      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2069      * made immutable before being delivered to an AccessibilityService.
   2070      * </p>
   2071      *
   2072      * @param longClickable True if the node is long clickable.
   2073      * @throws IllegalStateException If called from an AccessibilityService.
   2074      */
   2075     public void setLongClickable(boolean longClickable) {
   2076         mInfo.setLongClickable(longClickable);
   2077     }
   2078 
   2079     /**
   2080      * Gets whether this node is enabled.
   2081      *
   2082      * @return True if the node is enabled.
   2083      */
   2084     public boolean isEnabled() {
   2085         return mInfo.isEnabled();
   2086     }
   2087 
   2088     /**
   2089      * Sets whether this node is enabled.
   2090      * <p>
   2091      * <strong>Note:</strong> Cannot be called from an
   2092      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2093      * made immutable before being delivered to an AccessibilityService.
   2094      * </p>
   2095      *
   2096      * @param enabled True if the node is enabled.
   2097      * @throws IllegalStateException If called from an AccessibilityService.
   2098      */
   2099     public void setEnabled(boolean enabled) {
   2100         mInfo.setEnabled(enabled);
   2101     }
   2102 
   2103     /**
   2104      * Gets whether this node is a password.
   2105      *
   2106      * @return True if the node is a password.
   2107      */
   2108     public boolean isPassword() {
   2109         return mInfo.isPassword();
   2110     }
   2111 
   2112     /**
   2113      * Sets whether this node is a password.
   2114      * <p>
   2115      * <strong>Note:</strong> Cannot be called from an
   2116      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2117      * made immutable before being delivered to an AccessibilityService.
   2118      * </p>
   2119      *
   2120      * @param password True if the node is a password.
   2121      * @throws IllegalStateException If called from an AccessibilityService.
   2122      */
   2123     public void setPassword(boolean password) {
   2124         mInfo.setPassword(password);
   2125     }
   2126 
   2127     /**
   2128      * Gets if the node is scrollable.
   2129      *
   2130      * @return True if the node is scrollable, false otherwise.
   2131      */
   2132     public boolean isScrollable() {
   2133         return mInfo.isScrollable();
   2134     }
   2135 
   2136     /**
   2137      * Sets if the node is scrollable.
   2138      * <p>
   2139      * <strong>Note:</strong> Cannot be called from an
   2140      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2141      * made immutable before being delivered to an AccessibilityService.
   2142      * </p>
   2143      *
   2144      * @param scrollable True if the node is scrollable, false otherwise.
   2145      * @throws IllegalStateException If called from an AccessibilityService.
   2146      */
   2147     public void setScrollable(boolean scrollable) {
   2148         mInfo.setScrollable(scrollable);
   2149     }
   2150 
   2151     /**
   2152      * Returns whether the node originates from a view considered important for accessibility.
   2153      *
   2154      * @return {@code true} if the node originates from a view considered important for
   2155      *         accessibility, {@code false} otherwise
   2156      *
   2157      * @see View#isImportantForAccessibility()
   2158      */
   2159     public boolean isImportantForAccessibility() {
   2160         if (Build.VERSION.SDK_INT >= 24) {
   2161             return mInfo.isImportantForAccessibility();
   2162         } else {
   2163             return true;
   2164         }
   2165     }
   2166 
   2167     /**
   2168      * Sets whether the node is considered important for accessibility.
   2169      * <p>
   2170      *   <strong>Note:</strong> Cannot be called from an
   2171      *   {@link android.accessibilityservice.AccessibilityService}.
   2172      *   This class is made immutable before being delivered to an AccessibilityService.
   2173      * </p>
   2174      *
   2175      * @param important {@code true} if the node is considered important for accessibility,
   2176      *                  {@code false} otherwise
   2177      */
   2178     public void setImportantForAccessibility(boolean important) {
   2179         if (Build.VERSION.SDK_INT >= 24) {
   2180             mInfo.setImportantForAccessibility(important);
   2181         }
   2182     }
   2183 
   2184     /**
   2185      * Gets the package this node comes from.
   2186      *
   2187      * @return The package name.
   2188      */
   2189     public CharSequence getPackageName() {
   2190         return mInfo.getPackageName();
   2191     }
   2192 
   2193     /**
   2194      * Sets the package this node comes from.
   2195      * <p>
   2196      * <strong>Note:</strong> Cannot be called from an
   2197      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2198      * made immutable before being delivered to an AccessibilityService.
   2199      * </p>
   2200      *
   2201      * @param packageName The package name.
   2202      * @throws IllegalStateException If called from an AccessibilityService.
   2203      */
   2204     public void setPackageName(CharSequence packageName) {
   2205         mInfo.setPackageName(packageName);
   2206     }
   2207 
   2208     /**
   2209      * Gets the class this node comes from.
   2210      *
   2211      * @return The class name.
   2212      */
   2213     public CharSequence getClassName() {
   2214         return mInfo.getClassName();
   2215     }
   2216 
   2217     /**
   2218      * Sets the class this node comes from.
   2219      * <p>
   2220      * <strong>Note:</strong> Cannot be called from an
   2221      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2222      * made immutable before being delivered to an AccessibilityService.
   2223      * </p>
   2224      *
   2225      * @param className The class name.
   2226      * @throws IllegalStateException If called from an AccessibilityService.
   2227      */
   2228     public void setClassName(CharSequence className) {
   2229         mInfo.setClassName(className);
   2230     }
   2231 
   2232     /**
   2233      * Gets the text of this node.
   2234      *
   2235      * @return The text.
   2236      */
   2237     public CharSequence getText() {
   2238         return mInfo.getText();
   2239     }
   2240 
   2241     /**
   2242      * Sets the text of this node.
   2243      * <p>
   2244      * <strong>Note:</strong> Cannot be called from an
   2245      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2246      * made immutable before being delivered to an AccessibilityService.
   2247      * </p>
   2248      *
   2249      * @param text The text.
   2250      * @throws IllegalStateException If called from an AccessibilityService.
   2251      */
   2252     public void setText(CharSequence text) {
   2253         mInfo.setText(text);
   2254     }
   2255 
   2256     /**
   2257      * Gets the content description of this node.
   2258      *
   2259      * @return The content description.
   2260      */
   2261     public CharSequence getContentDescription() {
   2262         return mInfo.getContentDescription();
   2263     }
   2264 
   2265     /**
   2266      * Sets the content description of this node.
   2267      * <p>
   2268      * <strong>Note:</strong> Cannot be called from an
   2269      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2270      * made immutable before being delivered to an AccessibilityService.
   2271      * </p>
   2272      *
   2273      * @param contentDescription The content description.
   2274      * @throws IllegalStateException If called from an AccessibilityService.
   2275      */
   2276     public void setContentDescription(CharSequence contentDescription) {
   2277         mInfo.setContentDescription(contentDescription);
   2278     }
   2279 
   2280     /**
   2281      * Return an instance back to be reused.
   2282      * <p>
   2283      * <strong>Note:</strong> You must not touch the object after calling this function.
   2284      *
   2285      * @throws IllegalStateException If the info is already recycled.
   2286      */
   2287     public void recycle() {
   2288         mInfo.recycle();
   2289     }
   2290 
   2291     /**
   2292      * Sets the fully qualified resource name of the source view's id.
   2293      *
   2294      * <p>
   2295      *   <strong>Note:</strong> Cannot be called from an
   2296      *   {@link android.accessibilityservice.AccessibilityService}.
   2297      *   This class is made immutable before being delivered to an AccessibilityService.
   2298      * </p>
   2299      *
   2300      * @param viewId The id resource name.
   2301      */
   2302     public void setViewIdResourceName(String viewId) {
   2303         if (Build.VERSION.SDK_INT >= 18) {
   2304             mInfo.setViewIdResourceName(viewId);
   2305         }
   2306     }
   2307 
   2308     /**
   2309      * Gets the fully qualified resource name of the source view's id.
   2310      *
   2311      * <p>
   2312      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
   2313      *   and in order to report the source view id of an {@link AccessibilityNodeInfoCompat}
   2314      *   the client has to set the {@link AccessibilityServiceInfoCompat#FLAG_REPORT_VIEW_IDS}
   2315      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
   2316      * </p>
   2317      *
   2318      * @return The id resource name.
   2319      */
   2320     public String getViewIdResourceName() {
   2321         if (Build.VERSION.SDK_INT >= 18) {
   2322             return mInfo.getViewIdResourceName();
   2323         } else {
   2324             return null;
   2325         }
   2326     }
   2327 
   2328     /**
   2329      * Gets the node's live region mode.
   2330      * <p>
   2331      * A live region is a node that contains information that is important for
   2332      * the user and when it changes the user should be notified. For example,
   2333      * in a login screen with a TextView that displays an "incorrect password"
   2334      * notification, that view should be marked as a live region with mode
   2335      * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_POLITE}.
   2336      * <p>
   2337      * It is the responsibility of the accessibility service to monitor
   2338      * {@link AccessibilityEventCompat#TYPE_WINDOW_CONTENT_CHANGED} events
   2339      * indicating changes to live region nodes and their children.
   2340      *
   2341      * @return The live region mode, or
   2342      *         {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_NONE} if the view is
   2343      *         not a live region.
   2344      * @see ViewCompat#getAccessibilityLiveRegion(View)
   2345      */
   2346     public int getLiveRegion() {
   2347         if (Build.VERSION.SDK_INT >= 19) {
   2348             return mInfo.getLiveRegion();
   2349         } else {
   2350             return ViewCompat.ACCESSIBILITY_LIVE_REGION_NONE;
   2351         }
   2352     }
   2353 
   2354     /**
   2355      * Sets the node's live region mode.
   2356      * <p>
   2357      * <strong>Note:</strong> Cannot be called from an
   2358      * {@link android.accessibilityservice.AccessibilityService}. This class is
   2359      * made immutable before being delivered to an AccessibilityService.
   2360      *
   2361      * @param mode The live region mode, or
   2362      *        {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_NONE} if the view is
   2363      *        not a live region.
   2364      * @see ViewCompat#setAccessibilityLiveRegion(View, int)
   2365      */
   2366     public void setLiveRegion(int mode) {
   2367         if (Build.VERSION.SDK_INT >= 19) {
   2368             mInfo.setLiveRegion(mode);
   2369         }
   2370     }
   2371 
   2372     /**
   2373      * Get the drawing order of the view corresponding it this node.
   2374      * <p>
   2375      * Drawing order is determined only within the node's parent, so this index is only relative
   2376      * to its siblings.
   2377      * <p>
   2378      * In some cases, the drawing order is essentially simultaneous, so it is possible for two
   2379      * siblings to return the same value. It is also possible that values will be skipped.
   2380      *
   2381      * @return The drawing position of the view corresponding to this node relative to its siblings.
   2382      */
   2383     public int getDrawingOrder() {
   2384         if (Build.VERSION.SDK_INT >= 24) {
   2385             return mInfo.getDrawingOrder();
   2386         } else {
   2387             return 0;
   2388         }
   2389     }
   2390 
   2391     /**
   2392      * Set the drawing order of the view corresponding it this node.
   2393      *
   2394      * <p>
   2395      *   <strong>Note:</strong> Cannot be called from an
   2396      *   {@link android.accessibilityservice.AccessibilityService}.
   2397      *   This class is made immutable before being delivered to an AccessibilityService.
   2398      * </p>
   2399      * @param drawingOrderInParent
   2400      * @throws IllegalStateException If called from an AccessibilityService.
   2401      */
   2402     public void setDrawingOrder(int drawingOrderInParent) {
   2403         if (Build.VERSION.SDK_INT >= 24) {
   2404             mInfo.setDrawingOrder(drawingOrderInParent);
   2405         }
   2406     }
   2407 
   2408     /**
   2409      * Gets the collection info if the node is a collection. A collection
   2410      * child is always a collection item.
   2411      *
   2412      * @return The collection info.
   2413      */
   2414     public CollectionInfoCompat getCollectionInfo() {
   2415         if (Build.VERSION.SDK_INT >= 19) {
   2416             AccessibilityNodeInfo.CollectionInfo info = mInfo.getCollectionInfo();
   2417             if (info != null) {
   2418                 return new CollectionInfoCompat(info);
   2419             }
   2420         }
   2421         return null;
   2422     }
   2423 
   2424     public void setCollectionInfo(Object collectionInfo) {
   2425         if (Build.VERSION.SDK_INT >= 19) {
   2426             mInfo.setCollectionInfo((collectionInfo == null) ? null
   2427                     : (AccessibilityNodeInfo.CollectionInfo) ((CollectionInfoCompat)
   2428                             collectionInfo).mInfo);
   2429         }
   2430 
   2431     }
   2432 
   2433     public void setCollectionItemInfo(Object collectionItemInfo) {
   2434         if (Build.VERSION.SDK_INT >= 19) {
   2435             mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null
   2436                     : (AccessibilityNodeInfo.CollectionItemInfo) ((CollectionItemInfoCompat)
   2437                             collectionItemInfo).mInfo);
   2438         }
   2439     }
   2440 
   2441     /**
   2442      * Gets the collection item info if the node is a collection item. A collection
   2443      * item is always a child of a collection.
   2444      *
   2445      * @return The collection item info.
   2446      */
   2447     public CollectionItemInfoCompat getCollectionItemInfo() {
   2448         if (Build.VERSION.SDK_INT >= 19) {
   2449             AccessibilityNodeInfo.CollectionItemInfo info = mInfo.getCollectionItemInfo();
   2450             if (info != null) {
   2451                 return new CollectionItemInfoCompat(info);
   2452             }
   2453         }
   2454         return null;
   2455     }
   2456 
   2457     /**
   2458      * Gets the range info if this node is a range.
   2459      *
   2460      * @return The range.
   2461      */
   2462     public RangeInfoCompat getRangeInfo() {
   2463         if (Build.VERSION.SDK_INT >= 19) {
   2464             AccessibilityNodeInfo.RangeInfo info = mInfo.getRangeInfo();
   2465             if (info != null) {
   2466                 return new RangeInfoCompat(info);
   2467             }
   2468         }
   2469         return null;
   2470     }
   2471 
   2472     /**
   2473      * Sets the range info if this node is a range.
   2474      * <p>
   2475      *   <strong>Note:</strong> Cannot be called from an
   2476      *   {@link android.accessibilityservice.AccessibilityService}.
   2477      *   This class is made immutable before being delivered to an AccessibilityService.
   2478      * </p>
   2479      *
   2480      * @param rangeInfo The range info.
   2481      */
   2482     public void setRangeInfo(RangeInfoCompat rangeInfo) {
   2483         if (Build.VERSION.SDK_INT >= 19) {
   2484             mInfo.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo.mInfo);
   2485         }
   2486     }
   2487 
   2488     /**
   2489      * Gets the actions that can be performed on the node.
   2490      *
   2491      * @return A list of AccessibilityActions.
   2492      */
   2493     @SuppressWarnings("unchecked")
   2494     public List<AccessibilityActionCompat> getActionList() {
   2495         List<Object> actions = null;
   2496         if (Build.VERSION.SDK_INT >= 21) {
   2497             actions = (List<Object>) (List<?>) mInfo.getActionList();
   2498         }
   2499         if (actions != null) {
   2500             List<AccessibilityActionCompat> result = new ArrayList<AccessibilityActionCompat>();
   2501             final int actionCount = actions.size();
   2502             for (int i = 0; i < actionCount; i++) {
   2503                 Object action = actions.get(i);
   2504                 result.add(new AccessibilityActionCompat(action));
   2505             }
   2506             return result;
   2507         } else {
   2508             return Collections.<AccessibilityActionCompat>emptyList();
   2509         }
   2510     }
   2511 
   2512     /**
   2513      * Sets if the content of this node is invalid. For example,
   2514      * a date is not well-formed.
   2515      * <p>
   2516      *   <strong>Note:</strong> Cannot be called from an
   2517      *   {@link android.accessibilityservice.AccessibilityService}.
   2518      *   This class is made immutable before being delivered to an AccessibilityService.
   2519      * </p>
   2520      *
   2521      * @param contentInvalid If the node content is invalid.
   2522      */
   2523     public void setContentInvalid(boolean contentInvalid) {
   2524         if (Build.VERSION.SDK_INT >= 19) {
   2525             mInfo.setContentInvalid(contentInvalid);
   2526         }
   2527     }
   2528 
   2529     /**
   2530      * Gets if the content of this node is invalid. For example,
   2531      * a date is not well-formed.
   2532      *
   2533      * @return If the node content is invalid.
   2534      */
   2535     public boolean isContentInvalid() {
   2536         if (Build.VERSION.SDK_INT >= 19) {
   2537             return mInfo.isContentInvalid();
   2538         } else {
   2539             return false;
   2540         }
   2541     }
   2542 
   2543     /**
   2544      * Gets whether this node is context clickable.
   2545      *
   2546      * @return True if the node is context clickable.
   2547      */
   2548     public boolean isContextClickable() {
   2549         if (Build.VERSION.SDK_INT >= 23) {
   2550             return mInfo.isContextClickable();
   2551         } else {
   2552             return false;
   2553         }
   2554     }
   2555 
   2556     /**
   2557      * Sets whether this node is context clickable.
   2558      * <p>
   2559      * <strong>Note:</strong> Cannot be called from an
   2560      * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable
   2561      * before being delivered to an AccessibilityService.
   2562      * </p>
   2563      *
   2564      * @param contextClickable True if the node is context clickable.
   2565      * @throws IllegalStateException If called from an AccessibilityService.
   2566      */
   2567     public void setContextClickable(boolean contextClickable) {
   2568         if (Build.VERSION.SDK_INT >= 23) {
   2569             mInfo.setContextClickable(contextClickable);
   2570         }
   2571     }
   2572 
   2573     /**
   2574      * Gets the hint text of this node. Only applies to nodes where text can be entered.
   2575      *
   2576      * @return The hint text.
   2577      */
   2578     public @Nullable CharSequence getHintText() {
   2579         if (Build.VERSION.SDK_INT >= 26) {
   2580             return mInfo.getHintText();
   2581         } else if (Build.VERSION.SDK_INT >= 19) {
   2582             return mInfo.getExtras().getCharSequence(HINT_TEXT_KEY);
   2583         }
   2584         return null;
   2585     }
   2586 
   2587     /**
   2588      * Sets the hint text of this node. Only applies to nodes where text can be entered.
   2589      * <p>This method has no effect below API 19</p>
   2590      * <p>
   2591      *   <strong>Note:</strong> Cannot be called from an
   2592      *   {@link android.accessibilityservice.AccessibilityService}.
   2593      *   This class is made immutable before being delivered to an AccessibilityService.
   2594      * </p>
   2595      *
   2596      * @param hintText The hint text for this mode.
   2597      *
   2598      * @throws IllegalStateException If called from an AccessibilityService.
   2599      */
   2600     public void setHintText(@Nullable CharSequence hintText) {
   2601         if (Build.VERSION.SDK_INT >= 26) {
   2602             mInfo.setHintText(hintText);
   2603         } else if (Build.VERSION.SDK_INT >= 19) {
   2604             mInfo.getExtras().putCharSequence(HINT_TEXT_KEY, hintText);
   2605         }
   2606     }
   2607 
   2608 
   2609     /**
   2610      * Sets the error text of this node.
   2611      * <p>
   2612      *   <strong>Note:</strong> Cannot be called from an
   2613      *   {@link android.accessibilityservice.AccessibilityService}.
   2614      *   This class is made immutable before being delivered to an AccessibilityService.
   2615      * </p>
   2616      *
   2617      * @param error The error text.
   2618      *
   2619      * @throws IllegalStateException If called from an AccessibilityService.
   2620      */
   2621     public void setError(CharSequence error) {
   2622         if (Build.VERSION.SDK_INT >= 21) {
   2623             mInfo.setError(error);
   2624         }
   2625     }
   2626 
   2627     /**
   2628      * Gets the error text of this node.
   2629      *
   2630      * @return The error text.
   2631      */
   2632     public CharSequence getError() {
   2633         if (Build.VERSION.SDK_INT >= 21) {
   2634             return mInfo.getError();
   2635         } else {
   2636             return null;
   2637         }
   2638     }
   2639 
   2640     /**
   2641      * Sets the view for which the view represented by this info serves as a
   2642      * label for accessibility purposes.
   2643      *
   2644      * @param labeled The view for which this info serves as a label.
   2645      */
   2646     public void setLabelFor(View labeled) {
   2647         if (Build.VERSION.SDK_INT >= 17) {
   2648             mInfo.setLabelFor(labeled);
   2649         }
   2650     }
   2651 
   2652     /**
   2653      * Sets the view for which the view represented by this info serves as a
   2654      * label for accessibility purposes. If <code>virtualDescendantId</code>
   2655      * is {@link View#NO_ID} the root is set as the labeled.
   2656      * <p>
   2657      * A virtual descendant is an imaginary View that is reported as a part of the view
   2658      * hierarchy for accessibility purposes. This enables custom views that draw complex
   2659      * content to report themselves as a tree of virtual views, thus conveying their
   2660      * logical structure.
   2661      * </p>
   2662      *
   2663      * @param root The root whose virtual descendant serves as a label.
   2664      * @param virtualDescendantId The id of the virtual descendant.
   2665      */
   2666     public void setLabelFor(View root, int virtualDescendantId) {
   2667         if (Build.VERSION.SDK_INT >= 17) {
   2668             mInfo.setLabelFor(root, virtualDescendantId);
   2669         }
   2670     }
   2671 
   2672     /**
   2673      * Gets the node info for which the view represented by this info serves as
   2674      * a label for accessibility purposes.
   2675      * <p>
   2676      *   <strong>Note:</strong> It is a client responsibility to recycle the
   2677      *     received info by calling {@link AccessibilityNodeInfoCompat#recycle()}
   2678      *     to avoid creating of multiple instances.
   2679      * </p>
   2680      *
   2681      * @return The labeled info.
   2682      */
   2683     public AccessibilityNodeInfoCompat getLabelFor() {
   2684         if (Build.VERSION.SDK_INT >= 17) {
   2685             return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabelFor());
   2686         } else {
   2687             return null;
   2688         }
   2689     }
   2690 
   2691     /**
   2692      * Sets the view which serves as the label of the view represented by
   2693      * this info for accessibility purposes.
   2694      *
   2695      * @param label The view that labels this node's source.
   2696      */
   2697     public void setLabeledBy(View label) {
   2698         if (Build.VERSION.SDK_INT >= 17) {
   2699             mInfo.setLabeledBy(label);
   2700         }
   2701     }
   2702 
   2703     /**
   2704      * Sets the view which serves as the label of the view represented by
   2705      * this info for accessibility purposes. If <code>virtualDescendantId</code>
   2706      * is {@link View#NO_ID} the root is set as the label.
   2707      * <p>
   2708      * A virtual descendant is an imaginary View that is reported as a part of the view
   2709      * hierarchy for accessibility purposes. This enables custom views that draw complex
   2710      * content to report themselves as a tree of virtual views, thus conveying their
   2711      * logical structure.
   2712      * </p>
   2713      * <p>
   2714      *   <strong>Note:</strong> Cannot be called from an
   2715      *   {@link android.accessibilityservice.AccessibilityService}.
   2716      *   This class is made immutable before being delivered to an AccessibilityService.
   2717      * </p>
   2718      *
   2719      * @param root The root whose virtual descendant labels this node's source.
   2720      * @param virtualDescendantId The id of the virtual descendant.
   2721      */
   2722     public void setLabeledBy(View root, int virtualDescendantId) {
   2723         if (Build.VERSION.SDK_INT >= 17) {
   2724             mInfo.setLabeledBy(root, virtualDescendantId);
   2725         }
   2726     }
   2727 
   2728     /**
   2729      * Gets the node info which serves as the label of the view represented by
   2730      * this info for accessibility purposes.
   2731      * <p>
   2732      *   <strong>Note:</strong> It is a client responsibility to recycle the
   2733      *     received info by calling {@link AccessibilityNodeInfoCompat#recycle()}
   2734      *     to avoid creating of multiple instances.
   2735      * </p>
   2736      *
   2737      * @return The label.
   2738      */
   2739     public AccessibilityNodeInfoCompat getLabeledBy() {
   2740         if (Build.VERSION.SDK_INT >= 17) {
   2741             return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabeledBy());
   2742         } else {
   2743             return null;
   2744         }
   2745     }
   2746 
   2747     /**
   2748      * Gets if this node opens a popup or a dialog.
   2749      *
   2750      * @return If the the node opens a popup.
   2751      */
   2752     public boolean canOpenPopup() {
   2753         if (Build.VERSION.SDK_INT >= 19) {
   2754             return mInfo.canOpenPopup();
   2755         } else {
   2756             return false;
   2757         }
   2758     }
   2759 
   2760     /**
   2761      * Sets if this node opens a popup or a dialog.
   2762      * <p>
   2763      *   <strong>Note:</strong> Cannot be called from an
   2764      *   {@link android.accessibilityservice.AccessibilityService}.
   2765      *   This class is made immutable before being delivered to an AccessibilityService.
   2766      * </p>
   2767      *
   2768      * @param opensPopup If the the node opens a popup.
   2769      */
   2770     public void setCanOpenPopup(boolean opensPopup) {
   2771         if (Build.VERSION.SDK_INT >= 19) {
   2772             mInfo.setCanOpenPopup(opensPopup);
   2773         }
   2774     }
   2775 
   2776     /**
   2777      * Finds {@link AccessibilityNodeInfoCompat}s by the fully qualified view id's resource
   2778      * name where a fully qualified id is of the from "package:id/id_resource_name".
   2779      * For example, if the target application's package is "foo.bar" and the id
   2780      * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz".
   2781      *
   2782      * <p>
   2783      *   <strong>Note:</strong> It is a client responsibility to recycle the
   2784      *     received info by calling {@link AccessibilityNodeInfoCompat#recycle()}
   2785      *     to avoid creating of multiple instances.
   2786      * </p>
   2787      * <p>
   2788      *   <strong>Note:</strong> The primary usage of this API is for UI test automation
   2789      *   and in order to report the fully qualified view id if an
   2790      *   {@link AccessibilityNodeInfoCompat} the client has to set the
   2791      *   {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}
   2792      *   flag when configuring his {@link android.accessibilityservice.AccessibilityService}.
   2793      * </p>
   2794      *
   2795      * @param viewId The fully qualified resource name of the view id to find.
   2796      * @return A list of node info.
   2797      */
   2798     public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(String viewId) {
   2799         if (Build.VERSION.SDK_INT >= 18) {
   2800             List<AccessibilityNodeInfo> nodes = mInfo.findAccessibilityNodeInfosByViewId(viewId);
   2801             List<AccessibilityNodeInfoCompat> result = new ArrayList<>();
   2802             for (AccessibilityNodeInfo node : nodes) {
   2803                 result.add(AccessibilityNodeInfoCompat.wrap(node));
   2804             }
   2805             return result;
   2806         } else {
   2807             return Collections.emptyList();
   2808         }
   2809     }
   2810 
   2811     /**
   2812      * Gets an optional bundle with extra data. The bundle
   2813      * is lazily created and never <code>null</code>.
   2814      * <p>
   2815      * <strong>Note:</strong> It is recommended to use the package
   2816      * name of your application as a prefix for the keys to avoid
   2817      * collisions which may confuse an accessibility service if the
   2818      * same key has different meaning when emitted from different
   2819      * applications.
   2820      * </p>
   2821      *
   2822      * @return The bundle.
   2823      */
   2824     public Bundle getExtras() {
   2825         if (Build.VERSION.SDK_INT >= 19) {
   2826             return mInfo.getExtras();
   2827         } else {
   2828             return new Bundle();
   2829         }
   2830     }
   2831 
   2832     /**
   2833      * Gets the input type of the source as defined by {@link InputType}.
   2834      *
   2835      * @return The input type.
   2836      */
   2837     public int getInputType() {
   2838         if (Build.VERSION.SDK_INT >= 19) {
   2839             return mInfo.getInputType();
   2840         } else {
   2841             return InputType.TYPE_NULL;
   2842         }
   2843     }
   2844 
   2845     /**
   2846      * Sets the input type of the source as defined by {@link InputType}.
   2847      * <p>
   2848      *   <strong>Note:</strong> Cannot be called from an
   2849      *   {@link android.accessibilityservice.AccessibilityService}.
   2850      *   This class is made immutable before being delivered to an
   2851      *   AccessibilityService.
   2852      * </p>
   2853      *
   2854      * @param inputType The input type.
   2855      *
   2856      * @throws IllegalStateException If called from an AccessibilityService.
   2857      */
   2858     public void setInputType(int inputType) {
   2859         if (Build.VERSION.SDK_INT >= 19) {
   2860             mInfo.setInputType(inputType);
   2861         }
   2862     }
   2863 
   2864     /**
   2865      * Sets the maximum text length, or -1 for no limit.
   2866      * <p>
   2867      * Typically used to indicate that an editable text field has a limit on
   2868      * the number of characters entered.
   2869      * <p>
   2870      * <strong>Note:</strong> Cannot be called from an
   2871      * {@link android.accessibilityservice.AccessibilityService}.
   2872      * This class is made immutable before being delivered to an AccessibilityService.
   2873      *
   2874      * @param max The maximum text length.
   2875      * @see #getMaxTextLength()
   2876      *
   2877      * @throws IllegalStateException If called from an AccessibilityService.
   2878      */
   2879     public void setMaxTextLength(int max) {
   2880         if (Build.VERSION.SDK_INT >= 21) {
   2881             mInfo.setMaxTextLength(max);
   2882         }
   2883     }
   2884 
   2885     /**
   2886      * Returns the maximum text length for this node.
   2887      *
   2888      * @return The maximum text length, or -1 for no limit.
   2889      * @see #setMaxTextLength(int)
   2890      */
   2891     public int getMaxTextLength() {
   2892         if (Build.VERSION.SDK_INT >= 21) {
   2893             return mInfo.getMaxTextLength();
   2894         } else {
   2895             return -1;
   2896         }
   2897     }
   2898 
   2899     /**
   2900      * Sets the text selection start and end.
   2901      * <p>
   2902      *   <strong>Note:</strong> Cannot be called from an
   2903      *   {@link android.accessibilityservice.AccessibilityService}.
   2904      *   This class is made immutable before being delivered to an AccessibilityService.
   2905      * </p>
   2906      *
   2907      * @param start The text selection start.
   2908      * @param end The text selection end.
   2909      *
   2910      * @throws IllegalStateException If called from an AccessibilityService.
   2911      */
   2912     public void setTextSelection(int start, int end) {
   2913         if (Build.VERSION.SDK_INT >= 18) {
   2914             mInfo.setTextSelection(start, end);
   2915         }
   2916     }
   2917 
   2918     /**
   2919      * Gets the text selection start.
   2920      *
   2921      * @return The text selection start if there is selection or -1.
   2922      */
   2923     public int getTextSelectionStart() {
   2924         if (Build.VERSION.SDK_INT >= 18) {
   2925             return mInfo.getTextSelectionStart();
   2926         } else {
   2927             return -1;
   2928         }
   2929     }
   2930 
   2931     /**
   2932      * Gets the text selection end.
   2933      *
   2934      * @return The text selection end if there is selection or -1.
   2935      */
   2936     public int getTextSelectionEnd() {
   2937         if (Build.VERSION.SDK_INT >= 18) {
   2938             return mInfo.getTextSelectionEnd();
   2939         } else {
   2940             return -1;
   2941         }
   2942     }
   2943 
   2944     /**
   2945      * Gets the node before which this one is visited during traversal. A screen-reader
   2946      * must visit the content of this node before the content of the one it precedes.
   2947      *
   2948      * @return The succeeding node if such or <code>null</code>.
   2949      *
   2950      * @see #setTraversalBefore(android.view.View)
   2951      * @see #setTraversalBefore(android.view.View, int)
   2952      */
   2953     public AccessibilityNodeInfoCompat getTraversalBefore() {
   2954         if (Build.VERSION.SDK_INT >= 22) {
   2955             return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalBefore());
   2956         } else {
   2957             return null;
   2958         }
   2959     }
   2960 
   2961     /**
   2962      * Sets the view before whose node this one should be visited during traversal. A
   2963      * screen-reader must visit the content of this node before the content of the one
   2964      * it precedes.
   2965      * <p>
   2966      *   <strong>Note:</strong> Cannot be called from an
   2967      *   {@link android.accessibilityservice.AccessibilityService}.
   2968      *   This class is made immutable before being delivered to an AccessibilityService.
   2969      * </p>
   2970      *
   2971      * @param view The view providing the preceding node.
   2972      *
   2973      * @see #getTraversalBefore()
   2974      */
   2975     public void setTraversalBefore(View view) {
   2976         if (Build.VERSION.SDK_INT >= 22) {
   2977             mInfo.setTraversalBefore(view);
   2978         }
   2979     }
   2980 
   2981     /**
   2982      * Sets the node before which this one is visited during traversal. A screen-reader
   2983      * must visit the content of this node before the content of the one it precedes.
   2984      * The successor is a virtual descendant of the given <code>root</code>. If
   2985      * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
   2986      * as the successor.
   2987      * <p>
   2988      * A virtual descendant is an imaginary View that is reported as a part of the view
   2989      * hierarchy for accessibility purposes. This enables custom views that draw complex
   2990      * content to report them selves as a tree of virtual views, thus conveying their
   2991      * logical structure.
   2992      * </p>
   2993      * <p>
   2994      *   <strong>Note:</strong> Cannot be called from an
   2995      *   {@link android.accessibilityservice.AccessibilityService}.
   2996      *   This class is made immutable before being delivered to an AccessibilityService.
   2997      * </p>
   2998      *
   2999      * @param root The root of the virtual subtree.
   3000      * @param virtualDescendantId The id of the virtual descendant.
   3001      */
   3002     public void setTraversalBefore(View root, int virtualDescendantId) {
   3003         if (Build.VERSION.SDK_INT >= 22) {
   3004             mInfo.setTraversalBefore(root, virtualDescendantId);
   3005         }
   3006     }
   3007 
   3008     /**
   3009      * Gets the node after which this one is visited in accessibility traversal.
   3010      * A screen-reader must visit the content of the other node before the content
   3011      * of this one.
   3012      *
   3013      * @return The succeeding node if such or <code>null</code>.
   3014      *
   3015      * @see #setTraversalAfter(android.view.View)
   3016      * @see #setTraversalAfter(android.view.View, int)
   3017      */
   3018     public AccessibilityNodeInfoCompat getTraversalAfter() {
   3019         if (Build.VERSION.SDK_INT >= 22) {
   3020             return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalAfter());
   3021         } else {
   3022             return null;
   3023         }
   3024     }
   3025 
   3026     /**
   3027      * Sets the view whose node is visited after this one in accessibility traversal.
   3028      * A screen-reader must visit the content of the other node before the content
   3029      * of this one.
   3030      * <p>
   3031      *   <strong>Note:</strong> Cannot be called from an
   3032      *   {@link android.accessibilityservice.AccessibilityService}.
   3033      *   This class is made immutable before being delivered to an AccessibilityService.
   3034      * </p>
   3035      *
   3036      * @param view The previous view.
   3037      *
   3038      * @see #getTraversalAfter()
   3039      */
   3040     public void setTraversalAfter(View view) {
   3041         if (Build.VERSION.SDK_INT >= 22) {
   3042             mInfo.setTraversalAfter(view);
   3043         }
   3044     }
   3045 
   3046     /**
   3047      * Sets the node after which this one is visited in accessibility traversal.
   3048      * A screen-reader must visit the content of the other node before the content
   3049      * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
   3050      * the root is set as the predecessor.
   3051      * <p>
   3052      * A virtual descendant is an imaginary View that is reported as a part of the view
   3053      * hierarchy for accessibility purposes. This enables custom views that draw complex
   3054      * content to report them selves as a tree of virtual views, thus conveying their
   3055      * logical structure.
   3056      * </p>
   3057      * <p>
   3058      *   <strong>Note:</strong> Cannot be called from an
   3059      *   {@link android.accessibilityservice.AccessibilityService}.
   3060      *   This class is made immutable before being delivered to an AccessibilityService.
   3061      * </p>
   3062      *
   3063      * @param root The root of the virtual subtree.
   3064      * @param virtualDescendantId The id of the virtual descendant.
   3065      */
   3066     public void setTraversalAfter(View root, int virtualDescendantId) {
   3067         if (Build.VERSION.SDK_INT >= 22) {
   3068             mInfo.setTraversalAfter(root, virtualDescendantId);
   3069         }
   3070     }
   3071 
   3072     /**
   3073      * Gets the window to which this node belongs.
   3074      *
   3075      * @return The window.
   3076      *
   3077      * @see android.accessibilityservice.AccessibilityService#getWindows()
   3078      */
   3079     public AccessibilityWindowInfoCompat getWindow() {
   3080         if (Build.VERSION.SDK_INT >= 21) {
   3081             return AccessibilityWindowInfoCompat.wrapNonNullInstance(mInfo.getWindow());
   3082         } else {
   3083             return null;
   3084         }
   3085     }
   3086 
   3087     /**
   3088      * Gets if the node can be dismissed.
   3089      *
   3090      * @return If the node can be dismissed.
   3091      */
   3092     public boolean isDismissable() {
   3093         if (Build.VERSION.SDK_INT >= 19) {
   3094             return mInfo.isDismissable();
   3095         } else {
   3096             return false;
   3097         }
   3098     }
   3099 
   3100     /**
   3101      * Sets if the node can be dismissed.
   3102      * <p>
   3103      *   <strong>Note:</strong> Cannot be called from an
   3104      *   {@link android.accessibilityservice.AccessibilityService}.
   3105      *   This class is made immutable before being delivered to an AccessibilityService.
   3106      * </p>
   3107      *
   3108      * @param dismissable If the node can be dismissed.
   3109      */
   3110     public void setDismissable(boolean dismissable) {
   3111         if (Build.VERSION.SDK_INT >= 19) {
   3112             mInfo.setDismissable(dismissable);
   3113         }
   3114     }
   3115 
   3116     /**
   3117      * Gets if the node is editable.
   3118      *
   3119      * @return True if the node is editable, false otherwise.
   3120      */
   3121     public boolean isEditable() {
   3122         if (Build.VERSION.SDK_INT >= 18) {
   3123             return mInfo.isEditable();
   3124         } else {
   3125             return false;
   3126         }
   3127     }
   3128 
   3129     /**
   3130      * Sets whether this node is editable.
   3131      * <p>
   3132      *   <strong>Note:</strong> Cannot be called from an
   3133      *   {@link android.accessibilityservice.AccessibilityService}.
   3134      *   This class is made immutable before being delivered to an AccessibilityService.
   3135      * </p>
   3136      *
   3137      * @param editable True if the node is editable.
   3138      *
   3139      * @throws IllegalStateException If called from an AccessibilityService.
   3140      */
   3141     public void setEditable(boolean editable) {
   3142         if (Build.VERSION.SDK_INT >= 18) {
   3143             mInfo.setEditable(editable);
   3144         }
   3145     }
   3146 
   3147     /**
   3148      * Gets if the node is a multi line editable text.
   3149      *
   3150      * @return True if the node is multi line.
   3151      */
   3152     public boolean isMultiLine() {
   3153         if (Build.VERSION.SDK_INT >= 19) {
   3154             return mInfo.isMultiLine();
   3155         } else {
   3156             return false;
   3157         }
   3158     }
   3159 
   3160     /**
   3161      * Sets if the node is a multi line editable text.
   3162      * <p>
   3163      *   <strong>Note:</strong> Cannot be called from an
   3164      *   {@link android.accessibilityservice.AccessibilityService}.
   3165      *   This class is made immutable before being delivered to an AccessibilityService.
   3166      * </p>
   3167      *
   3168      * @param multiLine True if the node is multi line.
   3169      */
   3170     public void setMultiLine(boolean multiLine) {
   3171         if (Build.VERSION.SDK_INT >= 19) {
   3172             mInfo.setMultiLine(multiLine);
   3173         }
   3174     }
   3175 
   3176     /**
   3177      * Gets the tooltip text of this node.
   3178      *
   3179      * @return The tooltip text.
   3180      */
   3181     @Nullable
   3182     public CharSequence getTooltipText() {
   3183         if (BuildCompat.isAtLeastP()) {
   3184             return mInfo.getTooltipText();
   3185         } else if (Build.VERSION.SDK_INT >= 19) {
   3186             return mInfo.getExtras().getCharSequence(TOOLTIP_TEXT_KEY);
   3187         }
   3188         return null;
   3189     }
   3190 
   3191     /**
   3192      * Sets the tooltip text of this node.
   3193      * <p>This method has no effect below API 19</p>
   3194      * <p>
   3195      *   <strong>Note:</strong> Cannot be called from an
   3196      *   {@link android.accessibilityservice.AccessibilityService}.
   3197      *   This class is made immutable before being delivered to an AccessibilityService.
   3198      * </p>
   3199      *
   3200      * @param tooltipText The tooltip text.
   3201      *
   3202      * @throws IllegalStateException If called from an AccessibilityService.
   3203      */
   3204     public void setTooltipText(@Nullable CharSequence tooltipText) {
   3205         if (BuildCompat.isAtLeastP()) {
   3206             mInfo.setTooltipText(tooltipText);
   3207         } else if (Build.VERSION.SDK_INT >= 19) {
   3208             mInfo.getExtras().putCharSequence(TOOLTIP_TEXT_KEY, tooltipText);
   3209         }
   3210     }
   3211 
   3212     /**
   3213      * If this node represents a visually distinct region of the screen that may update separately
   3214      * from the rest of the window, it is considered a pane. Set the pane title to indicate that
   3215      * the node is a pane, and to provide a title for it.
   3216      * <p>This method has no effect below API 19</p>
   3217      * <p>
   3218      *   <strong>Note:</strong> Cannot be called from an
   3219      *   {@link android.accessibilityservice.AccessibilityService}.
   3220      *   This class is made immutable before being delivered to an AccessibilityService.
   3221      * </p>
   3222      * @param paneTitle The title of the window represented by this node.
   3223      */
   3224     public void setPaneTitle(@Nullable CharSequence paneTitle) {
   3225         if (BuildCompat.isAtLeastP()) {
   3226             mInfo.setPaneTitle(paneTitle);
   3227         } else if (Build.VERSION.SDK_INT >= 19) {
   3228             mInfo.getExtras().putCharSequence(PANE_TITLE_KEY, paneTitle);
   3229         }
   3230     }
   3231 
   3232     /**
   3233      * Get the title of the pane represented by this node.
   3234      *
   3235      * @return The title of the pane represented by this node, or {@code null} if this node does
   3236      *         not represent a pane.
   3237      */
   3238     public @Nullable CharSequence getPaneTitle() {
   3239         if (BuildCompat.isAtLeastP()) {
   3240             return mInfo.getPaneTitle();
   3241         } else if (Build.VERSION.SDK_INT >= 19) {
   3242             return mInfo.getExtras().getCharSequence(PANE_TITLE_KEY);
   3243         }
   3244         return null;
   3245     }
   3246 
   3247     /**
   3248      * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note
   3249      * that {@code false} indicates that it is not explicitly marked, not that the node is not
   3250      * a focusable unit. Screen readers should generally use other signals, such as
   3251      * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive
   3252      * focus.
   3253      *
   3254      * @return {@code true} if the node is specifically marked as a focusable unit for screen
   3255      *         readers, {@code false} otherwise.
   3256      */
   3257     public boolean isScreenReaderFocusable() {
   3258         if (BuildCompat.isAtLeastP()) {
   3259             return mInfo.isScreenReaderFocusable();
   3260         }
   3261         return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE);
   3262     }
   3263 
   3264     /**
   3265      * Sets whether the node should be considered a focusable unit by a screen reader.
   3266      * <p>This method has no effect below API 19</p>
   3267      * <p>
   3268      *   <strong>Note:</strong> Cannot be called from an
   3269      *   {@link android.accessibilityservice.AccessibilityService}.
   3270      *   This class is made immutable before being delivered to an AccessibilityService.
   3271      * </p>
   3272      *
   3273      * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers,
   3274      *                              {@code false} otherwise.
   3275      */
   3276     public void setScreenReaderFocusable(boolean screenReaderFocusable) {
   3277         if (BuildCompat.isAtLeastP()) {
   3278             mInfo.setScreenReaderFocusable(screenReaderFocusable);
   3279         } else {
   3280             setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable);
   3281         }
   3282     }
   3283 
   3284     /**
   3285      * Returns whether the node's text represents a hint for the user to enter text. It should only
   3286      * be {@code true} if the node has editable text.
   3287      *
   3288      * @return {@code true} if the text in the node represents a hint to the user, {@code false}
   3289      * otherwise.
   3290      */
   3291     public boolean isShowingHintText() {
   3292         if (Build.VERSION.SDK_INT >= 26) {
   3293             return mInfo.isShowingHintText();
   3294         }
   3295         return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT);
   3296     }
   3297 
   3298     /**
   3299      * Sets whether the node's text represents a hint for the user to enter text. It should only
   3300      * be {@code true} if the node has editable text.
   3301      * <p>This method has no effect below API 19</p>
   3302      * <p>
   3303      *   <strong>Note:</strong> Cannot be called from an
   3304      *   {@link android.accessibilityservice.AccessibilityService}.
   3305      *   This class is made immutable before being delivered to an AccessibilityService.
   3306      * </p>
   3307      *
   3308      * @param showingHintText {@code true} if the text in the node represents a hint to the user,
   3309      * {@code false} otherwise.
   3310      */
   3311     public void setShowingHintText(boolean showingHintText) {
   3312         if (Build.VERSION.SDK_INT >= 26) {
   3313             mInfo.setShowingHintText(showingHintText);
   3314         } else {
   3315             setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText);
   3316         }
   3317     }
   3318 
   3319     /**
   3320      * Returns whether node represents a heading.
   3321      * <p><strong>Note:</strong> Returns {@code true} if either {@link #setHeading(boolean)}
   3322      * marks this node as a heading or if the node has a {@link CollectionItemInfoCompat} that marks
   3323      * it as such, to accomodate apps that use the now-deprecated API.</p>
   3324      *
   3325      * @return {@code true} if the node is a heading, {@code false} otherwise.
   3326      */
   3327     public boolean isHeading() {
   3328         if (getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING)) return true;
   3329         CollectionItemInfoCompat collectionItemInfo = getCollectionItemInfo();
   3330         return (collectionItemInfo != null) && (collectionItemInfo.isHeading());
   3331     }
   3332 
   3333     /**
   3334      * Sets whether the node represents a heading.
   3335      * <p>This method has no effect below API 19</p>
   3336      * <p>
   3337      *   <strong>Note:</strong> Cannot be called from an
   3338      *   {@link android.accessibilityservice.AccessibilityService}.
   3339      *   This class is made immutable before being delivered to an AccessibilityService.
   3340      * </p>
   3341      *
   3342      * @param isHeading {@code true} if the node is a heading, {@code false} otherwise.
   3343      */
   3344     public void setHeading(boolean isHeading) {
   3345         setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading);
   3346     }
   3347 
   3348     /**
   3349      * Refreshes this info with the latest state of the view it represents.
   3350      * <p>
   3351      * <strong>Note:</strong> If this method returns false this info is obsolete
   3352      * since it represents a view that is no longer in the view tree and should
   3353      * be recycled.
   3354      * </p>
   3355      * @return Whether the refresh succeeded.
   3356      */
   3357     public boolean refresh() {
   3358         if (Build.VERSION.SDK_INT >= 18) {
   3359             return mInfo.refresh();
   3360         } else {
   3361             return false;
   3362         }
   3363     }
   3364 
   3365     /**
   3366      * Gets the custom role description.
   3367      * @return The role description.
   3368      */
   3369     public @Nullable CharSequence getRoleDescription() {
   3370         if (Build.VERSION.SDK_INT >= 19) {
   3371             return mInfo.getExtras().getCharSequence(ROLE_DESCRIPTION_KEY);
   3372         } else {
   3373             return null;
   3374         }
   3375     }
   3376 
   3377     /**
   3378      * Sets the custom role description.
   3379      *
   3380      * <p>
   3381      *   The role description allows you to customize the name for the view's semantic
   3382      *   role. For example, if you create a custom subclass of {@link android.view.View}
   3383      *   to display a menu bar, you could assign it the role description of "menu bar".
   3384      * </p>
   3385      * <p>
   3386      *   <strong>Warning:</strong> For consistency with other applications, you should
   3387      *   not use the role description to force accessibility services to describe
   3388      *   standard views (such as buttons or checkboxes) using specific wording. For
   3389      *   example, you should not set a role description of "check box" or "tick box" for
   3390      *   a standard {@link android.widget.CheckBox}. Instead let accessibility services
   3391      *   decide what feedback to provide.
   3392      * </p>
   3393      * <p>
   3394      *   <strong>Note:</strong> Cannot be called from an
   3395      *   {@link android.accessibilityservice.AccessibilityService}.
   3396      *   This class is made immutable before being delivered to an AccessibilityService.
   3397      * </p>
   3398      *
   3399      * @param roleDescription The role description.
   3400      */
   3401     public void setRoleDescription(@Nullable CharSequence roleDescription) {
   3402         if (Build.VERSION.SDK_INT >= 19) {
   3403             mInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription);
   3404         }
   3405     }
   3406 
   3407     @Override
   3408     public int hashCode() {
   3409         return (mInfo == null) ? 0 : mInfo.hashCode();
   3410     }
   3411 
   3412     @Override
   3413     public boolean equals(Object obj) {
   3414         if (this == obj) {
   3415             return true;
   3416         }
   3417         if (obj == null) {
   3418             return false;
   3419         }
   3420         if (getClass() != obj.getClass()) {
   3421             return false;
   3422         }
   3423         AccessibilityNodeInfoCompat other = (AccessibilityNodeInfoCompat) obj;
   3424         if (mInfo == null) {
   3425             if (other.mInfo != null) {
   3426                 return false;
   3427             }
   3428         } else if (!mInfo.equals(other.mInfo)) {
   3429             return false;
   3430         }
   3431         return true;
   3432     }
   3433 
   3434     @Override
   3435     public String toString() {
   3436         StringBuilder builder = new StringBuilder();
   3437         builder.append(super.toString());
   3438 
   3439         Rect bounds = new Rect();
   3440 
   3441         getBoundsInParent(bounds);
   3442         builder.append("; boundsInParent: " + bounds);
   3443 
   3444         getBoundsInScreen(bounds);
   3445         builder.append("; boundsInScreen: " + bounds);
   3446 
   3447         builder.append("; packageName: ").append(getPackageName());
   3448         builder.append("; className: ").append(getClassName());
   3449         builder.append("; text: ").append(getText());
   3450         builder.append("; contentDescription: ").append(getContentDescription());
   3451         builder.append("; viewId: ").append(getViewIdResourceName());
   3452 
   3453         builder.append("; checkable: ").append(isCheckable());
   3454         builder.append("; checked: ").append(isChecked());
   3455         builder.append("; focusable: ").append(isFocusable());
   3456         builder.append("; focused: ").append(isFocused());
   3457         builder.append("; selected: ").append(isSelected());
   3458         builder.append("; clickable: ").append(isClickable());
   3459         builder.append("; longClickable: ").append(isLongClickable());
   3460         builder.append("; enabled: ").append(isEnabled());
   3461         builder.append("; password: ").append(isPassword());
   3462         builder.append("; scrollable: " + isScrollable());
   3463 
   3464         builder.append("; [");
   3465         for (int actionBits = getActions(); actionBits != 0;) {
   3466             final int action = 1 << Integer.numberOfTrailingZeros(actionBits);
   3467             actionBits &= ~action;
   3468             builder.append(getActionSymbolicName(action));
   3469             if (actionBits != 0) {
   3470                 builder.append(", ");
   3471             }
   3472         }
   3473         builder.append("]");
   3474 
   3475         return builder.toString();
   3476     }
   3477 
   3478     private void setBooleanProperty(int property, boolean value) {
   3479         Bundle extras = getExtras();
   3480         if (extras != null) {
   3481             int booleanProperties = extras.getInt(BOOLEAN_PROPERTY_KEY, 0);
   3482             booleanProperties &= ~property;
   3483             booleanProperties |= (value) ? property : 0;
   3484             extras.putInt(BOOLEAN_PROPERTY_KEY, booleanProperties);
   3485         }
   3486     }
   3487 
   3488     private boolean getBooleanProperty(int property) {
   3489         Bundle extras = getExtras();
   3490         if (extras == null) return false;
   3491         return (extras.getInt(BOOLEAN_PROPERTY_KEY, 0) & property) == property;
   3492     }
   3493 
   3494     private static String getActionSymbolicName(int action) {
   3495         switch (action) {
   3496             case ACTION_FOCUS:
   3497                 return "ACTION_FOCUS";
   3498             case ACTION_CLEAR_FOCUS:
   3499                 return "ACTION_CLEAR_FOCUS";
   3500             case ACTION_SELECT:
   3501                 return "ACTION_SELECT";
   3502             case ACTION_CLEAR_SELECTION:
   3503                 return "ACTION_CLEAR_SELECTION";
   3504             case ACTION_CLICK:
   3505                 return "ACTION_CLICK";
   3506             case ACTION_LONG_CLICK:
   3507                 return "ACTION_LONG_CLICK";
   3508             case ACTION_ACCESSIBILITY_FOCUS:
   3509                 return "ACTION_ACCESSIBILITY_FOCUS";
   3510             case ACTION_CLEAR_ACCESSIBILITY_FOCUS:
   3511                 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS";
   3512             case ACTION_NEXT_AT_MOVEMENT_GRANULARITY:
   3513                 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY";
   3514             case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY:
   3515                 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY";
   3516             case ACTION_NEXT_HTML_ELEMENT:
   3517                 return "ACTION_NEXT_HTML_ELEMENT";
   3518             case ACTION_PREVIOUS_HTML_ELEMENT:
   3519                 return "ACTION_PREVIOUS_HTML_ELEMENT";
   3520             case ACTION_SCROLL_FORWARD:
   3521                 return "ACTION_SCROLL_FORWARD";
   3522             case ACTION_SCROLL_BACKWARD:
   3523                 return "ACTION_SCROLL_BACKWARD";
   3524             case ACTION_CUT:
   3525                 return "ACTION_CUT";
   3526             case ACTION_COPY:
   3527                 return "ACTION_COPY";
   3528             case ACTION_PASTE:
   3529                 return "ACTION_PASTE";
   3530             case ACTION_SET_SELECTION:
   3531                 return "ACTION_SET_SELECTION";
   3532             default:
   3533                 return"ACTION_UNKNOWN";
   3534         }
   3535     }
   3536 }
   3537