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 android.view.View.NO_ID; 20 21 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX; 22 23 import static java.util.Collections.emptyList; 24 25 import android.accessibilityservice.AccessibilityService; 26 import android.annotation.SuppressLint; 27 import android.content.ClipData; 28 import android.graphics.Rect; 29 import android.graphics.Region; 30 import android.os.Build; 31 import android.os.Bundle; 32 import android.text.InputType; 33 import android.text.Spannable; 34 import android.text.SpannableString; 35 import android.text.Spanned; 36 import android.text.TextUtils; 37 import android.text.style.ClickableSpan; 38 import android.util.Log; 39 import android.util.SparseArray; 40 import android.view.View; 41 import android.view.accessibility.AccessibilityEvent; 42 import android.view.accessibility.AccessibilityNodeInfo; 43 import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo; 44 45 import androidx.annotation.IntDef; 46 import androidx.annotation.IntRange; 47 import androidx.annotation.OptIn; 48 import androidx.annotation.RequiresApi; 49 import androidx.annotation.RestrictTo; 50 import androidx.core.R; 51 import androidx.core.accessibilityservice.AccessibilityServiceInfoCompat; 52 import androidx.core.view.ViewCompat; 53 import androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments; 54 import androidx.core.view.accessibility.AccessibilityViewCommand.MoveAtGranularityArguments; 55 import androidx.core.view.accessibility.AccessibilityViewCommand.MoveHtmlArguments; 56 import androidx.core.view.accessibility.AccessibilityViewCommand.MoveWindowArguments; 57 import androidx.core.view.accessibility.AccessibilityViewCommand.ScrollToPositionArguments; 58 import androidx.core.view.accessibility.AccessibilityViewCommand.SetProgressArguments; 59 import androidx.core.view.accessibility.AccessibilityViewCommand.SetSelectionArguments; 60 import androidx.core.view.accessibility.AccessibilityViewCommand.SetTextArguments; 61 62 import org.jspecify.annotations.NonNull; 63 import org.jspecify.annotations.Nullable; 64 65 import java.lang.annotation.Retention; 66 import java.lang.annotation.RetentionPolicy; 67 import java.lang.ref.WeakReference; 68 import java.time.Duration; 69 import java.util.ArrayList; 70 import java.util.List; 71 import java.util.Map; 72 73 /** 74 * Helper for accessing {@link android.view.accessibility.AccessibilityNodeInfo} in a backwards 75 * compatible fashion. 76 */ 77 public class AccessibilityNodeInfoCompat { 78 79 /** 80 * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}. 81 * Each action has a unique id and a label. 82 * <p> 83 * There are three categories of actions: 84 * <ul> 85 * <li><strong>Standard actions</strong> - These are actions that are reported and 86 * handled by the standard UI widgets in the platform. Each standard action is associated with 87 * a resource id, e.g. {@link android.R.id#accessibilityActionScrollUp}. Note that actions were 88 * formerly associated with static constants defined in this class, e.g. 89 * {@link #ACTION_FOCUS}. These actions will have {@code null} labels. 90 * </li> 91 * <li><strong>Custom actions action</strong> - These are actions that are reported 92 * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For 93 * example, an application may define a custom action for clearing the user history. 94 * </li> 95 * <li><strong>Overriden standard actions</strong> - These are actions that override 96 * standard actions to customize them. For example, an app may add a label to the 97 * standard {@link #ACTION_CLICK} action to indicate to the user that this action clears 98 * browsing history. 99 * </ul> 100 * </p> 101 * <p class="note"> 102 * <strong>Note:</strong> Views which support these actions should invoke 103 * {@link ViewCompat#setImportantForAccessibility(View, int)} with 104 * {@link ViewCompat#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an 105 * {@link android.accessibilityservice.AccessibilityService} can discover the set of supported 106 * actions. 107 * </p> 108 */ 109 public static class AccessibilityActionCompat { 110 111 private static final String TAG = "A11yActionCompat"; 112 113 /** 114 * Action that gives input focus to the node. 115 * <p>The focus request sends an event of {@link AccessibilityEvent#TYPE_VIEW_FOCUSED} 116 * if successful. In the View system, this is handled by {@link View#requestFocus}. 117 * 118 * <p>The node that is focused should return {@code true} for 119 * {@link AccessibilityNodeInfoCompat#isFocused()}. 120 * 121 * @see #ACTION_ACCESSIBILITY_FOCUS for the difference between system focus and 122 * accessibility focus. 123 */ 124 public static final AccessibilityActionCompat ACTION_FOCUS = 125 new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_FOCUS, null); 126 127 /** 128 * Action that clears input focus of the node. 129 * <p>The node that is cleared should return {@code false} for 130 * {@link AccessibilityNodeInfoCompat#isFocused()}. 131 */ 132 public static final AccessibilityActionCompat ACTION_CLEAR_FOCUS = 133 new AccessibilityActionCompat( 134 AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS, null); 135 136 /** 137 * Action that selects the node. 138 */ 139 public static final AccessibilityActionCompat ACTION_SELECT = 140 new AccessibilityActionCompat( 141 AccessibilityNodeInfoCompat.ACTION_SELECT, null); 142 143 /** 144 * Action that deselects the node. 145 */ 146 public static final AccessibilityActionCompat ACTION_CLEAR_SELECTION = 147 new AccessibilityActionCompat( 148 AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION, null); 149 150 /** 151 * Action that clicks on the node info. 152 * 153 * <p>The UI element that implements this should send a 154 * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} event. In the View system, 155 * the default handling of this action when performed by a service is to call 156 * {@link View#performClick()}, and setting a 157 * {@link View#setOnClickListener(View.OnClickListener)} automatically adds this action. 158 * 159 * <p>{@link #isClickable()} should return true if this action is available. 160 */ 161 public static final AccessibilityActionCompat ACTION_CLICK = 162 new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_CLICK, null); 163 164 /** 165 * Action that long clicks on the node. 166 * 167 * <p>The UI element that implements this should send a 168 * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED} event. In the View system, 169 * the default handling of this action when performed by a service is to call 170 * {@link View#performLongClick()}, and setting a 171 * {@link View#setOnLongClickListener(View.OnLongClickListener)} automatically adds this 172 * action. 173 * 174 * <p>{@link #isLongClickable()} should return true if this action is available. 175 */ 176 public static final AccessibilityActionCompat ACTION_LONG_CLICK = 177 new AccessibilityActionCompat( 178 AccessibilityNodeInfoCompat.ACTION_LONG_CLICK, null); 179 180 /** 181 * Action that gives accessibility focus to the node. 182 * <p>The UI element that implements this should send a 183 * {@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED} event 184 * if successful. The node that is focused should return {@code true} for 185 * {@link AccessibilityNodeInfoCompat#isAccessibilityFocused()}. 186 * 187 * <p>This is intended to be used by screen readers to assist with user navigation. Apps 188 * changing focus can confuse screen readers, so the resulting behavior can vary by device 189 * and screen reader version. 190 * <p>This is distinct from {@link #ACTION_FOCUS}, which refers to system focus. System 191 * focus is typically used to convey targets for keyboard navigation. 192 */ 193 public static final AccessibilityActionCompat ACTION_ACCESSIBILITY_FOCUS = 194 new AccessibilityActionCompat( 195 AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS, null); 196 197 /** 198 * Action that clears accessibility focus of the node. 199 * <p>The UI element that implements this should send a 200 * {@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED} event if successful. The 201 * node that is cleared should return {@code false} for 202 * {@link AccessibilityNodeInfoCompat#isAccessibilityFocused()}. 203 */ 204 public static final AccessibilityActionCompat ACTION_CLEAR_ACCESSIBILITY_FOCUS = 205 new AccessibilityActionCompat( 206 AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); 207 208 /** 209 * Action that requests to go to the next entity in this node's text 210 * at a given movement granularity. For example, move to the next character, 211 * word, etc. 212 * <p> 213 * <strong>Arguments:</strong> 214 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 215 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, 216 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 217 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 218 * <strong>Example:</strong> Move to the previous character and do not extend selection. 219 * <code><pre><p> 220 * Bundle arguments = new Bundle(); 221 * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 222 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER); 223 * arguments.putBoolean( 224 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); 225 * info.performAction( 226 * AccessibilityActionCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(), 227 * arguments); 228 * </code></pre></p> 229 * </p> 230 * 231 * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 232 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 233 * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 234 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 235 * 236 * @see AccessibilityNodeInfoCompat#setMovementGranularities(int) 237 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 238 * @see AccessibilityNodeInfoCompat#getMovementGranularities() 239 * AccessibilityNodeInfoCompat.getMovementGranularities() 240 * 241 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_CHARACTER 242 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER 243 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_WORD 244 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_WORD 245 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_LINE 246 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_LINE 247 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PARAGRAPH 248 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PARAGRAPH 249 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PAGE 250 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PAGE 251 */ 252 public static final AccessibilityActionCompat ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 253 new AccessibilityActionCompat( 254 AccessibilityNodeInfoCompat.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null, 255 MoveAtGranularityArguments.class); 256 257 /** 258 * Action that requests to go to the previous entity in this node's text 259 * at a given movement granularity. For example, move to the next character, 260 * word, etc. 261 * <p> 262 * <strong>Arguments:</strong> 263 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 264 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, 265 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 266 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 267 * <strong>Example:</strong> Move to the next character and do not extend selection. 268 * <code><pre><p> 269 * Bundle arguments = new Bundle(); 270 * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 271 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER); 272 * arguments.putBoolean( 273 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, false); 274 * info.performAction( 275 * AccessibilityActionCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(), 276 * arguments); 277 * </code></pre></p> 278 * </p> 279 * 280 * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 281 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 282 * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 283 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 284 * 285 * @see AccessibilityNodeInfoCompat#setMovementGranularities(int) 286 * AccessibilityNodeInfoCompat.setMovementGranularities(int) 287 * @see AccessibilityNodeInfoCompat#getMovementGranularities() 288 * AccessibilityNodeInfoCompat.getMovementGranularities() 289 * 290 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_CHARACTER 291 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_CHARACTER 292 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_WORD 293 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_WORD 294 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_LINE 295 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_LINE 296 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PARAGRAPH 297 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PARAGRAPH 298 * @see AccessibilityNodeInfoCompat#MOVEMENT_GRANULARITY_PAGE 299 * AccessibilityNodeInfoCompat.MOVEMENT_GRANULARITY_PAGE 300 */ 301 public static final AccessibilityActionCompat ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 302 new AccessibilityActionCompat( 303 AccessibilityNodeInfoCompat.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null, 304 MoveAtGranularityArguments.class); 305 306 /** 307 * Action to move to the next HTML element of a given type. For example, move 308 * to the BUTTON, INPUT, TABLE, etc. 309 * <p> 310 * <strong>Arguments:</strong> 311 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_HTML_ELEMENT_STRING 312 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 313 * <strong>Example:</strong> 314 * <code><pre><p> 315 * Bundle arguments = new Bundle(); 316 * arguments.putString( 317 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 318 * info.performAction( 319 * AccessibilityActionCompat.ACTION_NEXT_HTML_ELEMENT.getId(), arguments); 320 * </code></pre></p> 321 * </p> 322 */ 323 public static final AccessibilityActionCompat ACTION_NEXT_HTML_ELEMENT = 324 new AccessibilityActionCompat( 325 AccessibilityNodeInfoCompat.ACTION_NEXT_HTML_ELEMENT, null, 326 MoveHtmlArguments.class); 327 328 /** 329 * Action to move to the previous HTML element of a given type. For example, move 330 * to the BUTTON, INPUT, TABLE, etc. 331 * <p> 332 * <strong>Arguments:</strong> 333 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_HTML_ELEMENT_STRING 334 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 335 * <strong>Example:</strong> 336 * <code><pre><p> 337 * Bundle arguments = new Bundle(); 338 * arguments.putString( 339 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 340 * info.performAction( 341 * AccessibilityActionCompat.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments); 342 * </code></pre></p> 343 * </p> 344 */ 345 public static final AccessibilityActionCompat ACTION_PREVIOUS_HTML_ELEMENT = 346 new AccessibilityActionCompat( 347 AccessibilityNodeInfoCompat.ACTION_PREVIOUS_HTML_ELEMENT, null, 348 MoveHtmlArguments.class); 349 350 /** 351 * Action to scroll the node content forward. 352 */ 353 public static final AccessibilityActionCompat ACTION_SCROLL_FORWARD = 354 new AccessibilityActionCompat( 355 AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null); 356 357 /** 358 * Action to scroll the node content backward. 359 */ 360 public static final AccessibilityActionCompat ACTION_SCROLL_BACKWARD = 361 new AccessibilityActionCompat( 362 AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null); 363 364 /** 365 * Action to copy the current selection to the clipboard. 366 */ 367 public static final AccessibilityActionCompat ACTION_COPY = 368 new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_COPY, null); 369 370 /** 371 * Action to paste the current clipboard content. 372 */ 373 public static final AccessibilityActionCompat ACTION_PASTE = 374 new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_PASTE, null); 375 376 /** 377 * Action to cut the current selection and place it to the clipboard. 378 */ 379 public static final AccessibilityActionCompat ACTION_CUT = 380 new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_CUT, null); 381 382 /** 383 * Action to set the selection. Performing this action with no arguments 384 * clears the selection. 385 * <p> 386 * <strong>Arguments:</strong> 387 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_START_INT 388 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT}, 389 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_END_INT 390 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT}<br> 391 * <strong>Example:</strong> 392 * <code><pre><p> 393 * Bundle arguments = new Bundle(); 394 * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT, 1); 395 * arguments.putInt(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT, 2); 396 * info.performAction(AccessibilityActionCompat.ACTION_SET_SELECTION.getId(), arguments); 397 * </code></pre></p> 398 * </p> 399 * 400 * <p> If this is a text selection, the UI element that implements this should send a 401 * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED} event if its selection is 402 * updated. This element should also return {@code true} for 403 * {@link AccessibilityNodeInfoCompat#isTextSelectable()}. 404 * 405 * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_START_INT 406 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_START_INT 407 * @see AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SELECTION_END_INT 408 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SELECTION_END_INT 409 */ 410 public static final AccessibilityActionCompat ACTION_SET_SELECTION = 411 new AccessibilityActionCompat( 412 AccessibilityNodeInfoCompat.ACTION_SET_SELECTION, null, 413 SetSelectionArguments.class); 414 415 /** 416 * Action to expand an expandable node. 417 */ 418 public static final AccessibilityActionCompat ACTION_EXPAND = 419 new AccessibilityActionCompat( 420 AccessibilityNodeInfoCompat.ACTION_EXPAND, null); 421 422 /** 423 * Action to collapse an expandable node. 424 */ 425 public static final AccessibilityActionCompat ACTION_COLLAPSE = 426 new AccessibilityActionCompat( 427 AccessibilityNodeInfoCompat.ACTION_COLLAPSE, null); 428 429 /** 430 * Action to dismiss a dismissable node. 431 */ 432 public static final AccessibilityActionCompat ACTION_DISMISS = 433 new AccessibilityActionCompat( 434 AccessibilityNodeInfoCompat.ACTION_DISMISS, null); 435 436 /** 437 * Action that sets the text of the node. Performing the action without argument, 438 * using <code> null</code> or empty {@link CharSequence} will clear the text. This 439 * action will also put the cursor at the end of text. 440 * <p> 441 * <strong>Arguments:</strong> 442 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE 443 * AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> 444 * <strong>Example:</strong> 445 * <code><pre><p> 446 * Bundle arguments = new Bundle(); 447 * arguments.putCharSequence(AccessibilityNodeInfoCompat.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, 448 * "android"); 449 * info.performAction(AccessibilityActionCompat.ACTION_SET_TEXT.getId(), arguments); 450 * </code></pre></p> 451 * <p>The UI element that implements this should send a 452 * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED} event if its text is updated. 453 * This element should also return {@code true} for 454 * {@link AccessibilityNodeInfoCompat#isEditable()}. 455 */ 456 public static final AccessibilityActionCompat ACTION_SET_TEXT = 457 new AccessibilityActionCompat(AccessibilityNodeInfoCompat.ACTION_SET_TEXT, null, 458 SetTextArguments.class); 459 460 /** 461 * Action that requests the node make its bounding rectangle visible 462 * on the screen, scrolling if necessary just enough. 463 * 464 * @see View#requestRectangleOnScreen(Rect) 465 */ 466 public static final AccessibilityActionCompat ACTION_SHOW_ON_SCREEN = 467 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 468 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_ON_SCREEN : null, 469 android.R.id.accessibilityActionShowOnScreen, null, null, null); 470 471 /** 472 * Action that scrolls the node to make the specified collection 473 * position visible on screen. 474 * <p> 475 * <strong>Arguments:</strong> 476 * <ul> 477 * <li>{@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_ROW_INT}</li> 478 * <li>{@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_COLUMN_INT}</li> 479 * <ul> 480 * 481 * @see AccessibilityNodeInfoCompat#getCollectionInfo() 482 */ 483 public static final AccessibilityActionCompat ACTION_SCROLL_TO_POSITION = 484 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 485 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_TO_POSITION 486 : null, android.R.id.accessibilityActionScrollToPosition, null, null, 487 ScrollToPositionArguments.class); 488 489 /** 490 * Action to scroll the node content up. 491 */ 492 public static final AccessibilityActionCompat ACTION_SCROLL_UP = 493 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 494 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP : null, 495 android.R.id.accessibilityActionScrollUp, null, null, null); 496 /** 497 * Action to scroll the node content left. 498 */ 499 public static final AccessibilityActionCompat ACTION_SCROLL_LEFT = 500 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 501 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_LEFT : null, 502 android.R.id.accessibilityActionScrollLeft, null, null, null); 503 504 /** 505 * Action to scroll the node content down. 506 */ 507 public static final AccessibilityActionCompat ACTION_SCROLL_DOWN = 508 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 509 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN : null, 510 android.R.id.accessibilityActionScrollDown, null, null, null); 511 512 /** 513 * Action to scroll the node content right. 514 */ 515 public static final AccessibilityActionCompat ACTION_SCROLL_RIGHT = 516 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 517 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_RIGHT : null, 518 android.R.id.accessibilityActionScrollRight, null, null, null); 519 520 /** 521 * Action to move to the page above. 522 */ 523 public static final @NonNull AccessibilityActionCompat ACTION_PAGE_UP = 524 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 525 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_UP : null, 526 android.R.id.accessibilityActionPageUp, null, null, null); 527 528 /** 529 * Action to move to the page below. 530 */ 531 public static final @NonNull AccessibilityActionCompat ACTION_PAGE_DOWN = 532 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 533 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_DOWN : null, 534 android.R.id.accessibilityActionPageDown, null, null, null); 535 536 /** 537 * Action to move to the page left. 538 */ 539 public static final @NonNull AccessibilityActionCompat ACTION_PAGE_LEFT = 540 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 541 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT : null, 542 android.R.id.accessibilityActionPageLeft, null, null, null); 543 544 /** 545 * Action to move to the page right. 546 */ 547 public static final @NonNull AccessibilityActionCompat ACTION_PAGE_RIGHT = 548 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 29 549 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT : null, 550 android.R.id.accessibilityActionPageRight, null, null, null); 551 552 /** 553 * Action that context clicks the node. 554 * 555 * <p>The UI element that implements this should send a 556 * {@link AccessibilityEvent#TYPE_VIEW_CONTEXT_CLICKED} event. In the View system, 557 * the default handling of this action when performed by a service is to call 558 * {@link View#performContextClick()}, and setting a 559 * {@link View#setOnContextClickListener(View.OnContextClickListener)} automatically adds 560 * this action. 561 * 562 * <p>A context click usually occurs from a mouse pointer right-click or a stylus button 563 * press. 564 * 565 * <p>{@link #isContextClickable()} should return true if this action is available. 566 */ 567 public static final AccessibilityActionCompat ACTION_CONTEXT_CLICK = 568 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 23 569 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_CONTEXT_CLICK : null, 570 android.R.id.accessibilityActionContextClick, null, null, null); 571 572 /** 573 * Action that sets progress between {@link RangeInfoCompat#getMin() RangeInfo.getMin()} and 574 * {@link RangeInfoCompat#getMax() RangeInfo.getMax()}. It should use the same value type as 575 * {@link RangeInfoCompat#getType() RangeInfo.getType()} 576 * <p> 577 * <strong>Arguments:</strong> 578 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_PROGRESS_VALUE} 579 * 580 * @see RangeInfoCompat 581 */ 582 public static final AccessibilityActionCompat ACTION_SET_PROGRESS = 583 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 24 584 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS : null, 585 android.R.id.accessibilityActionSetProgress, null, null, 586 SetProgressArguments.class); 587 588 /** 589 * Action to move a window to a new location. 590 * <p> 591 * <strong>Arguments:</strong> 592 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_X} 593 * {@link AccessibilityNodeInfoCompat#ACTION_ARGUMENT_MOVE_WINDOW_Y} 594 */ 595 public static final AccessibilityActionCompat ACTION_MOVE_WINDOW = 596 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 26 597 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_MOVE_WINDOW : null, 598 android.R.id.accessibilityActionMoveWindow, null, null, 599 MoveWindowArguments.class); 600 601 /** 602 * Action to show a tooltip. 603 */ 604 public static final AccessibilityActionCompat ACTION_SHOW_TOOLTIP = 605 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 28 606 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP : null, 607 android.R.id.accessibilityActionShowTooltip, null, null, null); 608 609 /** 610 * Action to hide a tooltip. A node should expose this action only for views that are 611 * currently showing a tooltip. 612 */ 613 public static final AccessibilityActionCompat ACTION_HIDE_TOOLTIP = 614 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 28 615 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP : null, 616 android.R.id.accessibilityActionHideTooltip, null, null, null); 617 618 /** 619 * Action that presses and holds a node. 620 * <p> 621 * This action is for nodes that have distinct behavior that depends on how long a press is 622 * held. Nodes having a single action for long press should use {@link #ACTION_LONG_CLICK} 623 * instead of this action, and nodes should not expose both actions. 624 * <p> 625 * When calling {@code performAction(ACTION_PRESS_AND_HOLD, bundle}, use 626 * {@link #ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT} to specify how long the 627 * node is pressed. The first time an accessibility service performs ACTION_PRES_AND_HOLD 628 * on a node, it must specify 0 as ACTION_ARGUMENT_PRESS_AND_HOLD, so the application is 629 * notified that the held state has started. To ensure reasonable behavior, the values 630 * must be increased incrementally and may not exceed 10,000. UIs requested 631 * to hold for times outside of this range should ignore the action. 632 * <p> 633 * The total time the element is held could be specified by an accessibility user up-front, 634 * or may depend on what happens on the UI as the user continues to request the hold. 635 * <p> 636 * <strong>Note:</strong> The time between dispatching the action and it arriving in the 637 * UI process is not guaranteed. It is possible on a busy system for the time to expire 638 * unexpectedly. For the case of holding down a key for a repeating action, a delayed 639 * arrival should be benign. Please do not use this sort of action in cases where such 640 * delays will lead to unexpected UI behavior. 641 * <p> 642 */ 643 public static final @NonNull AccessibilityActionCompat ACTION_PRESS_AND_HOLD = 644 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 30 645 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PRESS_AND_HOLD : null, 646 android.R.id.accessibilityActionPressAndHold, null, null, null); 647 648 /** 649 * Action to send an ime actionId which is from 650 * {@link android.view.inputmethod.EditorInfo#actionId}. This ime actionId sets by 651 * {@link android.widget.TextView#setImeActionLabel(CharSequence, int)}, or it would be 652 * {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED} if no specific 653 * actionId has set. A node should expose this action only for views that are currently 654 * with input focus and editable. 655 */ 656 public static final @NonNull AccessibilityActionCompat ACTION_IME_ENTER = 657 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 30 658 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_IME_ENTER : null, 659 android.R.id.accessibilityActionImeEnter, null, null, null); 660 661 /** 662 * Action to start a drag. 663 * <p> 664 * This action initiates a drag & drop within the system. The source's dragged content is 665 * prepared before the drag begins. In View, this action should prepare the arguments to 666 * {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}} and then 667 * call the method. The equivalent should be performed for other UI toolkits. 668 * </p> 669 * 670 * @see AccessibilityEventCompat#CONTENT_CHANGE_TYPE_DRAG_STARTED 671 */ 672 public static final @NonNull AccessibilityActionCompat ACTION_DRAG_START = 673 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 32 674 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_DRAG_START : null, 675 android.R.id.accessibilityActionDragStart, null, null, null); 676 677 /** 678 * Action to trigger a drop of the content being dragged. 679 * <p> 680 * This action is added to potential drop targets if the source started a drag with 681 * {@link #ACTION_DRAG_START}. In View, these targets are Views that accepted 682 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} and have an 683 * {@link View.OnDragListener}. 684 * </p> 685 * 686 * @see AccessibilityEventCompat#CONTENT_CHANGE_TYPE_DRAG_DROPPED 687 */ 688 public static final @NonNull AccessibilityActionCompat ACTION_DRAG_DROP = 689 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 32 690 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_DRAG_DROP : null, 691 android.R.id.accessibilityActionDragDrop, null, null, null); 692 693 /** 694 * Action to cancel a drag. 695 * <p> 696 * This action is added to the source that started a drag with {@link #ACTION_DRAG_START}. 697 * </p> 698 * 699 * @see AccessibilityEventCompat#CONTENT_CHANGE_TYPE_DRAG_CANCELLED 700 */ 701 public static final @NonNull AccessibilityActionCompat ACTION_DRAG_CANCEL = 702 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 32 703 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_DRAG_CANCEL : null, 704 android.R.id.accessibilityActionDragCancel, null, null, null); 705 706 /** 707 * Action to show suggestions for editable text. 708 */ 709 public static final @NonNull AccessibilityActionCompat ACTION_SHOW_TEXT_SUGGESTIONS = 710 new AccessibilityActionCompat(Build.VERSION.SDK_INT >= 33 711 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TEXT_SUGGESTIONS 712 : null, android.R.id.accessibilityActionShowTextSuggestions, null, 713 null, null); 714 715 /** 716 * Action that brings fully on screen the next node in the specified direction. 717 * 718 * <p> 719 * This should include wrapping around to the next/previous row, column, etc. in a 720 * collection if one is available. If there is no node in that direction, the action 721 * should fail and return false. 722 * </p> 723 * <p> 724 * This action should be used instead of 725 * {@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION} when a widget does not 726 * have clear row and column semantics or if a directional search is needed to find a 727 * node in a complex ViewGroup where individual nodes may span multiple rows or 728 * columns. The implementing widget must send a 729 * {@link AccessibilityEventCompat#TYPE_VIEW_TARGETED_BY_SCROLL} accessibility event 730 * with the scroll target as the source. An accessibility service can listen for this 731 * event, inspect its source, and use the result when determining where to place 732 * accessibility focus. 733 * <p> 734 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_DIRECTION_INT}. This is a 735 * required argument.<br> 736 * </p> 737 */ 738 @OptIn(markerClass = androidx.core.os.BuildCompat.PrereleaseSdkCheck.class) 739 public static final @NonNull AccessibilityActionCompat ACTION_SCROLL_IN_DIRECTION = 740 new AccessibilityActionCompat( 741 Build.VERSION.SDK_INT >= 34 ? Api34Impl.getActionScrollInDirection() : null, 742 android.R.id.accessibilityActionScrollInDirection, null, null, null); 743 744 final Object mAction; 745 private final int mId; 746 private final Class<? extends CommandArguments> mViewCommandArgumentClass; 747 748 /** 749 */ 750 @RestrictTo(LIBRARY_GROUP_PREFIX) 751 protected final AccessibilityViewCommand mCommand; 752 753 /** 754 * Creates a new instance. 755 * 756 * @param actionId The action id. 757 * @param label The action label. 758 */ AccessibilityActionCompat(int actionId, CharSequence label)759 public AccessibilityActionCompat(int actionId, CharSequence label) { 760 this(null, actionId, label, null, null); 761 } 762 763 /** 764 * Creates a new instance. 765 * 766 * @param actionId The action id. 767 * @param label The action label. 768 * @param command The command performed when the service requests the action 769 */ 770 @RestrictTo(LIBRARY_GROUP_PREFIX) AccessibilityActionCompat(int actionId, CharSequence label, AccessibilityViewCommand command)771 public AccessibilityActionCompat(int actionId, CharSequence label, 772 AccessibilityViewCommand command) { 773 this(null, actionId, label, command, null); 774 } 775 AccessibilityActionCompat(Object action)776 AccessibilityActionCompat(Object action) { 777 this(action, 0, null, null, null); 778 } 779 AccessibilityActionCompat(int actionId, CharSequence label, Class<? extends CommandArguments> viewCommandArgumentClass)780 private AccessibilityActionCompat(int actionId, CharSequence label, 781 Class<? extends CommandArguments> viewCommandArgumentClass) { 782 this(null, actionId, label, null, viewCommandArgumentClass); 783 } 784 AccessibilityActionCompat(Object action, int id, CharSequence label, AccessibilityViewCommand command, Class<? extends CommandArguments> viewCommandArgumentClass)785 AccessibilityActionCompat(Object action, int id, CharSequence label, 786 AccessibilityViewCommand command, 787 Class<? extends CommandArguments> viewCommandArgumentClass) { 788 mId = id; 789 mCommand = command; 790 if (action == null) { 791 mAction = new AccessibilityNodeInfo.AccessibilityAction(id, label); 792 } else { 793 mAction = action; 794 } 795 mViewCommandArgumentClass = viewCommandArgumentClass; 796 } 797 798 /** 799 * Gets the id for this action. 800 * 801 * @return The action id. 802 */ getId()803 public int getId() { 804 return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getId(); 805 } 806 807 /** 808 * Gets the label for this action. Its purpose is to describe the 809 * action to user. 810 * 811 * @return The label. 812 */ getLabel()813 public CharSequence getLabel() { 814 return ((AccessibilityNodeInfo.AccessibilityAction) mAction).getLabel(); 815 } 816 817 /** 818 * Performs the action. 819 * @return If the action was handled. 820 * @param view View to act upon. 821 * @param arguments Optional action arguments. 822 */ 823 @RestrictTo(LIBRARY_GROUP_PREFIX) perform(View view, Bundle arguments)824 public boolean perform(View view, Bundle arguments) { 825 if (mCommand != null) { 826 CommandArguments viewCommandArgument = null; 827 if (mViewCommandArgumentClass != null) { 828 try { 829 viewCommandArgument = 830 mViewCommandArgumentClass.getDeclaredConstructor().newInstance(); 831 viewCommandArgument.setBundle(arguments); 832 } catch (Exception e) { 833 final String className = mViewCommandArgumentClass == null 834 ? "null" : mViewCommandArgumentClass.getName(); 835 Log.e(TAG, "Failed to execute command with argument class " 836 + "ViewCommandArgument: " + className, e); 837 } 838 } 839 return mCommand.perform(view, viewCommandArgument); 840 } 841 return false; 842 } 843 844 /** 845 */ 846 @RestrictTo(LIBRARY_GROUP_PREFIX) createReplacementAction(CharSequence label, AccessibilityViewCommand command)847 public AccessibilityActionCompat createReplacementAction(CharSequence label, 848 AccessibilityViewCommand command) { 849 return new AccessibilityActionCompat(null, mId, label, command, 850 mViewCommandArgumentClass); 851 } 852 853 @Override hashCode()854 public int hashCode() { 855 return mAction != null ? mAction.hashCode() : 0; 856 } 857 858 @Override equals(@ullable Object obj)859 public boolean equals(@Nullable Object obj) { 860 if (obj == null) { 861 return false; 862 } 863 if (!(obj instanceof AccessibilityNodeInfoCompat.AccessibilityActionCompat)) { 864 return false; 865 } 866 AccessibilityNodeInfoCompat.AccessibilityActionCompat other = 867 (AccessibilityNodeInfoCompat.AccessibilityActionCompat) obj; 868 if (mAction == null) { 869 if (other.mAction != null) { 870 return false; 871 } 872 } else if (!mAction.equals(other.mAction)) { 873 return false; 874 } 875 return true; 876 } 877 878 @Override toString()879 public @NonNull String toString() { 880 StringBuilder builder = new StringBuilder(); 881 builder.append("AccessibilityActionCompat: "); 882 // Mirror AccessibilityNodeInfoCompat.toString's action string. 883 String actionName = getActionSymbolicName(mId); 884 if (actionName.equals("ACTION_UNKNOWN") && getLabel() != null) { 885 actionName = getLabel().toString(); 886 } 887 builder.append(actionName); 888 return builder.toString(); 889 } 890 } 891 892 /** 893 * Class with information if a node is a collection. 894 * <p> 895 * A collection of items has rows and columns and may be marked as hierarchical. 896 * 897 * <p> 898 * For example, a list where the items are placed in a vertical layout is a collection with one 899 * column and as many rows as the list items. This collection has 3 rows and 1 column and should 900 * not be marked as hierarchical since items do not exist at different levels/ranks and there 901 * are no nested collections. 902 * <ul> 903 * <li>Item 1</li> 904 * <li>Item 2</li> 905 * <li>Item 3</li> 906 * </ul> 907 * 908 * <p> 909 * A table is a collection with several rows and several columns. This collection has 2 rows and 910 * 3 columns and is not marked as hierarchical: 911 *<table> 912 * <tr> 913 * <td>Item 1</td> 914 * <td>Item 2</td> 915 * <td>Item 3</td> 916 * </tr> 917 * <tr> 918 * <td>Item 4</td> 919 * <td>Item 5</td> 920 * <td>Item 6</td> 921 * </tr> 922 * </table> 923 * 924 * <p> 925 * Nested collections could be marked as hierarchical. To add outer and inner collections to the 926 * same hierarchy, mark them both as hierarchical. 927 * 928 * <p> For example, if you have a collection with two lists - this collection has an outer 929 * list with 3 rows and 1 column and an inner list within "Item 2" with 2 rows and 1 - 930 * you can mark both the outer list and the inner list as hierarchical to make them part of 931 * the same hierarchy. If a collection does not have any ancestor or descendant hierarchical 932 * collections, it does not need to be marked as hierarchical. 933 * <ul> 934 * <li>Item 1</li> 935 * <li> Item 2 936 * <ul> 937 * <li>Item 2A</li> 938 * <li>Item 2B</li> 939 * </ul> 940 * </li> 941 * <li>Item 3</li> 942 * </ul> 943 * 944 * <p> 945 * To be a valid list, a collection has 1 row and any number of columns or 1 column and any 946 * number of rows. 947 * </p> 948 */ 949 public static class CollectionInfoCompat { 950 /** Selection mode where items are not selectable. */ 951 public static final int SELECTION_MODE_NONE = 0; 952 953 /** Selection mode where a single item may be selected. */ 954 public static final int SELECTION_MODE_SINGLE = 1; 955 956 /** Selection mode where multiple items may be selected. */ 957 public static final int SELECTION_MODE_MULTIPLE = 2; 958 959 /** 960 * Constant to denote a missing collection count. 961 * 962 * This should be used for {@code mItemCount} and 963 * {@code mImportantForAccessibilityItemCount} when values for those fields are not known. 964 */ 965 public static final int UNDEFINED = AccessibilityNodeInfo.CollectionInfo.UNDEFINED; 966 967 final Object mInfo; 968 969 /** 970 * Returns a cached instance if such is available otherwise a new one. 971 * 972 * @param rowCount The number of rows. 973 * @param columnCount The number of columns. 974 * @param hierarchical Whether the collection is hierarchical. 975 * @param selectionMode The collection's selection mode, one of: 976 * <ul> 977 * <li>{@link #SELECTION_MODE_NONE} 978 * <li>{@link #SELECTION_MODE_SINGLE} 979 * <li>{@link #SELECTION_MODE_MULTIPLE} 980 * </ul> 981 * 982 * @return An instance. 983 */ obtain(int rowCount, int columnCount, boolean hierarchical, int selectionMode)984 public static CollectionInfoCompat obtain(int rowCount, int columnCount, 985 boolean hierarchical, int selectionMode) { 986 return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain( 987 rowCount, columnCount, hierarchical, selectionMode)); 988 } 989 990 /** 991 * Returns a cached instance if such is available otherwise a new one. 992 * 993 * @param rowCount The number of rows, or -1 if count is unknown. 994 * @param columnCount The number of columns , or -1 if count is unknown. 995 * @param hierarchical Whether the collection is hierarchical. 996 * 997 * @return An instance. 998 */ obtain(int rowCount, int columnCount, boolean hierarchical)999 public static CollectionInfoCompat obtain(int rowCount, int columnCount, 1000 boolean hierarchical) { 1001 return new CollectionInfoCompat(AccessibilityNodeInfo.CollectionInfo.obtain( 1002 rowCount, columnCount, hierarchical)); 1003 } 1004 CollectionInfoCompat(Object info)1005 CollectionInfoCompat(Object info) { 1006 mInfo = info; 1007 } 1008 1009 /** 1010 * Gets the number of columns. 1011 * 1012 * @return The column count, or -1 if count is unknown. 1013 */ getColumnCount()1014 public int getColumnCount() { 1015 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getColumnCount(); 1016 } 1017 1018 /** 1019 * Gets the number of rows. 1020 * 1021 * @return The row count, or -1 if count is unknown. 1022 */ getRowCount()1023 public int getRowCount() { 1024 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getRowCount(); 1025 } 1026 1027 /** 1028 * Gets if the collection is a hierarchically ordered. 1029 * 1030 * @return Whether the collection is hierarchical. 1031 */ isHierarchical()1032 public boolean isHierarchical() { 1033 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).isHierarchical(); 1034 } 1035 1036 /** 1037 * Gets the collection's selection mode. 1038 * 1039 * @return The collection's selection mode, one of: 1040 * <ul> 1041 * <li>{@link #SELECTION_MODE_NONE} 1042 * <li>{@link #SELECTION_MODE_SINGLE} 1043 * <li>{@link #SELECTION_MODE_MULTIPLE} 1044 * </ul> 1045 */ getSelectionMode()1046 public int getSelectionMode() { 1047 return ((AccessibilityNodeInfo.CollectionInfo) mInfo).getSelectionMode(); 1048 } 1049 1050 /** 1051 * Gets the number of items in the collection. 1052 * 1053 * @return The count of items, which may be {@code UNDEFINED} if the count is not known. 1054 */ getItemCount()1055 public int getItemCount() { 1056 if (Build.VERSION.SDK_INT >= 35) { 1057 return Api35Impl.getItemCount(mInfo); 1058 } 1059 return UNDEFINED; 1060 } 1061 1062 /** 1063 * Gets the number of items in the collection considered important for accessibility. 1064 * 1065 * @return The count of items important for accessibility, which may be {@code UNDEFINED} 1066 * if the count is not known. 1067 */ getImportantForAccessibilityItemCount()1068 public int getImportantForAccessibilityItemCount() { 1069 if (Build.VERSION.SDK_INT >= 35) { 1070 return Api35Impl.getImportantForAccessibilityItemCount(mInfo); 1071 } 1072 return UNDEFINED; 1073 } 1074 1075 /** 1076 * Class for building {@link CollectionInfoCompat} objects. 1077 */ 1078 public static final class Builder { 1079 private int mRowCount = 0; 1080 private int mColumnCount = 0; 1081 private boolean mHierarchical = false; 1082 private int mSelectionMode; 1083 private int mItemCount = AccessibilityNodeInfo.CollectionInfo.UNDEFINED; 1084 private int mImportantForAccessibilityItemCount = 1085 AccessibilityNodeInfo.CollectionInfo.UNDEFINED; 1086 1087 /** 1088 * Creates a new Builder. 1089 */ Builder()1090 public Builder() { 1091 } 1092 1093 /** 1094 * Sets the row count. 1095 * @param rowCount The number of rows in the collection. 1096 * @return This builder. 1097 */ setRowCount(int rowCount)1098 public CollectionInfoCompat.@NonNull Builder setRowCount(int rowCount) { 1099 mRowCount = rowCount; 1100 return this; 1101 } 1102 1103 /** 1104 * Sets the column count. 1105 * @param columnCount The number of columns in the collection. 1106 * @return This builder. 1107 */ setColumnCount(int columnCount)1108 public CollectionInfoCompat.@NonNull Builder setColumnCount(int columnCount) { 1109 mColumnCount = columnCount; 1110 return this; 1111 } 1112 /** 1113 * Sets whether the collection is hierarchical. 1114 * @param hierarchical Whether the collection is hierarchical. 1115 * @return This builder. 1116 */ setHierarchical(boolean hierarchical)1117 public CollectionInfoCompat.@NonNull Builder setHierarchical(boolean hierarchical) { 1118 mHierarchical = hierarchical; 1119 return this; 1120 } 1121 1122 /** 1123 * Sets the selection mode. 1124 * @param selectionMode The selection mode. 1125 * @return This builder. 1126 */ setSelectionMode(int selectionMode)1127 public CollectionInfoCompat.@NonNull Builder setSelectionMode(int selectionMode) { 1128 mSelectionMode = selectionMode; 1129 return this; 1130 } 1131 1132 /** 1133 * Sets the number of items in the collection. Can be optionally set for ViewGroups with 1134 * clear row and column semantics; should be set for all other clients. 1135 * 1136 * @param itemCount The number of items in the collection. This should be set to 1137 * {@code UNDEFINED} if the item count is not known. 1138 * @return This builder. 1139 */ setItemCount(int itemCount)1140 public CollectionInfoCompat.@NonNull Builder setItemCount(int itemCount) { 1141 mItemCount = itemCount; 1142 return this; 1143 } 1144 1145 /** 1146 * Sets the number of views considered important for accessibility. 1147 * @param importantForAccessibilityItemCount The number of items important for 1148 * accessibility. 1149 * @return This builder. 1150 */ setImportantForAccessibilityItemCount( int importantForAccessibilityItemCount)1151 public CollectionInfoCompat.@NonNull Builder setImportantForAccessibilityItemCount( 1152 int importantForAccessibilityItemCount) { 1153 mImportantForAccessibilityItemCount = importantForAccessibilityItemCount; 1154 return this; 1155 } 1156 1157 /** 1158 * Creates a new {@link CollectionInfoCompat} instance. 1159 */ build()1160 public @NonNull CollectionInfoCompat build() { 1161 if (Build.VERSION.SDK_INT >= 35) { 1162 return Api35Impl.buildCollectionInfoCompat(mRowCount, mColumnCount, 1163 mHierarchical, mSelectionMode, mItemCount, 1164 mImportantForAccessibilityItemCount); 1165 } 1166 1167 return CollectionInfoCompat.obtain(mRowCount, mColumnCount, mHierarchical, 1168 mSelectionMode); 1169 } 1170 } 1171 } 1172 1173 /** 1174 * Class with information if a node is a collection item. 1175 * <p> 1176 * A collection item is contained in a collection, it starts at 1177 * a given row and column in the collection, and spans one or 1178 * more rows and columns. For example, a header of two related 1179 * table columns starts at the first row and the first column, 1180 * spans one row and two columns. 1181 * </p> 1182 */ 1183 public static class CollectionItemInfoCompat { 1184 1185 final Object mInfo; 1186 1187 /** 1188 * Returns a cached instance if such is available otherwise a new one. 1189 * 1190 * @param rowIndex The row index at which the item is located. 1191 * @param rowSpan The number of rows the item spans. 1192 * @param columnIndex The column index at which the item is located. 1193 * @param columnSpan The number of columns the item spans. 1194 * @param heading Whether the item is a heading. This should be set to false and the newer 1195 * {@link AccessibilityNodeInfoCompat#setHeading(boolean)} used to identify 1196 * headings. 1197 * @param selected Whether the item is selected. 1198 * @return An instance. 1199 */ obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading, boolean selected)1200 public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan, 1201 int columnIndex, int columnSpan, boolean heading, boolean selected) { 1202 return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain( 1203 rowIndex, rowSpan, columnIndex, columnSpan, heading, selected)); 1204 } 1205 1206 /** 1207 * Returns a cached instance if such is available otherwise a new one. 1208 * 1209 * @param rowIndex The row index at which the item is located. 1210 * @param rowSpan The number of rows the item spans. 1211 * @param columnIndex The column index at which the item is located. 1212 * @param columnSpan The number of columns the item spans. 1213 * @param heading Whether the item is a heading. This should be set to false and the newer 1214 * {@link AccessibilityNodeInfoCompat#setHeading(boolean)} used to identify 1215 * headings. 1216 * @return An instance. 1217 */ obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading)1218 public static CollectionItemInfoCompat obtain(int rowIndex, int rowSpan, 1219 int columnIndex, int columnSpan, boolean heading) { 1220 return new CollectionItemInfoCompat(AccessibilityNodeInfo.CollectionItemInfo.obtain( 1221 rowIndex, rowSpan, columnIndex, columnSpan, heading)); 1222 } 1223 CollectionItemInfoCompat(Object info)1224 CollectionItemInfoCompat(Object info) { 1225 mInfo = info; 1226 } 1227 1228 /** 1229 * Gets the column index at which the item is located. 1230 * 1231 * @return The column index. 1232 */ getColumnIndex()1233 public int getColumnIndex() { 1234 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnIndex(); 1235 } 1236 1237 /** 1238 * Gets the number of columns the item spans. 1239 * 1240 * @return The column span. 1241 */ getColumnSpan()1242 public int getColumnSpan() { 1243 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getColumnSpan(); 1244 } 1245 1246 /** 1247 * Gets the row index at which the item is located. 1248 * 1249 * @return The row index. 1250 */ getRowIndex()1251 public int getRowIndex() { 1252 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowIndex(); 1253 } 1254 1255 /** 1256 * Gets the number of rows the item spans. 1257 * 1258 * @return The row span. 1259 */ getRowSpan()1260 public int getRowSpan() { 1261 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).getRowSpan(); 1262 } 1263 1264 /** 1265 * Gets if the collection item is a heading. For example, section 1266 * heading, table header, etc. 1267 * 1268 * @return If the item is a heading. 1269 * @deprecated Use {@link AccessibilityNodeInfoCompat#isHeading()} 1270 */ 1271 @SuppressWarnings("deprecation") 1272 @Deprecated isHeading()1273 public boolean isHeading() { 1274 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isHeading(); 1275 } 1276 1277 /** 1278 * Gets if the collection item is selected. 1279 * 1280 * @return If the item is selected. 1281 */ isSelected()1282 public boolean isSelected() { 1283 return ((AccessibilityNodeInfo.CollectionItemInfo) mInfo).isSelected(); 1284 } 1285 1286 /** 1287 * Gets the row title at which the item is located. 1288 * 1289 * @return The row title. 1290 */ getRowTitle()1291 public @Nullable String getRowTitle() { 1292 if (Build.VERSION.SDK_INT >= 33) { 1293 return Api33Impl.getCollectionItemRowTitle(mInfo); 1294 } else { 1295 return null; 1296 } 1297 } 1298 1299 /** 1300 * Gets the column title at which the item is located. 1301 * 1302 * @return The column title. 1303 */ getColumnTitle()1304 public @Nullable String getColumnTitle() { 1305 if (Build.VERSION.SDK_INT >= 33) { 1306 return Api33Impl.getCollectionItemColumnTitle(mInfo); 1307 } else { 1308 return null; 1309 } 1310 } 1311 1312 /** 1313 * Builder for creating {@link CollectionItemInfoCompat} objects. 1314 */ 1315 public static final class Builder { 1316 private boolean mHeading; 1317 private int mColumnIndex; 1318 private int mRowIndex; 1319 private int mColumnSpan; 1320 private int mRowSpan; 1321 private boolean mSelected; 1322 private String mRowTitle; 1323 private String mColumnTitle; 1324 1325 /** 1326 * Creates a new Builder. 1327 */ Builder()1328 public Builder() { 1329 } 1330 1331 /** 1332 * Sets the collection item is a heading. 1333 * 1334 * @param heading The heading state 1335 * @return This builder 1336 */ setHeading(boolean heading)1337 public @NonNull Builder setHeading(boolean heading) { 1338 mHeading = heading; 1339 return this; 1340 } 1341 1342 /** 1343 * Sets the column index at which the item is located. 1344 * 1345 * @param columnIndex The column index 1346 * @return This builder 1347 */ setColumnIndex(int columnIndex)1348 public @NonNull Builder setColumnIndex(int columnIndex) { 1349 mColumnIndex = columnIndex; 1350 return this; 1351 } 1352 1353 /** 1354 * Sets the row index at which the item is located. 1355 * 1356 * @param rowIndex The row index 1357 * @return This builder 1358 */ setRowIndex(int rowIndex)1359 public @NonNull Builder setRowIndex(int rowIndex) { 1360 mRowIndex = rowIndex; 1361 return this; 1362 } 1363 1364 /** 1365 * Sets the number of columns the item spans. 1366 * 1367 * @param columnSpan The number of columns spans 1368 * @return This builder 1369 */ setColumnSpan(int columnSpan)1370 public @NonNull Builder setColumnSpan(int columnSpan) { 1371 mColumnSpan = columnSpan; 1372 return this; 1373 } 1374 1375 /** 1376 * Sets the number of rows the item spans. 1377 * 1378 * @param rowSpan The number of rows spans 1379 * @return This builder 1380 */ setRowSpan(int rowSpan)1381 public @NonNull Builder setRowSpan(int rowSpan) { 1382 mRowSpan = rowSpan; 1383 return this; 1384 } 1385 1386 /** 1387 * Sets the collection item is selected. 1388 * 1389 * @param selected The number of rows spans 1390 * @return This builder 1391 */ setSelected(boolean selected)1392 public @NonNull Builder setSelected(boolean selected) { 1393 mSelected = selected; 1394 return this; 1395 } 1396 1397 /** 1398 * Sets the row title at which the item is located. 1399 * 1400 * @param rowTitle The row title 1401 * @return This builder 1402 */ setRowTitle(@ullable String rowTitle)1403 public @NonNull Builder setRowTitle(@Nullable String rowTitle) { 1404 mRowTitle = rowTitle; 1405 return this; 1406 } 1407 1408 /** 1409 * Sets the column title at which the item is located. 1410 * 1411 * @param columnTitle The column title 1412 * @return This builder 1413 */ setColumnTitle(@ullable String columnTitle)1414 public @NonNull Builder setColumnTitle(@Nullable String columnTitle) { 1415 mColumnTitle = columnTitle; 1416 return this; 1417 } 1418 1419 /** 1420 * Builds and returns a {@link AccessibilityNodeInfo.CollectionItemInfo}. 1421 */ build()1422 public @NonNull CollectionItemInfoCompat build() { 1423 if (Build.VERSION.SDK_INT >= 33) { 1424 return Api33Impl.buildCollectionItemInfoCompat(mHeading, mColumnIndex, 1425 mRowIndex, mColumnSpan, mRowSpan, mSelected, mRowTitle, mColumnTitle); 1426 } else { 1427 return new CollectionItemInfoCompat( 1428 AccessibilityNodeInfo.CollectionItemInfo.obtain(mRowIndex, mRowSpan, 1429 mColumnIndex, mColumnSpan, mHeading, mSelected)); 1430 } 1431 } 1432 } 1433 } 1434 1435 /** 1436 * Class with information if a node is a range. 1437 */ 1438 public static class RangeInfoCompat { 1439 /** Range type: integer. */ 1440 public static final int RANGE_TYPE_INT = 0; 1441 /** Range type: float. */ 1442 public static final int RANGE_TYPE_FLOAT = 1; 1443 /** Range type: percent with values from zero to one.*/ 1444 public static final int RANGE_TYPE_PERCENT = 2; 1445 1446 /** 1447 * Obtains a cached instance if such is available otherwise a new one. 1448 * 1449 * @param type The type of the range. 1450 * @param min The min value. 1451 * @param max The max value. 1452 * @param current The current value. 1453 * @return The instance 1454 */ obtain(int type, float min, float max, float current)1455 public static RangeInfoCompat obtain(int type, float min, float max, float current) { 1456 return new RangeInfoCompat( 1457 AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current)); 1458 } 1459 1460 final Object mInfo; 1461 RangeInfoCompat(Object info)1462 RangeInfoCompat(Object info) { 1463 mInfo = info; 1464 } 1465 1466 /** 1467 * Creates a new range. 1468 * 1469 * @param type The type of the range. 1470 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no 1471 * minimum. 1472 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no 1473 * maximum. 1474 * @param current The current value. 1475 */ RangeInfoCompat(int type, float min, float max, float current)1476 public RangeInfoCompat(int type, float min, float max, float current) { 1477 if (Build.VERSION.SDK_INT >= 30) { 1478 mInfo = Api30Impl.createRangeInfo(type, min, max, current); 1479 } else { 1480 mInfo = AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current); 1481 } 1482 } 1483 1484 /** 1485 * Gets the current value. 1486 * 1487 * @return The current value. 1488 */ getCurrent()1489 public float getCurrent() { 1490 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getCurrent(); 1491 } 1492 1493 /** 1494 * Gets the max value. 1495 * 1496 * @return The max value. 1497 */ getMax()1498 public float getMax() { 1499 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMax(); 1500 } 1501 1502 /** 1503 * Gets the min value. 1504 * 1505 * @return The min value. 1506 */ getMin()1507 public float getMin() { 1508 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getMin(); 1509 } 1510 1511 /** 1512 * Gets the range type. 1513 * 1514 * @return The range type. 1515 * 1516 * @see #RANGE_TYPE_INT 1517 * @see #RANGE_TYPE_FLOAT 1518 * @see #RANGE_TYPE_PERCENT 1519 */ getType()1520 public int getType() { 1521 return ((AccessibilityNodeInfo.RangeInfo) mInfo).getType(); 1522 } 1523 } 1524 1525 /** 1526 * Class with information of touch delegated views and regions. 1527 */ 1528 public static final class TouchDelegateInfoCompat { 1529 final TouchDelegateInfo mInfo; 1530 1531 /** 1532 * Create a new instance of {@link TouchDelegateInfoCompat}. 1533 * 1534 * @param targetMap A map from regions (in view coordinates) to delegated views. 1535 */ TouchDelegateInfoCompat(@onNull Map<Region, View> targetMap)1536 public TouchDelegateInfoCompat(@NonNull Map<Region, View> targetMap) { 1537 if (Build.VERSION.SDK_INT >= 29) { 1538 mInfo = new TouchDelegateInfo(targetMap); 1539 } else { 1540 mInfo = null; 1541 } 1542 } 1543 TouchDelegateInfoCompat(@onNull TouchDelegateInfo info)1544 TouchDelegateInfoCompat(@NonNull TouchDelegateInfo info) { 1545 mInfo = info; 1546 } 1547 1548 /** 1549 * Returns the number of touch delegate target region. 1550 * <p> 1551 * Compatibility: 1552 * <ul> 1553 * <li>API < 29: Always returns {@code 0}</li> 1554 * </ul> 1555 * 1556 * @return Number of touch delegate target region. 1557 */ getRegionCount()1558 public @IntRange(from = 0) int getRegionCount() { 1559 if (Build.VERSION.SDK_INT >= 29) { 1560 return mInfo.getRegionCount(); 1561 } 1562 return 0; 1563 } 1564 1565 /** 1566 * Return the {@link Region} at the given index. 1567 * <p> 1568 * Compatibility: 1569 * <ul> 1570 * <li>API < 29: Always returns {@code null}</li> 1571 * </ul> 1572 * 1573 * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1. 1574 * @return Returns the {@link Region} stored at the given index. 1575 */ getRegionAt(@ntRangefrom = 0) int index)1576 public @Nullable Region getRegionAt(@IntRange(from = 0) int index) { 1577 if (Build.VERSION.SDK_INT >= 29) { 1578 return mInfo.getRegionAt(index); 1579 } 1580 return null; 1581 } 1582 1583 /** 1584 * Return the target {@link AccessibilityNodeInfoCompat} for the given {@link Region}. 1585 * <p> 1586 * <strong>Note:</strong> This api can only be called from 1587 * {@link android.accessibilityservice.AccessibilityService}. 1588 * </p> 1589 * <p> 1590 * Compatibility: 1591 * <ul> 1592 * <li>API < 29: Always returns {@code null}</li> 1593 * </ul> 1594 * 1595 * @param region The region retrieved from {@link #getRegionAt(int)}. 1596 * @return The target node associates with the given region. 1597 */ getTargetForRegion(@onNull Region region)1598 public @Nullable AccessibilityNodeInfoCompat getTargetForRegion(@NonNull Region region) { 1599 if (Build.VERSION.SDK_INT >= 29) { 1600 AccessibilityNodeInfo info = mInfo.getTargetForRegion(region); 1601 if (info != null) { 1602 return AccessibilityNodeInfoCompat.wrap(info); 1603 } 1604 } 1605 return null; 1606 } 1607 } 1608 1609 private static final String ROLE_DESCRIPTION_KEY = 1610 "AccessibilityNodeInfo.roleDescription"; 1611 1612 private static final String PANE_TITLE_KEY = 1613 "androidx.view.accessibility.AccessibilityNodeInfoCompat.PANE_TITLE_KEY"; 1614 1615 private static final String TOOLTIP_TEXT_KEY = 1616 "androidx.view.accessibility.AccessibilityNodeInfoCompat.TOOLTIP_TEXT_KEY"; 1617 1618 private static final String HINT_TEXT_KEY = 1619 "androidx.view.accessibility.AccessibilityNodeInfoCompat.HINT_TEXT_KEY"; 1620 1621 private static final String BOOLEAN_PROPERTY_KEY = 1622 "androidx.view.accessibility.AccessibilityNodeInfoCompat.BOOLEAN_PROPERTY_KEY"; 1623 1624 private static final String SPANS_ID_KEY = 1625 "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_ID_KEY"; 1626 1627 private static final String SPANS_START_KEY = 1628 "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_START_KEY"; 1629 1630 private static final String SPANS_END_KEY = 1631 "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_END_KEY"; 1632 1633 private static final String SPANS_FLAGS_KEY = 1634 "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_FLAGS_KEY"; 1635 1636 private static final String SPANS_ACTION_ID_KEY = 1637 "androidx.view.accessibility.AccessibilityNodeInfoCompat.SPANS_ACTION_ID_KEY"; 1638 1639 private static final String STATE_DESCRIPTION_KEY = 1640 "androidx.view.accessibility.AccessibilityNodeInfoCompat.STATE_DESCRIPTION_KEY"; 1641 1642 private static final String SUPPLEMENTAL_DESCRIPTION_KEY = 1643 "androidx.view.accessibility.AccessibilityNodeInfoCompat.SUPPLEMENTAL_DESCRIPTION_KEY"; 1644 1645 private static final String UNIQUE_ID_KEY = 1646 "androidx.view.accessibility.AccessibilityNodeInfoCompat.UNIQUE_ID_KEY"; 1647 1648 private static final String CONTAINER_TITLE_KEY = 1649 "androidx.view.accessibility.AccessibilityNodeInfoCompat.CONTAINER_TITLE_KEY"; 1650 1651 private static final String BOUNDS_IN_WINDOW_KEY = 1652 "androidx.view.accessibility.AccessibilityNodeInfoCompat.BOUNDS_IN_WINDOW_KEY"; 1653 1654 private static final String EXPANDED_STATE_KEY = 1655 "androidx.view.accessibility.AccessibilityNodeInfoCompat.EXPANDED_STATE_KEY"; 1656 1657 private static final String MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY = 1658 "androidx.view.accessibility.AccessibilityNodeInfoCompat." 1659 + "MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY"; 1660 private static final String IS_REQUIRED_KEY = 1661 "androidx.view.accessibility.AccessibilityNodeInfoCompat.IS_REQUIRED_KEY"; 1662 1663 private static final String CHECKED_KEY = 1664 "androidx.view.accessibility.AccessibilityNodeInfoCompat.CHECKED_KEY"; 1665 1666 // These don't line up with the internal framework constants, since they are independent 1667 // and we might as well get all 32 bits of utility here. 1668 private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x00000001; 1669 private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x00000002; 1670 private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x00000004; 1671 private static final int BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY = 0x00000008; 1672 1673 private static final int BOOLEAN_PROPERTY_HAS_REQUEST_INITIAL_ACCESSIBILITY_FOCUS = 1 << 5; 1674 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE = 1 << 6; 1675 private static final int BOOLEAN_PROPERTY_TEXT_SELECTABLE = 1 << 23; 1676 private static final int BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING = 1 << 26; 1677 1678 private final AccessibilityNodeInfo mInfo; 1679 1680 /** 1681 * androidx.customview.widget.ExploreByTouchHelper.HOST_ID = -1; 1682 */ 1683 @RestrictTo(LIBRARY_GROUP_PREFIX) 1684 public int mParentVirtualDescendantId = NO_ID; 1685 1686 private int mVirtualDescendantId = NO_ID; 1687 1688 // Actions introduced in IceCreamSandwich 1689 1690 /** 1691 * Action that focuses the node. 1692 * @see AccessibilityActionCompat#ACTION_FOCUS 1693 */ 1694 public static final int ACTION_FOCUS = 0x00000001; 1695 1696 /** 1697 * Action that unfocuses the node. 1698 * @see AccessibilityActionCompat#ACTION_CLEAR_FOCUS 1699 */ 1700 public static final int ACTION_CLEAR_FOCUS = 0x00000002; 1701 1702 /** 1703 * Action that selects the node. 1704 * @see AccessibilityActionCompat#ACTION_SELECT 1705 */ 1706 public static final int ACTION_SELECT = 0x00000004; 1707 1708 /** 1709 * Action that unselects the node. 1710 * @see AccessibilityActionCompat#ACTION_CLEAR_SELECTION 1711 */ 1712 public static final int ACTION_CLEAR_SELECTION = 0x00000008; 1713 1714 /** 1715 * Action that clicks on the node info. 1716 * @see AccessibilityActionCompat#ACTION_CLICK 1717 */ 1718 public static final int ACTION_CLICK = 0x00000010; 1719 1720 /** 1721 * Action that long clicks on the node. 1722 * @see AccessibilityActionCompat#ACTION_LONG_CLICK 1723 */ 1724 public static final int ACTION_LONG_CLICK = 0x00000020; 1725 1726 // Actions introduced in JellyBean 1727 1728 /** 1729 * Action that gives accessibility focus to the node. 1730 * @see AccessibilityActionCompat#ACTION_ACCESSIBILITY_FOCUS 1731 */ 1732 public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040; 1733 1734 /** 1735 * Action that clears accessibility focus of the node. 1736 */ 1737 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080; 1738 1739 /** 1740 * Action that requests to go to the next entity in this node's text 1741 * at a given movement granularity. For example, move to the next character, 1742 * word, etc. 1743 * <p> 1744 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, 1745 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 1746 * <strong>Example:</strong> Move to the previous character and do not extend selection. 1747 * <code><pre><p> 1748 * Bundle arguments = new Bundle(); 1749 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 1750 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 1751 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 1752 * false); 1753 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments); 1754 * </code></pre></p> 1755 * </p> 1756 * 1757 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 1758 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 1759 * 1760 * @see #setMovementGranularities(int) 1761 * @see #getMovementGranularities() 1762 * 1763 * @see #MOVEMENT_GRANULARITY_CHARACTER 1764 * @see #MOVEMENT_GRANULARITY_WORD 1765 * @see #MOVEMENT_GRANULARITY_LINE 1766 * @see #MOVEMENT_GRANULARITY_PARAGRAPH 1767 * @see #MOVEMENT_GRANULARITY_PAGE 1768 * @see AccessibilityActionCompat#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 1769 */ 1770 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100; 1771 1772 /** 1773 * Action that requests to go to the previous entity in this node's text 1774 * at a given movement granularity. For example, move to the next character, 1775 * word, etc. 1776 * <p> 1777 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, 1778 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 1779 * <strong>Example:</strong> Move to the next character and do not extend selection. 1780 * <code><pre><p> 1781 * Bundle arguments = new Bundle(); 1782 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 1783 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 1784 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 1785 * false); 1786 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, 1787 * arguments); 1788 * </code></pre></p> 1789 * </p> 1790 * 1791 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 1792 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 1793 * 1794 * @see #setMovementGranularities(int) 1795 * @see #getMovementGranularities() 1796 * 1797 * @see #MOVEMENT_GRANULARITY_CHARACTER 1798 * @see #MOVEMENT_GRANULARITY_WORD 1799 * @see #MOVEMENT_GRANULARITY_LINE 1800 * @see #MOVEMENT_GRANULARITY_PARAGRAPH 1801 * @see #MOVEMENT_GRANULARITY_PAGE 1802 * @see AccessibilityActionCompat#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 1803 */ 1804 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200; 1805 1806 /** 1807 * Action to move to the next HTML element of a given type. For example, move 1808 * to the BUTTON, INPUT, TABLE, etc. 1809 * <p> 1810 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 1811 * <strong>Example:</strong> 1812 * <code><pre><p> 1813 * Bundle arguments = new Bundle(); 1814 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 1815 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments); 1816 * </code></pre></p> 1817 * </p> 1818 * @see AccessibilityActionCompat#ACTION_NEXT_HTML_ELEMENT 1819 */ 1820 public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400; 1821 1822 /** 1823 * Action to move to the previous HTML element of a given type. For example, move 1824 * to the BUTTON, INPUT, TABLE, etc. 1825 * <p> 1826 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 1827 * <strong>Example:</strong> 1828 * <code><pre><p> 1829 * Bundle arguments = new Bundle(); 1830 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 1831 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments); 1832 * </code></pre></p> 1833 * </p> 1834 * 1835 * @see AccessibilityActionCompat#ACTION_PREVIOUS_HTML_ELEMENT 1836 */ 1837 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800; 1838 1839 /** 1840 * Action to scroll the node content forward. 1841 * @see AccessibilityActionCompat#ACTION_SCROLL_FORWARD 1842 */ 1843 public static final int ACTION_SCROLL_FORWARD = 0x00001000; 1844 1845 /** 1846 * Action to scroll the node content backward. 1847 * @see AccessibilityActionCompat#ACTION_SCROLL_BACKWARD 1848 */ 1849 public static final int ACTION_SCROLL_BACKWARD = 0x00002000; 1850 1851 // Actions introduced in JellyBeanMr2 1852 1853 /** 1854 * Action to copy the current selection to the clipboard. 1855 * @see AccessibilityActionCompat#ACTION_COPY 1856 */ 1857 public static final int ACTION_COPY = 0x00004000; 1858 1859 /** 1860 * Action to paste the current clipboard content. 1861 * @see AccessibilityActionCompat#ACTION_PASTE 1862 */ 1863 public static final int ACTION_PASTE = 0x00008000; 1864 1865 /** 1866 * Action to cut the current selection and place it to the clipboard. 1867 * @see AccessibilityActionCompat#ACTION_CUT 1868 */ 1869 public static final int ACTION_CUT = 0x00010000; 1870 1871 /** 1872 * Action to set the selection. Performing this action with no arguments 1873 * clears the selection. 1874 * <p> 1875 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT}, 1876 * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br> 1877 * <strong>Example:</strong> 1878 * <code><pre><p> 1879 * Bundle arguments = new Bundle(); 1880 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1); 1881 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2); 1882 * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments); 1883 * </code></pre></p> 1884 * </p> 1885 * 1886 * @see #ACTION_ARGUMENT_SELECTION_START_INT 1887 * @see #ACTION_ARGUMENT_SELECTION_END_INT 1888 * @see AccessibilityActionCompat#ACTION_SET_SELECTION 1889 */ 1890 public static final int ACTION_SET_SELECTION = 0x00020000; 1891 1892 /** 1893 * Action to expand an expandable node. 1894 * @see AccessibilityActionCompat#ACTION_EXPAND 1895 */ 1896 public static final int ACTION_EXPAND = 0x00040000; 1897 1898 /** 1899 * Action to collapse an expandable node. 1900 * @see AccessibilityActionCompat#ACTION_COLLAPSE 1901 */ 1902 public static final int ACTION_COLLAPSE = 0x00080000; 1903 1904 /** 1905 * Action to dismiss a dismissible node. 1906 * @see AccessibilityActionCompat#ACTION_DISMISS 1907 */ 1908 public static final int ACTION_DISMISS = 0x00100000; 1909 1910 /** 1911 * Action that sets the text of the node. Performing the action without argument, using <code> 1912 * null</code> or empty {@link CharSequence} will clear the text. This action will also put the 1913 * cursor at the end of text. 1914 * <p> 1915 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> 1916 * <strong>Example:</strong> 1917 * <code><pre><p> 1918 * Bundle arguments = new Bundle(); 1919 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, 1920 * "android"); 1921 * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 1922 * </code></pre></p> 1923 * @see AccessibilityActionCompat#ACTION_SET_TEXT 1924 */ 1925 public static final int ACTION_SET_TEXT = 0x00200000; 1926 1927 // Action arguments 1928 1929 /** 1930 * Argument for which movement granularity to be used when traversing the node text. 1931 * <p> 1932 * <strong>Type:</strong> int<br> 1933 * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY}, 1934 * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY} 1935 * </p> 1936 */ 1937 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = 1938 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; 1939 1940 /** 1941 * Argument for which HTML element to get moving to the next/previous HTML element. 1942 * <p> 1943 * <strong>Type:</strong> String<br> 1944 * <strong>Actions:</strong> {@link AccessibilityActionCompat#ACTION_NEXT_HTML_ELEMENT}, 1945 * {@link AccessibilityActionCompat#ACTION_PREVIOUS_HTML_ELEMENT} 1946 * </p> 1947 */ 1948 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = 1949 "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; 1950 1951 /** 1952 * Argument for whether when moving at granularity to extend the selection 1953 * or to move it otherwise. 1954 * <p> 1955 * <strong>Type:</strong> boolean<br> 1956 * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY}, 1957 * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY} 1958 * </p> 1959 * 1960 * @see AccessibilityActionCompat#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 1961 * @see AccessibilityActionCompat#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 1962 */ 1963 public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = 1964 "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN"; 1965 1966 /** 1967 * Argument for specifying the selection start. 1968 * <p> 1969 * <strong>Type:</strong> int<br> 1970 * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION} 1971 * </p> 1972 * 1973 * @see AccessibilityActionCompat#ACTION_SET_SELECTION 1974 */ 1975 public static final String ACTION_ARGUMENT_SELECTION_START_INT = 1976 "ACTION_ARGUMENT_SELECTION_START_INT"; 1977 1978 /** 1979 * Argument for specifying the selection end. 1980 * <p> 1981 * <strong>Type:</strong> int<br> 1982 * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION} 1983 * </p> 1984 * 1985 * @see AccessibilityActionCompat#ACTION_SET_SELECTION 1986 */ 1987 public static final String ACTION_ARGUMENT_SELECTION_END_INT = 1988 "ACTION_ARGUMENT_SELECTION_END_INT"; 1989 1990 /** 1991 * Argument for specifying the text content to set 1992 * <p> 1993 * <strong>Type:</strong> CharSequence<br> 1994 * <strong>Actions:</strong> {@link #ACTION_SET_TEXT} 1995 * </p> 1996 * 1997 * @see AccessibilityActionCompat#ACTION_SET_TEXT 1998 */ 1999 public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = 2000 "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE"; 2001 2002 /** 2003 * Argument for specifying the collection row to make visible on screen. 2004 * <p> 2005 * <strong>Type:</strong> int<br> 2006 * <strong>Actions:</strong> 2007 * <ul> 2008 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li> 2009 * </ul> 2010 * 2011 * @see AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION 2012 */ 2013 public static final String ACTION_ARGUMENT_ROW_INT = 2014 "android.view.accessibility.action.ARGUMENT_ROW_INT"; 2015 2016 /** 2017 * Argument for specifying the collection column to make visible on screen. 2018 * <p> 2019 * <strong>Type:</strong> int<br> 2020 * <strong>Actions:</strong> 2021 * <ul> 2022 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li> 2023 * </ul> 2024 * 2025 * @see AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION 2026 */ 2027 public static final String ACTION_ARGUMENT_COLUMN_INT = 2028 "android.view.accessibility.action.ARGUMENT_COLUMN_INT"; 2029 2030 /** 2031 * Argument for specifying the progress value to set. 2032 * <p> 2033 * <strong>Type:</strong> float<br> 2034 * <strong>Actions:</strong> 2035 * <ul> 2036 * <li>{@link AccessibilityActionCompat#ACTION_SET_PROGRESS}</li> 2037 * </ul> 2038 * 2039 * @see AccessibilityActionCompat#ACTION_SET_PROGRESS 2040 */ 2041 public static final String ACTION_ARGUMENT_PROGRESS_VALUE = 2042 "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE"; 2043 2044 /** 2045 * Argument for specifying the x coordinate to which to move a window. 2046 * <p> 2047 * <strong>Type:</strong> int<br> 2048 * <strong>Actions:</strong> 2049 * <ul> 2050 * <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li> 2051 * </ul> 2052 * 2053 * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW 2054 */ 2055 public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = 2056 "ACTION_ARGUMENT_MOVE_WINDOW_X"; 2057 2058 /** 2059 * Argument for specifying the y coordinate to which to move a window. 2060 * <p> 2061 * <strong>Type:</strong> int<br> 2062 * <strong>Actions:</strong> 2063 * <ul> 2064 * <li>{@link AccessibilityActionCompat#ACTION_MOVE_WINDOW}</li> 2065 * </ul> 2066 * 2067 * @see AccessibilityActionCompat#ACTION_MOVE_WINDOW 2068 */ 2069 public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = 2070 "ACTION_ARGUMENT_MOVE_WINDOW_Y"; 2071 2072 /** 2073 * Argument to represent the duration in milliseconds to press and hold a node. 2074 * <p> 2075 * <strong>Type:</strong> int<br> 2076 * <strong>Actions:</strong> 2077 * <ul> 2078 * <li>{@link AccessibilityActionCompat#ACTION_PRESS_AND_HOLD}</li> 2079 * </ul> 2080 * 2081 * @see AccessibilityActionCompat#ACTION_PRESS_AND_HOLD 2082 */ 2083 @SuppressLint("ActionValue") 2084 public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = 2085 "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT"; 2086 2087 /** 2088 * <p>Argument to represent the direction when using 2089 * {@link AccessibilityActionCompat#ACTION_SCROLL_IN_DIRECTION}.</p> 2090 * 2091 * <p> 2092 * The value of this argument can be one of: 2093 * <ul> 2094 * <li>{@link View#FOCUS_DOWN}</li> 2095 * <li>{@link View#FOCUS_UP}</li> 2096 * <li>{@link View#FOCUS_LEFT}</li> 2097 * <li>{@link View#FOCUS_RIGHT}</li> 2098 * <li>{@link View#FOCUS_FORWARD}</li> 2099 * <li>{@link View#FOCUS_BACKWARD}</li> 2100 * </ul> 2101 * </p> 2102 */ 2103 public static final String ACTION_ARGUMENT_DIRECTION_INT = 2104 "androidx.core.view.accessibility.action.ARGUMENT_DIRECTION_INT"; 2105 2106 /** 2107 * <p>Argument to represent the scroll amount as a percent of the visible area of a node, with 2108 * 1.0F as the default. Values smaller than 1.0F represent a partial scroll of the node, and 2109 * values larger than 1.0F represent a scroll that extends beyond the currently visible node 2110 * Rect. Setting this to {@link Float#POSITIVE_INFINITY} or to another "too large" value should 2111 * scroll to the end of the node. Negative values should not be used with this argument. 2112 * </p> 2113 * 2114 * <p> 2115 * This argument should be used with the following scroll actions: 2116 * <ul> 2117 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_FORWARD}</li> 2118 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_BACKWARD}</li> 2119 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_UP}</li> 2120 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_DOWN}</li> 2121 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_LEFT}</li> 2122 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_RIGHT}</li> 2123 * </ul> 2124 * </p> 2125 * <p> 2126 * Example: if a view representing a list of items implements 2127 * {@link AccessibilityActionCompat#ACTION_SCROLL_FORWARD} to scroll forward by an entire 2128 * screen 2129 * (one "page"), then passing a value of .25F via this argument should scroll that view 2130 * only by 1/4th of a screen. Passing a value of 1.50F via this argument should scroll the 2131 * view by 1 1/2 screens or to end of the node if the node doesn't extend to 1 1/2 screens. 2132 * </p> 2133 * 2134 * <p> 2135 * This argument should not be used with the following scroll actions, which don't cleanly 2136 * conform to granular scroll semantics: 2137 * <ul> 2138 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_IN_DIRECTION}</li> 2139 * <li>{@link AccessibilityActionCompat#ACTION_SCROLL_TO_POSITION}</li> 2140 * </ul> 2141 * </p> 2142 * 2143 * <p> 2144 * Views that support this argument should set 2145 * {@link #setGranularScrollingSupported(boolean)} to true. Clients should use 2146 * {@link #isGranularScrollingSupported()} to check if granular scrolling is supported. 2147 * </p> 2148 */ 2149 public static final String ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT = 2150 "androidx.core.view.accessibility.action.ARGUMENT_SCROLL_AMOUNT_FLOAT"; 2151 2152 // Focus types 2153 2154 /** 2155 * The input focus. 2156 */ 2157 public static final int FOCUS_INPUT = 1; 2158 2159 /** 2160 * The accessibility focus. 2161 */ 2162 public static final int FOCUS_ACCESSIBILITY = 2; 2163 2164 // Movement granularities 2165 2166 /** 2167 * Movement granularity bit for traversing the text of a node by character. 2168 */ 2169 public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001; 2170 2171 /** 2172 * Movement granularity bit for traversing the text of a node by word. 2173 */ 2174 public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002; 2175 2176 /** 2177 * Movement granularity bit for traversing the text of a node by line. 2178 */ 2179 public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004; 2180 2181 /** 2182 * Movement granularity bit for traversing the text of a node by paragraph. 2183 */ 2184 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008; 2185 2186 /** 2187 * Movement granularity bit for traversing the text of a node by page. 2188 */ 2189 public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010; 2190 2191 /** 2192 * Key used to request and locate extra data for text character location. This key requests that 2193 * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with 2194 * {@link android.view.accessibility.AccessibilityNodeInfo#refreshWithExtraData(String, Bundle)}. 2195 * The arguments taken by this request are two integers: 2196 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and 2197 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid 2198 * inside the CharSequence returned by {@link #getText()}, and the length must be positive. 2199 * <p> 2200 * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this 2201 * string as a key for {@link Bundle#getParcelableArray(String)}. The 2202 * {@link android.graphics.RectF} will be {@code null} for characters that either do not exist 2203 * or are off the screen. 2204 * <p> 2205 * Note that character locations returned are modified by changes in display magnification. 2206 * 2207 * {@see android.view.accessibility.AccessibilityNodeInfo#refreshWithExtraData(String, Bundle)} 2208 */ 2209 @SuppressWarnings("ActionValue") 2210 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = 2211 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY"; 2212 2213 /** 2214 * Key used to request and locate extra data for text character location in 2215 * window coordinates. This key requests that an array of 2216 * {@link android.graphics.RectF}s be added to the extras. This request is made with 2217 * {@link android.view.accessibility.AccessibilityNodeInfo#refreshWithExtraData(String, Bundle)}. 2218 * The arguments taken by this request are two integers: 2219 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and 2220 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index 2221 * must be valid inside the CharSequence returned by {@link #getText()}, and 2222 * the length must be positive. 2223 * <p> 2224 * Providers may advertise that they support text characters in window coordinates using 2225 * {@link #setAvailableExtraData(List)}. Services may check if an implementation supports text 2226 * characters in window coordinates with {@link #getAvailableExtraData()}. 2227 * <p> 2228 * The data can be retrieved from the {@code Bundle} returned by 2229 * {@link #getExtras()} using this string as a key for 2230 * {@link Bundle#getParcelableArray(String, Class)}. The 2231 * {@link android.graphics.RectF} will be {@code null} for characters that either do 2232 * not exist or are outside of the window bounds. 2233 * <p> 2234 * Note that character locations in window bounds are not modified by 2235 * changes in display magnification. 2236 * 2237 * {@see android.view.accessibility.AccessibilityNodeInfo#refreshWithExtraData(String, Bundle)} 2238 */ 2239 @SuppressWarnings("ActionValue") 2240 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY = 2241 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_IN_WINDOW_KEY"; 2242 2243 /** 2244 * Integer argument specifying the start index of the requested text location data. Must be 2245 * valid inside the CharSequence returned by {@link #getText()}. 2246 * 2247 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 2248 */ 2249 @SuppressWarnings("ActionValue") 2250 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = 2251 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX"; 2252 2253 /** 2254 * Integer argument specifying the end index of the requested text location data. Must be 2255 * positive and no larger than {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. 2256 * 2257 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 2258 */ 2259 @SuppressWarnings("ActionValue") 2260 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = 2261 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; 2262 2263 /** 2264 * The maximum allowed length of the requested text location data. 2265 */ 2266 public static final int EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_MAX_LENGTH = 20000; 2267 2268 /** 2269 * Prefetching strategy that prefetches the ancestors of the requested node. 2270 * <p> Ancestors will be prefetched before siblings and descendants. 2271 * 2272 * @see #getChild(int, int) 2273 * @see #getParent(int) 2274 * @see AccessibilityWindowInfoCompat#getRoot(int) 2275 * @see AccessibilityService#getRootInActiveWindow(int) 2276 * @see AccessibilityEvent#getSource(int) 2277 */ 2278 public static final int FLAG_PREFETCH_ANCESTORS = 0x00000001; 2279 2280 /** 2281 * Prefetching strategy that prefetches the siblings of the requested node. 2282 * <p> To avoid disconnected trees, this flag will also prefetch the parent. Siblings will be 2283 * prefetched before descendants. 2284 * 2285 * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags. 2286 */ 2287 public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002; 2288 2289 /** 2290 * Prefetching strategy that prefetches the descendants in a hybrid depth first and breadth 2291 * first approach. 2292 * <p> The children of the root node is prefetched before recursing on the children. This 2293 * must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST} or 2294 * {@link #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST} or this will trigger an 2295 * IllegalArgumentException. 2296 * 2297 * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags. 2298 */ 2299 public static final int FLAG_PREFETCH_DESCENDANTS_HYBRID = 0x00000004; 2300 2301 /** 2302 * Prefetching strategy that prefetches the descendants of the requested node depth-first. 2303 * <p> This must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_HYBRID} or 2304 * {@link #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST} or this will trigger an 2305 * IllegalArgumentException. 2306 * 2307 * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags. 2308 */ 2309 public static final int FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST = 0x00000008; 2310 2311 /** 2312 * Prefetching strategy that prefetches the descendants of the requested node breadth-first. 2313 * <p> This must not be combined with {@link #FLAG_PREFETCH_DESCENDANTS_HYBRID} or 2314 * {@link #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST} or this will trigger an 2315 * IllegalArgumentException. 2316 * 2317 * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags. 2318 */ 2319 public static final int FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST = 0x00000010; 2320 2321 /** 2322 * Prefetching flag that specifies prefetching should not be interrupted by a request to 2323 * retrieve a node or perform an action on a node. 2324 * 2325 * @see #FLAG_PREFETCH_ANCESTORS for where to use these flags. 2326 */ 2327 public static final int FLAG_PREFETCH_UNINTERRUPTIBLE = 0x00000020; 2328 2329 /** 2330 * Maximum batch size of prefetched nodes for a request. 2331 */ 2332 @SuppressLint("MinMaxConstant") 2333 public static final int MAX_NUMBER_OF_PREFETCHED_NODES = 50; 2334 2335 @IntDef( 2336 flag = false, 2337 value = { 2338 AccessibilityNodeInfo.EXPANDED_STATE_UNDEFINED, 2339 AccessibilityNodeInfo.EXPANDED_STATE_COLLAPSED, 2340 AccessibilityNodeInfo.EXPANDED_STATE_PARTIAL, 2341 AccessibilityNodeInfo.EXPANDED_STATE_FULL, 2342 }) 2343 @Retention(RetentionPolicy.SOURCE) 2344 private @interface ExpandedState {} 2345 2346 @IntDef( 2347 flag = false, 2348 value = { 2349 AccessibilityNodeInfo.CHECKED_STATE_FALSE, 2350 AccessibilityNodeInfo.CHECKED_STATE_TRUE, 2351 AccessibilityNodeInfo.CHECKED_STATE_PARTIAL, 2352 }) 2353 @Retention(RetentionPolicy.SOURCE) 2354 private @interface CheckedState {} 2355 2356 private static int sClickableSpanId = 0; 2357 2358 /** 2359 * Creates a wrapper for info implementation. 2360 * 2361 * @param object The info to wrap. 2362 * @return A wrapper for if the object is not null, null otherwise. 2363 */ 2364 @SuppressWarnings("deprecation") wrapNonNullInstance(Object object)2365 static AccessibilityNodeInfoCompat wrapNonNullInstance(Object object) { 2366 if (object != null) { 2367 return new AccessibilityNodeInfoCompat(object); 2368 } 2369 return null; 2370 } 2371 2372 /** 2373 * Creates a new instance wrapping an 2374 * {@link android.view.accessibility.AccessibilityNodeInfo}. 2375 * 2376 * @param info The info. 2377 * 2378 * @deprecated Use {@link #wrap(AccessibilityNodeInfo)} instead. 2379 */ 2380 @Deprecated AccessibilityNodeInfoCompat(Object info)2381 public AccessibilityNodeInfoCompat(Object info) { 2382 mInfo = (AccessibilityNodeInfo) info; 2383 } 2384 AccessibilityNodeInfoCompat(AccessibilityNodeInfo info)2385 private AccessibilityNodeInfoCompat(AccessibilityNodeInfo info) { 2386 mInfo = info; 2387 } 2388 2389 /** 2390 * Creates a new instance wrapping an 2391 * {@link android.view.accessibility.AccessibilityNodeInfo}. 2392 * 2393 * @param info The info. 2394 */ wrap(@onNull AccessibilityNodeInfo info)2395 public static AccessibilityNodeInfoCompat wrap(@NonNull AccessibilityNodeInfo info) { 2396 return new AccessibilityNodeInfoCompat(info); 2397 } 2398 2399 /** 2400 * @return The unwrapped {@link android.view.accessibility.AccessibilityNodeInfo}. 2401 */ unwrap()2402 public AccessibilityNodeInfo unwrap() { 2403 return mInfo; 2404 } 2405 2406 /** 2407 * @return The wrapped {@link android.view.accessibility.AccessibilityNodeInfo}. 2408 * 2409 * @deprecated Use {@link #unwrap()} instead. 2410 */ 2411 @Deprecated getInfo()2412 public Object getInfo() { 2413 return mInfo; 2414 } 2415 2416 /** 2417 * Returns a cached instance if such is available otherwise a new one and 2418 * sets the source. 2419 * 2420 * @return An instance. 2421 * @see #setSource(View) 2422 */ obtain(View source)2423 public static AccessibilityNodeInfoCompat obtain(View source) { 2424 return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(source)); 2425 } 2426 2427 /** 2428 * Returns a cached instance if such is available otherwise a new one 2429 * and sets the source. 2430 * 2431 * @param root The root of the virtual subtree. 2432 * @param virtualDescendantId The id of the virtual descendant. 2433 * @return An instance. 2434 * 2435 * @see #setSource(View, int) 2436 */ obtain(View root, int virtualDescendantId)2437 public static AccessibilityNodeInfoCompat obtain(View root, int virtualDescendantId) { 2438 return AccessibilityNodeInfoCompat.wrapNonNullInstance( 2439 AccessibilityNodeInfo.obtain(root, virtualDescendantId)); 2440 } 2441 2442 /** 2443 * Returns a cached instance if such is available otherwise a new one. 2444 * 2445 * @return An instance. 2446 */ obtain()2447 public static AccessibilityNodeInfoCompat obtain() { 2448 return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain()); 2449 } 2450 2451 /** 2452 * Returns a cached instance if such is available or a new one is create. 2453 * The returned instance is initialized from the given <code>info</code>. 2454 * 2455 * @param info The other info. 2456 * @return An instance. 2457 */ obtain(AccessibilityNodeInfoCompat info)2458 public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) { 2459 return AccessibilityNodeInfoCompat.wrap(AccessibilityNodeInfo.obtain(info.mInfo)); 2460 } 2461 2462 /** 2463 * Sets the source. 2464 * 2465 * @param source The info source. 2466 */ setSource(View source)2467 public void setSource(View source) { 2468 mVirtualDescendantId = NO_ID; 2469 2470 mInfo.setSource(source); 2471 } 2472 2473 /** 2474 * Sets the source to be a virtual descendant of the given <code>root</code>. 2475 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root 2476 * is set as the source. 2477 * <p> 2478 * A virtual descendant is an imaginary View that is reported as a part of the view 2479 * hierarchy for accessibility purposes. This enables custom views that draw complex 2480 * content to report themselves as a tree of virtual views, thus conveying their 2481 * logical structure. 2482 * <p> 2483 * <strong>Note:</strong> Cannot be called from an 2484 * {@link android.accessibilityservice.AccessibilityService}. 2485 * This class is made immutable before being delivered to an AccessibilityService. 2486 * <p> 2487 * This method is not supported on devices running API level < 16 since the platform did 2488 * not support virtual descendants of real views. 2489 * 2490 * @param root The root of the virtual subtree. 2491 * @param virtualDescendantId The id of the virtual descendant. 2492 */ setSource(View root, int virtualDescendantId)2493 public void setSource(View root, int virtualDescendantId) { 2494 // Store the ID anyway, since we may need it for equality checks. 2495 mVirtualDescendantId = virtualDescendantId; 2496 2497 mInfo.setSource(root, virtualDescendantId); 2498 } 2499 2500 /** 2501 * Find the view that has the specified focus type. The search starts from 2502 * the view represented by this node info. 2503 * 2504 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or 2505 * {@link #FOCUS_ACCESSIBILITY}. 2506 * @return The node info of the focused view or null. 2507 * 2508 * @see #FOCUS_INPUT 2509 * @see #FOCUS_ACCESSIBILITY 2510 */ findFocus(int focus)2511 public AccessibilityNodeInfoCompat findFocus(int focus) { 2512 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.findFocus(focus)); 2513 } 2514 2515 /** 2516 * Searches for the nearest view in the specified direction that can take 2517 * input focus. 2518 * 2519 * @param direction The direction. Can be one of: 2520 * {@link View#FOCUS_DOWN}, 2521 * {@link View#FOCUS_UP}, 2522 * {@link View#FOCUS_LEFT}, 2523 * {@link View#FOCUS_RIGHT}, 2524 * {@link View#FOCUS_FORWARD}, 2525 * {@link View#FOCUS_BACKWARD}. 2526 * 2527 * @return The node info for the view that can take accessibility focus. 2528 */ focusSearch(int direction)2529 public AccessibilityNodeInfoCompat focusSearch(int direction) { 2530 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.focusSearch(direction)); 2531 } 2532 2533 /** 2534 * Gets the id of the window from which the info comes from. 2535 * 2536 * @return The window id. 2537 */ getWindowId()2538 public int getWindowId() { 2539 return mInfo.getWindowId(); 2540 } 2541 2542 /** 2543 * Gets the number of children. 2544 * 2545 * @return The child count. 2546 */ getChildCount()2547 public int getChildCount() { 2548 return mInfo.getChildCount(); 2549 } 2550 2551 /** 2552 * Get the child at given index. 2553 * 2554 * @param index The child index. 2555 * @return The child node. 2556 * @throws IllegalStateException If called outside of an 2557 * AccessibilityService. 2558 */ getChild(int index)2559 public AccessibilityNodeInfoCompat getChild(int index) { 2560 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getChild(index)); 2561 } 2562 2563 /** 2564 * Get the child at given index. 2565 * 2566 * @param index The child index. 2567 * @param prefetchingStrategy the prefetching strategy. 2568 * @return The child node. 2569 * 2570 * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before 2571 * calling {@link #setQueryFromAppProcessEnabled}. 2572 * 2573 * @see AccessibilityNodeInfoCompat#getParent(int) for a description of prefetching. 2574 */ getChild(int index, int prefetchingStrategy)2575 public @Nullable AccessibilityNodeInfoCompat getChild(int index, int prefetchingStrategy) { 2576 if (Build.VERSION.SDK_INT >= 33) { 2577 return Api33Impl.getChild(mInfo, index, prefetchingStrategy); 2578 } 2579 return getChild(index); 2580 } 2581 2582 /** 2583 * Adds a child. 2584 * <p> 2585 * <strong>Note:</strong> Cannot be called from an 2586 * {@link android.accessibilityservice.AccessibilityService}. This class is 2587 * made immutable before being delivered to an AccessibilityService. 2588 * </p> 2589 * 2590 * @param child The child. 2591 * @throws IllegalStateException If called from an AccessibilityService. 2592 */ addChild(View child)2593 public void addChild(View child) { 2594 mInfo.addChild(child); 2595 } 2596 2597 /** 2598 * Adds a virtual child which is a descendant of the given <code>root</code>. 2599 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root 2600 * is added as a child. 2601 * <p> 2602 * A virtual descendant is an imaginary View that is reported as a part of the view 2603 * hierarchy for accessibility purposes. This enables custom views that draw complex 2604 * content to report them selves as a tree of virtual views, thus conveying their 2605 * logical structure. 2606 * </p> 2607 * 2608 * @param root The root of the virtual subtree. 2609 * @param virtualDescendantId The id of the virtual child. 2610 */ addChild(View root, int virtualDescendantId)2611 public void addChild(View root, int virtualDescendantId) { 2612 mInfo.addChild(root, virtualDescendantId); 2613 } 2614 2615 /** 2616 * Removes a child. If the child was not previously added to the node, 2617 * calling this method has no effect. 2618 * <p> 2619 * <strong>Note:</strong> Cannot be called from an 2620 * {@link android.accessibilityservice.AccessibilityService}. 2621 * This class is made immutable before being delivered to an AccessibilityService. 2622 * </p> 2623 * 2624 * @param child The child. 2625 * @return true if the child was present 2626 * 2627 * @throws IllegalStateException If called from an AccessibilityService. 2628 */ removeChild(View child)2629 public boolean removeChild(View child) { 2630 return mInfo.removeChild(child); 2631 } 2632 2633 /** 2634 * Removes a virtual child which is a descendant of the given 2635 * <code>root</code>. If the child was not previously added to the node, 2636 * calling this method has no effect. 2637 * 2638 * @param root The root of the virtual subtree. 2639 * @param virtualDescendantId The id of the virtual child. 2640 * @return true if the child was present 2641 * @see #addChild(View, int) 2642 */ removeChild(View root, int virtualDescendantId)2643 public boolean removeChild(View root, int virtualDescendantId) { 2644 return mInfo.removeChild(root, virtualDescendantId); 2645 } 2646 2647 /** 2648 * Gets the actions that can be performed on the node. 2649 * 2650 * @return The bit mask of with actions. 2651 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS 2652 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS 2653 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT 2654 * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION 2655 * 2656 * @deprecated Use {@link #getActionList()} instead. 2657 */ 2658 @Deprecated getActions()2659 public int getActions() { 2660 return mInfo.getActions(); 2661 } 2662 2663 /** 2664 * Adds an action that can be performed on the node. 2665 * <p> 2666 * <strong>Note:</strong> Cannot be called from an 2667 * {@link android.accessibilityservice.AccessibilityService}. This class is 2668 * made immutable before being delivered to an AccessibilityService. 2669 * </p> 2670 * 2671 * @param action The action. 2672 * @throws IllegalStateException If called from an AccessibilityService. 2673 */ addAction(int action)2674 public void addAction(int action) { 2675 mInfo.addAction(action); 2676 } 2677 extrasIntList(String key)2678 private List<Integer> extrasIntList(String key) { 2679 ArrayList<Integer> list = mInfo.getExtras() 2680 .getIntegerArrayList(key); 2681 if (list == null) { 2682 list = new ArrayList<Integer>(); 2683 mInfo.getExtras().putIntegerArrayList(key, list); 2684 } 2685 return list; 2686 } 2687 2688 /** 2689 * Adds an action that can be performed on the node. 2690 * <p> 2691 * <strong>Note:</strong> Cannot be called from an 2692 * {@link android.accessibilityservice.AccessibilityService}. This class is 2693 * made immutable before being delivered to an AccessibilityService. 2694 * </p> 2695 * 2696 * @param action The action. 2697 * @throws IllegalStateException If called from an AccessibilityService. 2698 */ addAction(AccessibilityActionCompat action)2699 public void addAction(AccessibilityActionCompat action) { 2700 mInfo.addAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction); 2701 } 2702 2703 /** 2704 * Removes an action that can be performed on the node. If the action was 2705 * not already added to the node, calling this method has no effect. 2706 * <p> 2707 * <strong>Note:</strong> Cannot be called from an 2708 * {@link android.accessibilityservice.AccessibilityService}. 2709 * This class is made immutable before being delivered to an AccessibilityService. 2710 * </p> 2711 * 2712 * @param action The action to be removed. 2713 * @return The action removed from the list of actions. 2714 * 2715 * @throws IllegalStateException If called from an AccessibilityService. 2716 */ removeAction(AccessibilityActionCompat action)2717 public boolean removeAction(AccessibilityActionCompat action) { 2718 return mInfo.removeAction((AccessibilityNodeInfo.AccessibilityAction) action.mAction); 2719 } 2720 2721 /** 2722 * Performs an action on the node. 2723 * <p> 2724 * <strong>Note:</strong> An action can be performed only if the request is 2725 * made from an {@link android.accessibilityservice.AccessibilityService}. 2726 * </p> 2727 * 2728 * @param action The action to perform. 2729 * @return True if the action was performed. 2730 * @throws IllegalStateException If called outside of an 2731 * AccessibilityService. 2732 */ performAction(int action)2733 public boolean performAction(int action) { 2734 return mInfo.performAction(action); 2735 } 2736 2737 /** 2738 * Performs an action on the node. 2739 * <p> 2740 * <strong>Note:</strong> An action can be performed only if the request is made 2741 * from an {@link android.accessibilityservice.AccessibilityService}. 2742 * </p> 2743 * 2744 * @param action The action to perform. 2745 * @param arguments A bundle with additional arguments. 2746 * @return True if the action was performed. 2747 * 2748 * @throws IllegalStateException If called outside of an AccessibilityService. 2749 */ performAction(int action, Bundle arguments)2750 public boolean performAction(int action, Bundle arguments) { 2751 return mInfo.performAction(action, arguments); 2752 } 2753 2754 /** 2755 * Sets the movement granularities for traversing the text of this node. 2756 * <p> 2757 * <strong>Note:</strong> Cannot be called from an 2758 * {@link android.accessibilityservice.AccessibilityService}. 2759 * This class is made immutable before being delivered to an AccessibilityService. 2760 * </p> 2761 * 2762 * @param granularities The bit mask with granularities. 2763 * 2764 * @throws IllegalStateException If called from an AccessibilityService. 2765 */ setMovementGranularities(int granularities)2766 public void setMovementGranularities(int granularities) { 2767 mInfo.setMovementGranularities(granularities); 2768 } 2769 2770 /** 2771 * Gets the movement granularities for traversing the text of this node. 2772 * 2773 * @return The bit mask with granularities. 2774 */ getMovementGranularities()2775 public int getMovementGranularities() { 2776 return mInfo.getMovementGranularities(); 2777 } 2778 2779 /** 2780 * Gets the expanded state for this node. 2781 * 2782 * @return The expanded state, one of: 2783 * <ul> 2784 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_UNDEFINED} 2785 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_COLLAPSED} 2786 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_FULL} 2787 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_PARTIAL} 2788 * </ul> 2789 */ 2790 @ExpandedState getExpandedState()2791 public int getExpandedState() { 2792 if (Build.VERSION.SDK_INT >= 36) { 2793 return Api36Impl.getExpandedState(mInfo); 2794 } else { 2795 return mInfo.getExtras().getInt(EXPANDED_STATE_KEY, 2796 AccessibilityNodeInfo.EXPANDED_STATE_UNDEFINED); 2797 } 2798 } 2799 2800 /** 2801 * Sets the expanded state of the node. 2802 * 2803 * <p><strong>Note:</strong> Cannot be called from an {@link 2804 * android.accessibilityservice.AccessibilityService}. This class is made immutable before being 2805 * delivered to an {@link android.accessibilityservice.AccessibilityService}. 2806 * 2807 * @param state new expanded state of this node. 2808 * @throws IllegalArgumentException If state is not one of: 2809 * <ul> 2810 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_UNDEFINED} 2811 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_COLLAPSED} 2812 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_PARTIAL} 2813 * <li>{@link AccessibilityNodeInfo#EXPANDED_STATE_FULL} 2814 * </ul> 2815 * 2816 * @throws IllegalStateException If called from an AccessibilityService 2817 */ setExpandedState(@xpandedState int state)2818 public void setExpandedState(@ExpandedState int state) { 2819 if (Build.VERSION.SDK_INT >= 36) { 2820 Api36Impl.setExpandedState(mInfo, state); 2821 } else { 2822 mInfo.getExtras().putInt(EXPANDED_STATE_KEY, state); 2823 } 2824 } 2825 2826 /** 2827 * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by text. The match 2828 * is case insensitive containment. The search is relative to this info i.e. this 2829 * info is the root of the traversed tree. 2830 * 2831 * @param text The searched text. 2832 * @return A list of node info. 2833 */ findAccessibilityNodeInfosByText(String text)2834 public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByText(String text) { 2835 List<AccessibilityNodeInfoCompat> result = new ArrayList<AccessibilityNodeInfoCompat>(); 2836 List<AccessibilityNodeInfo> infos = mInfo.findAccessibilityNodeInfosByText(text); 2837 final int infoCount = infos.size(); 2838 for (int i = 0; i < infoCount; i++) { 2839 AccessibilityNodeInfo info = infos.get(i); 2840 result.add(AccessibilityNodeInfoCompat.wrap(info)); 2841 } 2842 return result; 2843 } 2844 2845 /** 2846 * Gets the parent. 2847 * 2848 * @return The parent. 2849 */ getParent()2850 public AccessibilityNodeInfoCompat getParent() { 2851 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getParent()); 2852 } 2853 2854 /** 2855 * Gets the parent. 2856 * 2857 * <p> 2858 * Use {@code prefetchingStrategy} to determine the types of 2859 * nodes prefetched from the app if the requested node is not in the cache and must be retrieved 2860 * by the app. The default strategy for {@link #getParent()} is a combination of ancestor and 2861 * sibling strategies. The app will prefetch until all nodes fulfilling the strategies are 2862 * fetched, another node request is sent, or the maximum prefetch batch size of 2863 * {@link #MAX_NUMBER_OF_PREFETCHED_NODES} nodes is reached. To prevent interruption by another 2864 * request and to force prefetching of the max batch size, use 2865 * {@link AccessibilityNodeInfoCompat#FLAG_PREFETCH_UNINTERRUPTIBLE}. 2866 * </p> 2867 * 2868 * @param prefetchingStrategy the prefetching strategy. 2869 * @return The parent. 2870 * 2871 * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before 2872 * calling {@link #setQueryFromAppProcessEnabled}. 2873 * 2874 * @see #FLAG_PREFETCH_ANCESTORS 2875 * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST 2876 * @see #FLAG_PREFETCH_DESCENDANTS_DEPTH_FIRST 2877 * @see #FLAG_PREFETCH_DESCENDANTS_HYBRID 2878 * @see #FLAG_PREFETCH_SIBLINGS 2879 * @see #FLAG_PREFETCH_UNINTERRUPTIBLE 2880 */ getParent(int prefetchingStrategy)2881 public @Nullable AccessibilityNodeInfoCompat getParent(int prefetchingStrategy) { 2882 if (Build.VERSION.SDK_INT >= 33) { 2883 return Api33Impl.getParent(mInfo, prefetchingStrategy); 2884 } 2885 return getParent(); 2886 } 2887 2888 /** 2889 * Sets the parent. 2890 * <p> 2891 * <strong>Note:</strong> Cannot be called from an 2892 * {@link android.accessibilityservice.AccessibilityService}. This class is 2893 * made immutable before being delivered to an AccessibilityService. 2894 * </p> 2895 * 2896 * @param parent The parent. 2897 * @throws IllegalStateException If called from an AccessibilityService. 2898 */ setParent(View parent)2899 public void setParent(View parent) { 2900 mParentVirtualDescendantId = NO_ID; 2901 2902 mInfo.setParent(parent); 2903 } 2904 2905 /** 2906 * Sets the parent to be a virtual descendant of the given <code>root</code>. 2907 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root 2908 * is set as the parent. 2909 * <p> 2910 * A virtual descendant is an imaginary View that is reported as a part of the view 2911 * hierarchy for accessibility purposes. This enables custom views that draw complex 2912 * content to report them selves as a tree of virtual views, thus conveying their 2913 * logical structure. 2914 * <p> 2915 * <strong>Note:</strong> Cannot be called from an 2916 * {@link android.accessibilityservice.AccessibilityService}. 2917 * This class is made immutable before being delivered to an AccessibilityService. 2918 * <p> 2919 * This method is not supported on devices running API level < 16 since the platform did 2920 * not support virtual descendants of real views. 2921 * 2922 * @param root The root of the virtual subtree. 2923 * @param virtualDescendantId The id of the virtual descendant. 2924 */ setParent(View root, int virtualDescendantId)2925 public void setParent(View root, int virtualDescendantId) { 2926 // Store the ID anyway, since we may need it for equality checks. 2927 mParentVirtualDescendantId = virtualDescendantId; 2928 2929 mInfo.setParent(root, virtualDescendantId); 2930 } 2931 2932 /** 2933 * Gets the node bounds in the viewParent's coordinates. 2934 * {@link #getParent()} does not represent the source's viewParent. 2935 * Instead it represents the result of {@link View#getParentForAccessibility()}, 2936 * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true. 2937 * So this method is not reliable. 2938 * 2939 * @param outBounds The output node bounds. 2940 * 2941 * @deprecated Use {@link #getBoundsInScreen(Rect)} instead. 2942 */ 2943 @Deprecated getBoundsInParent(Rect outBounds)2944 public void getBoundsInParent(Rect outBounds) { 2945 mInfo.getBoundsInParent(outBounds); 2946 } 2947 2948 /** 2949 * Sets the node bounds in the viewParent's coordinates. 2950 * {@link #getParent()} does not represent the source's viewParent. 2951 * Instead it represents the result of {@link View#getParentForAccessibility()}, 2952 * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true. 2953 * So this method is not reliable. 2954 * 2955 * <p> 2956 * <strong>Note:</strong> Cannot be called from an 2957 * {@link android.accessibilityservice.AccessibilityService}. This class is 2958 * made immutable before being delivered to an AccessibilityService. 2959 * </p> 2960 * 2961 * @param bounds The node bounds. 2962 * @throws IllegalStateException If called from an AccessibilityService. 2963 * 2964 * @deprecated Accessibility services should not care about these bounds. 2965 */ 2966 @Deprecated setBoundsInParent(Rect bounds)2967 public void setBoundsInParent(Rect bounds) { 2968 mInfo.setBoundsInParent(bounds); 2969 } 2970 2971 /** 2972 * Gets the node bounds in screen coordinates. 2973 * 2974 * @param outBounds The output node bounds. 2975 */ getBoundsInScreen(Rect outBounds)2976 public void getBoundsInScreen(Rect outBounds) { 2977 mInfo.getBoundsInScreen(outBounds); 2978 } 2979 2980 /** 2981 * Sets the node bounds in screen coordinates. 2982 * <p> 2983 * <strong>Note:</strong> Cannot be called from an 2984 * {@link android.accessibilityservice.AccessibilityService}. This class is 2985 * made immutable before being delivered to an AccessibilityService. 2986 * </p> 2987 * 2988 * @param bounds The node bounds. 2989 * @throws IllegalStateException If called from an AccessibilityService. 2990 */ setBoundsInScreen(Rect bounds)2991 public void setBoundsInScreen(Rect bounds) { 2992 mInfo.setBoundsInScreen(bounds); 2993 } 2994 2995 /** 2996 * Gets the node bounds in window coordinates. 2997 * <p> 2998 * When magnification is enabled, the bounds in window are scaled up by magnification scale 2999 * and the positions are also adjusted according to the offset of magnification viewport. 3000 * For example, it returns Rect(-180, -180, 0, 0) for original bounds Rect(10, 10, 100, 100), 3001 * when the magnification scale is 2 and offsets for X and Y are both 200. 3002 * <p/> 3003 * <p> 3004 * Compatibility: 3005 * <ul> 3006 * <li>API < 19: No-op</li> 3007 * </ul> 3008 * @param outBounds The output node bounds. 3009 */ getBoundsInWindow(@onNull Rect outBounds)3010 public void getBoundsInWindow(@NonNull Rect outBounds) { 3011 if (Build.VERSION.SDK_INT >= 34) { 3012 Api34Impl.getBoundsInWindow(mInfo, outBounds); 3013 } else { 3014 Rect extraBounds = mInfo.getExtras().getParcelable(BOUNDS_IN_WINDOW_KEY); 3015 if (extraBounds != null) { 3016 outBounds.set(extraBounds.left, extraBounds.top, extraBounds.right, 3017 extraBounds.bottom); 3018 } 3019 } 3020 } 3021 3022 /** 3023 * Sets the node bounds in window coordinates. 3024 * <p> 3025 * <strong>Note:</strong> Cannot be called from an 3026 * {@link android.accessibilityservice.AccessibilityService}. 3027 * This class is made immutable before being delivered to an AccessibilityService. 3028 * </p> 3029 * <p> 3030 * Compatibility: 3031 * <ul> 3032 * <li>API < 19: No-op</li> 3033 * </ul> 3034 * @param bounds The node bounds. 3035 * 3036 * @throws IllegalStateException If called from an AccessibilityService. 3037 */ setBoundsInWindow(@onNull Rect bounds)3038 public void setBoundsInWindow(@NonNull Rect bounds) { 3039 if (Build.VERSION.SDK_INT >= 34) { 3040 Api34Impl.setBoundsInWindow(mInfo, bounds); 3041 } else { 3042 mInfo.getExtras().putParcelable(BOUNDS_IN_WINDOW_KEY, bounds); 3043 } 3044 } 3045 3046 /** 3047 * Gets whether this node is checkable. 3048 * 3049 * @return True if the node is checkable. 3050 */ isCheckable()3051 public boolean isCheckable() { 3052 return mInfo.isCheckable(); 3053 } 3054 3055 /** 3056 * Sets whether this node is checkable. 3057 * <p> 3058 * <strong>Note:</strong> Cannot be called from an 3059 * {@link android.accessibilityservice.AccessibilityService}. This class is 3060 * made immutable before being delivered to an AccessibilityService. 3061 * </p> 3062 * 3063 * @param checkable True if the node is checkable. 3064 * @throws IllegalStateException If called from an AccessibilityService. 3065 */ setCheckable(boolean checkable)3066 public void setCheckable(boolean checkable) { 3067 mInfo.setCheckable(checkable); 3068 } 3069 3070 /** 3071 * Gets whether this node is checked. 3072 * 3073 * @return True if the node is checked. 3074 * 3075 * @deprecated Use {@link #getChecked()} instead. 3076 */ 3077 @Deprecated isChecked()3078 public boolean isChecked() { 3079 return mInfo.isChecked(); 3080 } 3081 3082 /** 3083 * Sets whether this node is checked. 3084 * <p> 3085 * <strong>Note:</strong> Cannot be called from an 3086 * {@link android.accessibilityservice.AccessibilityService}. This class is 3087 * made immutable before being delivered to an AccessibilityService. 3088 * </p> 3089 * 3090 * @param checked True if the node is checked. 3091 * @throws IllegalStateException If called from an AccessibilityService. 3092 * 3093 * @deprecated Use {@link #setChecked(int)} instead. 3094 */ 3095 @Deprecated setChecked(boolean checked)3096 public void setChecked(boolean checked) { 3097 mInfo.setChecked(checked); 3098 } 3099 3100 /** 3101 * Gets the checked state of this node. 3102 * <p> 3103 * Note that this is only meaningful when {@link #isCheckable()} returns {@code true}. 3104 * 3105 * @see #setCheckable(boolean) 3106 * @see #isCheckable() 3107 * @see #setChecked(int) 3108 * @return The checked state, one of: 3109 * <ul> 3110 * <li>{@link AccessibilityNodeInfo#CHECKED_STATE_FALSE} 3111 * <li>{@link AccessibilityNodeInfo#CHECKED_STATE_TRUE} 3112 * <li>{@link AccessibilityNodeInfo#CHECKED_STATE_PARTIAL} 3113 * </ul> 3114 */ 3115 @CheckedState getChecked()3116 public int getChecked() { 3117 if (Build.VERSION.SDK_INT >= 36) { 3118 return Api36Impl.getChecked(mInfo); 3119 } else { 3120 return mInfo.getExtras().getInt(CHECKED_KEY, 3121 mInfo.isChecked() ? AccessibilityNodeInfo.CHECKED_STATE_TRUE 3122 : AccessibilityNodeInfo.CHECKED_STATE_FALSE); 3123 } 3124 } 3125 3126 /** 3127 * Sets the checked state of this node. This is only meaningful 3128 * when {@link #isCheckable()} returns {@code true}. 3129 * <p><strong>Note:</strong> Cannot be called from an 3130 * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable 3131 * before being delivered to an AccessibilityService. 3132 * 3133 * @see #setCheckable(boolean) 3134 * @see #isCheckable() 3135 * @see #getChecked() 3136 * @param checked The checked state. One of 3137 * <ul> 3138 * <li>{@link AccessibilityNodeInfo#CHECKED_STATE_FALSE} 3139 * <li>{@link AccessibilityNodeInfo#CHECKED_STATE_TRUE} 3140 * <li>{@link AccessibilityNodeInfo#CHECKED_STATE_PARTIAL} 3141 * </ul> 3142 * @throws IllegalStateException If called from an AccessibilityService. 3143 * @throws IllegalArgumentException if {@code checked} is not one of 3144 * {@link AccessibilityNodeInfo#CHECKED_STATE_FALSE}, 3145 * {@link AccessibilityNodeInfo#CHECKED_STATE_TRUE}, or 3146 * {@link AccessibilityNodeInfo#CHECKED_STATE_PARTIAL}. 3147 */ setChecked(@heckedState int checked)3148 public void setChecked(@CheckedState int checked) { 3149 if (Build.VERSION.SDK_INT >= 36) { 3150 Api36Impl.setChecked(mInfo, checked); 3151 return; 3152 } 3153 3154 if (checked == AccessibilityNodeInfo.CHECKED_STATE_TRUE 3155 || checked == AccessibilityNodeInfo.CHECKED_STATE_PARTIAL 3156 || checked == AccessibilityNodeInfo.CHECKED_STATE_FALSE) { 3157 mInfo.setChecked(checked == AccessibilityNodeInfo.CHECKED_STATE_TRUE); 3158 mInfo.getExtras().putInt(CHECKED_KEY, checked); 3159 } else { 3160 throw new IllegalArgumentException("Unknown checked argument: " + checked); 3161 } 3162 } 3163 3164 /** 3165 * Gets whether a node representing a form field requires input or selection. 3166 * 3167 * @return {@code true} if {@code this} node represents a form field that requires input or 3168 * selection, {@code false} otherwise. 3169 */ isFieldRequired()3170 public boolean isFieldRequired() { 3171 if (Build.VERSION.SDK_INT >= 36) { 3172 return Api36Impl.isFieldRequired(mInfo); 3173 } else { 3174 return mInfo.getExtras().getBoolean(IS_REQUIRED_KEY); 3175 } 3176 } 3177 3178 /** 3179 * Sets whether {@code this} node represents a form field that requires input or selection. 3180 * 3181 * <p><strong>Note:</strong> Cannot be called from an AccessibilityService. This class is made 3182 * immutable before being delivered to an AccessibilityService. 3183 * 3184 * @param required {@code true} if input or selection of this node should be required, {@code 3185 * false} otherwise. 3186 * @throws IllegalStateException If called from an AccessibilityService 3187 */ setFieldRequired(boolean required)3188 public void setFieldRequired(boolean required) { 3189 if (Build.VERSION.SDK_INT >= 36) { 3190 Api36Impl.setFieldRequired(mInfo, required); 3191 } else { 3192 mInfo.getExtras().putBoolean(IS_REQUIRED_KEY, required); 3193 } 3194 } 3195 3196 /** 3197 * Gets whether this node is focusable. 3198 * 3199 * @return True if the node is focusable. 3200 */ isFocusable()3201 public boolean isFocusable() { 3202 return mInfo.isFocusable(); 3203 } 3204 3205 /** 3206 * Sets whether this node is focusable. 3207 * <p> 3208 * <strong>Note:</strong> Cannot be called from an 3209 * {@link android.accessibilityservice.AccessibilityService}. This class is 3210 * made immutable before being delivered to an AccessibilityService. 3211 * </p> 3212 * 3213 * @param focusable True if the node is focusable. 3214 * @throws IllegalStateException If called from an AccessibilityService. 3215 */ setFocusable(boolean focusable)3216 public void setFocusable(boolean focusable) { 3217 mInfo.setFocusable(focusable); 3218 } 3219 3220 /** 3221 * Gets whether this node is focused. 3222 * 3223 * @return True if the node is focused. 3224 */ isFocused()3225 public boolean isFocused() { 3226 return mInfo.isFocused(); 3227 } 3228 3229 /** 3230 * Sets whether this node is focused. 3231 * <p> 3232 * <strong>Note:</strong> Cannot be called from an 3233 * {@link android.accessibilityservice.AccessibilityService}. This class is 3234 * made immutable before being delivered to an AccessibilityService. 3235 * </p> 3236 * 3237 * @param focused True if the node is focused. 3238 * @throws IllegalStateException If called from an AccessibilityService. 3239 */ setFocused(boolean focused)3240 public void setFocused(boolean focused) { 3241 mInfo.setFocused(focused); 3242 } 3243 3244 /** 3245 * Gets whether this node is visible to the user. 3246 * 3247 * @return Whether the node is visible to the user. 3248 */ isVisibleToUser()3249 public boolean isVisibleToUser() { 3250 return mInfo.isVisibleToUser(); 3251 } 3252 3253 /** 3254 * Sets whether this node is visible to the user. 3255 * <p> 3256 * <strong>Note:</strong> Cannot be called from an 3257 * {@link android.accessibilityservice.AccessibilityService}. 3258 * This class is made immutable before being delivered to an AccessibilityService. 3259 * </p> 3260 * 3261 * @param visibleToUser Whether the node is visible to the user. 3262 * 3263 * @throws IllegalStateException If called from an AccessibilityService. 3264 */ setVisibleToUser(boolean visibleToUser)3265 public void setVisibleToUser(boolean visibleToUser) { 3266 mInfo.setVisibleToUser(visibleToUser); 3267 } 3268 3269 /** 3270 * Gets whether this node is accessibility focused. 3271 * 3272 * @return True if the node is accessibility focused. 3273 */ isAccessibilityFocused()3274 public boolean isAccessibilityFocused() { 3275 return mInfo.isAccessibilityFocused(); 3276 } 3277 3278 /** 3279 * Sets whether this node is accessibility focused. 3280 * <p> 3281 * <strong>Note:</strong> Cannot be called from an 3282 * {@link android.accessibilityservice.AccessibilityService}. 3283 * This class is made immutable before being delivered to an AccessibilityService. 3284 * </p> 3285 * 3286 * @param focused True if the node is accessibility focused. 3287 * 3288 * @throws IllegalStateException If called from an AccessibilityService. 3289 */ setAccessibilityFocused(boolean focused)3290 public void setAccessibilityFocused(boolean focused) { 3291 mInfo.setAccessibilityFocused(focused); 3292 } 3293 3294 /** 3295 * Gets whether this node is selected. 3296 * 3297 * @return True if the node is selected. 3298 */ isSelected()3299 public boolean isSelected() { 3300 return mInfo.isSelected(); 3301 } 3302 3303 /** 3304 * Sets whether this node is selected. 3305 * <p> 3306 * <strong>Note:</strong> Cannot be called from an 3307 * {@link android.accessibilityservice.AccessibilityService}. This class is 3308 * made immutable before being delivered to an AccessibilityService. 3309 * </p> 3310 * 3311 * @param selected True if the node is selected. 3312 * @throws IllegalStateException If called from an AccessibilityService. 3313 */ setSelected(boolean selected)3314 public void setSelected(boolean selected) { 3315 mInfo.setSelected(selected); 3316 } 3317 3318 /** 3319 * Gets whether this node is clickable. 3320 * 3321 * @return True if the node is clickable. 3322 */ isClickable()3323 public boolean isClickable() { 3324 return mInfo.isClickable(); 3325 } 3326 3327 /** 3328 * Sets whether this node is clickable. 3329 * <p> 3330 * <strong>Note:</strong> Cannot be called from an 3331 * {@link android.accessibilityservice.AccessibilityService}. This class is 3332 * made immutable before being delivered to an AccessibilityService. 3333 * </p> 3334 * 3335 * @param clickable True if the node is clickable. 3336 * @throws IllegalStateException If called from an AccessibilityService. 3337 */ setClickable(boolean clickable)3338 public void setClickable(boolean clickable) { 3339 mInfo.setClickable(clickable); 3340 } 3341 3342 /** 3343 * Gets whether this node is long clickable. 3344 * 3345 * @return True if the node is long clickable. 3346 */ isLongClickable()3347 public boolean isLongClickable() { 3348 return mInfo.isLongClickable(); 3349 } 3350 3351 /** 3352 * Sets whether this node is long clickable. 3353 * <p> 3354 * <strong>Note:</strong> Cannot be called from an 3355 * {@link android.accessibilityservice.AccessibilityService}. This class is 3356 * made immutable before being delivered to an AccessibilityService. 3357 * </p> 3358 * 3359 * @param longClickable True if the node is long clickable. 3360 * @throws IllegalStateException If called from an AccessibilityService. 3361 */ setLongClickable(boolean longClickable)3362 public void setLongClickable(boolean longClickable) { 3363 mInfo.setLongClickable(longClickable); 3364 } 3365 3366 /** 3367 * Gets whether this node is enabled. 3368 * 3369 * @return True if the node is enabled. 3370 */ isEnabled()3371 public boolean isEnabled() { 3372 return mInfo.isEnabled(); 3373 } 3374 3375 /** 3376 * Sets whether this node is enabled. 3377 * <p> 3378 * <strong>Note:</strong> Cannot be called from an 3379 * {@link android.accessibilityservice.AccessibilityService}. This class is 3380 * made immutable before being delivered to an AccessibilityService. 3381 * </p> 3382 * 3383 * @param enabled True if the node is enabled. 3384 * @throws IllegalStateException If called from an AccessibilityService. 3385 */ setEnabled(boolean enabled)3386 public void setEnabled(boolean enabled) { 3387 mInfo.setEnabled(enabled); 3388 } 3389 3390 /** 3391 * Gets whether this node is a password. 3392 * 3393 * @return True if the node is a password. 3394 */ isPassword()3395 public boolean isPassword() { 3396 return mInfo.isPassword(); 3397 } 3398 3399 /** 3400 * Sets whether this node is a password. 3401 * <p> 3402 * <strong>Note:</strong> Cannot be called from an 3403 * {@link android.accessibilityservice.AccessibilityService}. This class is 3404 * made immutable before being delivered to an AccessibilityService. 3405 * </p> 3406 * 3407 * @param password True if the node is a password. 3408 * @throws IllegalStateException If called from an AccessibilityService. 3409 */ setPassword(boolean password)3410 public void setPassword(boolean password) { 3411 mInfo.setPassword(password); 3412 } 3413 3414 /** 3415 * Gets if the node is scrollable. 3416 * 3417 * @return True if the node is scrollable, false otherwise. 3418 */ isScrollable()3419 public boolean isScrollable() { 3420 return mInfo.isScrollable(); 3421 } 3422 3423 /** 3424 * Sets if the node is scrollable. 3425 * <p> 3426 * <strong>Note:</strong> Cannot be called from an 3427 * {@link android.accessibilityservice.AccessibilityService}. This class is 3428 * made immutable before being delivered to an AccessibilityService. 3429 * </p> 3430 * 3431 * @param scrollable True if the node is scrollable, false otherwise. 3432 * @throws IllegalStateException If called from an AccessibilityService. 3433 */ setScrollable(boolean scrollable)3434 public void setScrollable(boolean scrollable) { 3435 mInfo.setScrollable(scrollable); 3436 } 3437 3438 3439 /** 3440 * Gets if the node supports granular scrolling. 3441 * <p> 3442 * Compatibility: 3443 * <ul> 3444 * <li>Api < 19: Returns false.</li> 3445 * </ul> 3446 * @return True if all scroll actions that could support 3447 * {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT} have done so, false otherwise. 3448 */ isGranularScrollingSupported()3449 public boolean isGranularScrollingSupported() { 3450 return getBooleanProperty(BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING); 3451 } 3452 3453 /** 3454 * Sets if the node supports granular scrolling. This should be set to true if all scroll 3455 * actions which could support {@link #ACTION_ARGUMENT_SCROLL_AMOUNT_FLOAT} have done so. 3456 * <p> 3457 * <strong>Note:</strong> Cannot be called from an 3458 * {@link android.accessibilityservice.AccessibilityService}. 3459 * This class is made immutable before being delivered to an AccessibilityService. 3460 * </p> 3461 * <p> 3462 * Compatibility: 3463 * <ul> 3464 * <li>Api < 19: No-op.</li> 3465 * </ul> 3466 * @param granularScrollingSupported True if the node supports granular scrolling, false 3467 * otherwise. 3468 * 3469 * @throws IllegalStateException If called from an AccessibilityService. 3470 */ setGranularScrollingSupported(boolean granularScrollingSupported)3471 public void setGranularScrollingSupported(boolean granularScrollingSupported) { 3472 setBooleanProperty(BOOLEAN_PROPERTY_SUPPORTS_GRANULAR_SCROLLING, 3473 granularScrollingSupported); 3474 } 3475 3476 /** 3477 * Gets if the node has selectable text. 3478 * 3479 * <p> 3480 * Services should use {@link #ACTION_SET_SELECTION} for selection. Editable text nodes must 3481 * also be selectable. But not all UIs will populate this field, so services should consider 3482 * 'isTextSelectable | isEditable' to ensure they don't miss nodes with selectable text. 3483 * </p> 3484 * <p> 3485 * Compatibility: 3486 * <ul> 3487 * <li>Api < 19: Returns false.</li> 3488 * </ul> 3489 * 3490 * @see #isEditable 3491 * @return True if the node has selectable text. 3492 */ isTextSelectable()3493 public boolean isTextSelectable() { 3494 if (Build.VERSION.SDK_INT >= 33) { 3495 return Api33Impl.isTextSelectable(mInfo); 3496 } else { 3497 return getBooleanProperty(BOOLEAN_PROPERTY_TEXT_SELECTABLE); 3498 } 3499 } 3500 3501 /** 3502 * Sets if the node has selectable text. 3503 * <p> 3504 * <strong>Note:</strong> Cannot be called from an 3505 * {@link android.accessibilityservice.AccessibilityService}. 3506 * This class is made immutable before being delivered to an AccessibilityService. 3507 * </p> 3508 * <p> 3509 * Compatibility: 3510 * <ul> 3511 * <li>Api < 19: Does not operate.</li> 3512 * </ul> 3513 * </p> 3514 * 3515 * @param selectableText True if the node has selectable text, false otherwise. 3516 * 3517 * @throws IllegalStateException If called from an AccessibilityService. 3518 */ setTextSelectable(boolean selectableText)3519 public void setTextSelectable(boolean selectableText) { 3520 if (Build.VERSION.SDK_INT >= 33) { 3521 Api33Impl.setTextSelectable(mInfo, selectableText); 3522 } else { 3523 setBooleanProperty(BOOLEAN_PROPERTY_TEXT_SELECTABLE, selectableText); 3524 } 3525 } 3526 3527 /** 3528 * Gets the minimum time duration between two content change events. 3529 */ getMinDurationBetweenContentChangesMillis()3530 public long getMinDurationBetweenContentChangesMillis() { 3531 if (Build.VERSION.SDK_INT >= 34) { 3532 return Api34Impl.getMinDurationBetweenContentChangeMillis(mInfo); 3533 } else { 3534 return mInfo.getExtras().getLong(MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY); 3535 } 3536 } 3537 3538 /** 3539 * Sets the minimum time duration between two content change events, which is used in throttling 3540 * content change events in accessibility services. 3541 * 3542 * <p> 3543 * Example: An app can set MinDurationBetweenContentChanges as 1 min for a view which sends 3544 * content change events to accessibility services one event per second. 3545 * Accessibility service will throttle those content change events and only handle one event 3546 * per minute for that view. 3547 * </p> 3548 * 3549 * @see AccessibilityEventCompat#getContentChangeTypes for all content change types. 3550 * @param duration the minimum duration between content change events. 3551 */ setMinDurationBetweenContentChangesMillis(long duration)3552 public void setMinDurationBetweenContentChangesMillis(long duration) { 3553 if (Build.VERSION.SDK_INT >= 34) { 3554 Api34Impl.setMinDurationBetweenContentChangeMillis(mInfo, duration); 3555 } else { 3556 mInfo.getExtras().putLong(MIN_DURATION_BETWEEN_CONTENT_CHANGES_KEY, duration); 3557 } 3558 } 3559 3560 /** 3561 * Returns whether the node originates from a view considered important for accessibility. 3562 * 3563 * @return {@code true} if the node originates from a view considered important for 3564 * accessibility, {@code false} otherwise 3565 * 3566 * @see View#isImportantForAccessibility() 3567 */ isImportantForAccessibility()3568 public boolean isImportantForAccessibility() { 3569 if (Build.VERSION.SDK_INT >= 24) { 3570 return mInfo.isImportantForAccessibility(); 3571 } else { 3572 return true; 3573 } 3574 } 3575 3576 /** 3577 * Sets whether the node is considered important for accessibility. 3578 * <p> 3579 * <strong>Note:</strong> Cannot be called from an 3580 * {@link android.accessibilityservice.AccessibilityService}. 3581 * This class is made immutable before being delivered to an AccessibilityService. 3582 * </p> 3583 * 3584 * @param important {@code true} if the node is considered important for accessibility, 3585 * {@code false} otherwise 3586 */ setImportantForAccessibility(boolean important)3587 public void setImportantForAccessibility(boolean important) { 3588 if (Build.VERSION.SDK_INT >= 24) { 3589 mInfo.setImportantForAccessibility(important); 3590 } 3591 } 3592 3593 /** 3594 * Gets if the node's accessibility data is considered sensitive. 3595 * 3596 * @return True if the node's data is considered sensitive, false otherwise. 3597 * @see View#isAccessibilityDataSensitive() 3598 */ isAccessibilityDataSensitive()3599 public boolean isAccessibilityDataSensitive() { 3600 if (Build.VERSION.SDK_INT >= 34) { 3601 return Api34Impl.isAccessibilityDataSensitive(mInfo); 3602 } else { 3603 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE); 3604 } 3605 } 3606 3607 /** 3608 * Sets whether this node's accessibility data is considered sensitive. 3609 * 3610 * <p> 3611 * For SDK 34 and higher: when set to true the framework will hide this node from 3612 * accessibility services with the 3613 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} 3614 * property set to false. 3615 * </p> 3616 * <p> 3617 * Otherwise, for SDK 19 and higher: the framework cannot hide this node but this property may 3618 * be read by accessibility services to provide modified behavior for sensitive nodes. 3619 * </p> 3620 * <p> 3621 * <strong>Note:</strong> Cannot be called from an 3622 * {@link android.accessibilityservice.AccessibilityService}. 3623 * This class is made immutable before being delivered to an AccessibilityService. 3624 * </p> 3625 * 3626 * @param accessibilityDataSensitive True if the node's accessibility data is considered 3627 * sensitive. 3628 * @throws IllegalStateException If called from an AccessibilityService. 3629 */ setAccessibilityDataSensitive(boolean accessibilityDataSensitive)3630 public void setAccessibilityDataSensitive(boolean accessibilityDataSensitive) { 3631 if (Build.VERSION.SDK_INT >= 34) { 3632 Api34Impl.setAccessibilityDataSensitive(mInfo, accessibilityDataSensitive); 3633 } else { 3634 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_DATA_SENSITIVE, 3635 accessibilityDataSensitive); 3636 } 3637 } 3638 3639 /** 3640 * Gets the package this node comes from. 3641 * 3642 * @return The package name. 3643 */ getPackageName()3644 public CharSequence getPackageName() { 3645 return mInfo.getPackageName(); 3646 } 3647 3648 /** 3649 * Sets the package this node comes from. 3650 * <p> 3651 * <strong>Note:</strong> Cannot be called from an 3652 * {@link android.accessibilityservice.AccessibilityService}. This class is 3653 * made immutable before being delivered to an AccessibilityService. 3654 * </p> 3655 * 3656 * @param packageName The package name. 3657 * @throws IllegalStateException If called from an AccessibilityService. 3658 */ setPackageName(CharSequence packageName)3659 public void setPackageName(CharSequence packageName) { 3660 mInfo.setPackageName(packageName); 3661 } 3662 3663 /** 3664 * Gets the class this node comes from. 3665 * 3666 * @return The class name. 3667 */ getClassName()3668 public CharSequence getClassName() { 3669 return mInfo.getClassName(); 3670 } 3671 3672 /** 3673 * Sets the class this node comes from. 3674 * <p> 3675 * <strong>Note:</strong> Cannot be called from an 3676 * {@link android.accessibilityservice.AccessibilityService}. This class is 3677 * made immutable before being delivered to an AccessibilityService. 3678 * </p> 3679 * 3680 * @param className The class name. 3681 * @throws IllegalStateException If called from an AccessibilityService. 3682 */ setClassName(CharSequence className)3683 public void setClassName(CharSequence className) { 3684 mInfo.setClassName(className); 3685 } 3686 3687 /** 3688 * Gets the text of this node. 3689 * 3690 * @return The text. 3691 */ getText()3692 public CharSequence getText() { 3693 if (hasSpans()) { 3694 List<Integer> starts = extrasIntList(SPANS_START_KEY); 3695 List<Integer> ends = extrasIntList(SPANS_END_KEY); 3696 List<Integer> flags = extrasIntList(SPANS_FLAGS_KEY); 3697 List<Integer> ids = extrasIntList(SPANS_ID_KEY); 3698 Spannable spannable = new SpannableString(TextUtils.substring(mInfo.getText(), 3699 0, mInfo.getText().length())); 3700 for (int i = 0; i < starts.size(); i++) { 3701 spannable.setSpan(new AccessibilityClickableSpanCompat(ids.get(i), this, 3702 getExtras().getInt(SPANS_ACTION_ID_KEY)), 3703 starts.get(i), ends.get(i), flags.get(i)); 3704 } 3705 return spannable; 3706 } else { 3707 return mInfo.getText(); 3708 } 3709 } 3710 3711 /** 3712 * Sets the text of this node. 3713 * <p> 3714 * <strong>Note:</strong> Cannot be called from an 3715 * {@link android.accessibilityservice.AccessibilityService}. This class is 3716 * made immutable before being delivered to an AccessibilityService. 3717 * </p> 3718 * 3719 * @param text The text. 3720 * @throws IllegalStateException If called from an AccessibilityService. 3721 */ setText(CharSequence text)3722 public void setText(CharSequence text) { 3723 mInfo.setText(text); 3724 } 3725 3726 /** 3727 */ 3728 @RestrictTo(LIBRARY_GROUP_PREFIX) addSpansToExtras(CharSequence text, View view)3729 public void addSpansToExtras(CharSequence text, View view) { 3730 if (Build.VERSION.SDK_INT < 26) { 3731 clearExtrasSpans(); 3732 removeCollectedSpans(view); 3733 ClickableSpan[] spans = getClickableSpans(text); 3734 if (spans != null && spans.length > 0) { 3735 getExtras().putInt(SPANS_ACTION_ID_KEY, R.id.accessibility_action_clickable_span); 3736 SparseArray<WeakReference<ClickableSpan>> tagSpans = 3737 getOrCreateSpansFromViewTags(view); 3738 for (int i = 0; spans != null && i < spans.length; i++) { 3739 int id = idForClickableSpan(spans[i], tagSpans); 3740 tagSpans.put(id, new WeakReference<>(spans[i])); 3741 addSpanLocationToExtras(spans[i], (Spanned) text, id); 3742 } 3743 } 3744 } 3745 } 3746 getOrCreateSpansFromViewTags(View host)3747 private SparseArray<WeakReference<ClickableSpan>> getOrCreateSpansFromViewTags(View host) { 3748 SparseArray<WeakReference<ClickableSpan>> spans = getSpansFromViewTags(host); 3749 if (spans == null) { 3750 spans = new SparseArray<>(); 3751 host.setTag(R.id.tag_accessibility_clickable_spans, spans); 3752 } 3753 return spans; 3754 } 3755 3756 @SuppressWarnings("unchecked") getSpansFromViewTags(View host)3757 private SparseArray<WeakReference<ClickableSpan>> getSpansFromViewTags(View host) { 3758 return (SparseArray<WeakReference<ClickableSpan>>) host.getTag( 3759 R.id.tag_accessibility_clickable_spans); 3760 } 3761 3762 /** 3763 */ 3764 @RestrictTo(LIBRARY_GROUP_PREFIX) getClickableSpans(CharSequence text)3765 public static ClickableSpan[] getClickableSpans(CharSequence text) { 3766 if (text instanceof Spanned) { 3767 Spanned spanned = (Spanned) text; 3768 return spanned.getSpans(0, text.length(), ClickableSpan.class); 3769 } 3770 return null; 3771 } 3772 idForClickableSpan(ClickableSpan span, SparseArray<WeakReference<ClickableSpan>> spans)3773 private int idForClickableSpan(ClickableSpan span, 3774 SparseArray<WeakReference<ClickableSpan>> spans) { 3775 if (spans != null) { 3776 for (int i = 0; i < spans.size(); i++) { 3777 ClickableSpan aSpan = spans.valueAt(i).get(); 3778 if (span.equals(aSpan)) { 3779 return spans.keyAt(i); 3780 } 3781 } 3782 } 3783 return sClickableSpanId++; 3784 } 3785 hasSpans()3786 private boolean hasSpans() { 3787 return !extrasIntList(SPANS_START_KEY).isEmpty(); 3788 } 3789 clearExtrasSpans()3790 private void clearExtrasSpans() { 3791 mInfo.getExtras().remove(SPANS_START_KEY); 3792 mInfo.getExtras().remove(SPANS_END_KEY); 3793 mInfo.getExtras().remove(SPANS_FLAGS_KEY); 3794 mInfo.getExtras().remove(SPANS_ID_KEY); 3795 } 3796 addSpanLocationToExtras(ClickableSpan span, Spanned spanned, int id)3797 private void addSpanLocationToExtras(ClickableSpan span, Spanned spanned, int id) { 3798 extrasIntList(SPANS_START_KEY).add(spanned.getSpanStart(span)); 3799 extrasIntList(SPANS_END_KEY).add(spanned.getSpanEnd(span)); 3800 extrasIntList(SPANS_FLAGS_KEY).add(spanned.getSpanFlags(span)); 3801 extrasIntList(SPANS_ID_KEY).add(id); 3802 } 3803 removeCollectedSpans(View view)3804 private void removeCollectedSpans(View view) { 3805 SparseArray<WeakReference<ClickableSpan>> spans = getSpansFromViewTags(view); 3806 if (spans != null) { 3807 List<Integer> toBeRemovedIndices = new ArrayList<>(); 3808 for (int i = 0; i < spans.size(); i++) { 3809 if (spans.valueAt(i).get() == null) { 3810 toBeRemovedIndices.add(i); 3811 } 3812 } 3813 for (int i = 0; i < toBeRemovedIndices.size(); i++) { 3814 spans.remove(toBeRemovedIndices.get(i)); 3815 } 3816 } 3817 } 3818 3819 /** 3820 * Gets the content description of this node. 3821 * 3822 * @return The content description. 3823 */ getContentDescription()3824 public CharSequence getContentDescription() { 3825 return mInfo.getContentDescription(); 3826 } 3827 3828 /** 3829 * Gets the state description of this node. 3830 * 3831 * @return the state description or null if android version smaller 3832 * than 19. 3833 */ getStateDescription()3834 public @Nullable CharSequence getStateDescription() { 3835 if (Build.VERSION.SDK_INT >= 30) { 3836 return Api30Impl.getStateDescription(mInfo); 3837 } else { 3838 return mInfo.getExtras().getCharSequence(STATE_DESCRIPTION_KEY); 3839 } 3840 } 3841 3842 /** 3843 * Sets the content description of this node. 3844 * <p> 3845 * <strong>Note:</strong> Cannot be called from an 3846 * {@link android.accessibilityservice.AccessibilityService}. This class is 3847 * made immutable before being delivered to an AccessibilityService. 3848 * </p> 3849 * 3850 * @param contentDescription The content description. 3851 * @throws IllegalStateException If called from an AccessibilityService. 3852 */ setContentDescription(CharSequence contentDescription)3853 public void setContentDescription(CharSequence contentDescription) { 3854 mInfo.setContentDescription(contentDescription); 3855 } 3856 3857 /** 3858 * Sets the state description of this node. 3859 * <p> 3860 * <strong>Note:</strong> Cannot be called from an 3861 * {@link android.accessibilityservice.AccessibilityService}. 3862 * This class is made immutable before being delivered to an AccessibilityService. 3863 * </p> 3864 * 3865 * @param stateDescription the state description of this node. 3866 * @throws IllegalStateException If called from an AccessibilityService. 3867 */ setStateDescription(@ullable CharSequence stateDescription)3868 public void setStateDescription(@Nullable CharSequence stateDescription) { 3869 if (Build.VERSION.SDK_INT >= 30) { 3870 Api30Impl.setStateDescription(mInfo, stateDescription); 3871 } else { 3872 mInfo.getExtras().putCharSequence(STATE_DESCRIPTION_KEY, stateDescription); 3873 } 3874 } 3875 3876 /** 3877 * Gets the unique id of this node. 3878 * 3879 * @return the unique id or null if android version smaller 3880 * than 19. 3881 */ getUniqueId()3882 public @Nullable String getUniqueId() { 3883 if (Build.VERSION.SDK_INT >= 33) { 3884 return Api33Impl.getUniqueId(mInfo); 3885 } else { 3886 return mInfo.getExtras().getString(UNIQUE_ID_KEY); 3887 } 3888 } 3889 3890 /** 3891 * Sets the unique id of this node. 3892 * <p> 3893 * <strong>Note:</strong> Cannot be called from an 3894 * {@link android.accessibilityservice.AccessibilityService}. 3895 * This class is made immutable before being delivered to an AccessibilityService. 3896 * </p> 3897 * 3898 * @param uniqueId the unique id of this node. 3899 * @throws IllegalStateException If called from an AccessibilityService. 3900 */ setUniqueId(@ullable String uniqueId)3901 public void setUniqueId(@Nullable String uniqueId) { 3902 if (Build.VERSION.SDK_INT >= 33) { 3903 Api33Impl.setUniqueId(mInfo, uniqueId); 3904 } else { 3905 mInfo.getExtras().putString(UNIQUE_ID_KEY, uniqueId); 3906 } 3907 } 3908 3909 /** 3910 * Sets the container title for app-developer-defined container which can be any type of 3911 * ViewGroup or layout. 3912 * Container title will be used to group together related controls, similar to HTML fieldset. 3913 * Or container title may identify a large piece of the UI that is visibly grouped together, 3914 * such as a toolbar or a card, etc. 3915 * <p> 3916 * Container title helps to assist in navigation across containers and other groups. 3917 * For example, a screen reader may use this to determine where to put accessibility focus. 3918 * </p> 3919 * <p> 3920 * Container title is different from pane title{@link #setPaneTitle} which indicates that the 3921 * node represents a window or activity. 3922 * </p> 3923 * 3924 * <p> 3925 * Example: An app can set container titles on several non-modal menus, containing TextViews 3926 * or ImageButtons that have content descriptions, text, etc. Screen readers can quickly 3927 * switch accessibility focus among menus instead of child views. Other accessibility-services 3928 * can easily find the menu. 3929 * </p> 3930 * <p> 3931 * Compatibility: 3932 * <ul> 3933 * <li>API < 19: No-op</li> 3934 * </ul> 3935 * @param containerTitle The container title that is associated with a ViewGroup/Layout on the 3936 * screen. 3937 */ setContainerTitle(@ullable CharSequence containerTitle)3938 public void setContainerTitle(@Nullable CharSequence containerTitle) { 3939 if (Build.VERSION.SDK_INT >= 34) { 3940 Api34Impl.setContainerTitle(mInfo, containerTitle); 3941 } else { 3942 mInfo.getExtras().putCharSequence(CONTAINER_TITLE_KEY, containerTitle); 3943 } 3944 } 3945 3946 /** 3947 * Returns the container title. 3948 * <p> 3949 * Compatibility: 3950 * <ul> 3951 * <li>API < 19: Returns null</li> 3952 * </ul> 3953 * @see #setContainerTitle for details. 3954 */ getContainerTitle()3955 public @Nullable CharSequence getContainerTitle() { 3956 if (Build.VERSION.SDK_INT >= 34) { 3957 return Api34Impl.getContainerTitle(mInfo); 3958 } else { 3959 return mInfo.getExtras().getCharSequence(CONTAINER_TITLE_KEY); 3960 } 3961 } 3962 3963 /** 3964 * Return an instance back to be reused. 3965 * <p> 3966 * <strong>Note:</strong> You must not touch the object after calling this function. 3967 * 3968 * @throws IllegalStateException If the info is already recycled. 3969 * @deprecated Accessibility Object recycling is no longer necessary or functional. 3970 */ 3971 @Deprecated recycle()3972 public void recycle() { } 3973 3974 /** 3975 * Sets the fully qualified resource name of the source view's id. 3976 * 3977 * <p> 3978 * <strong>Note:</strong> Cannot be called from an 3979 * {@link android.accessibilityservice.AccessibilityService}. 3980 * This class is made immutable before being delivered to an AccessibilityService. 3981 * </p> 3982 * 3983 * @param viewId The id resource name. 3984 */ setViewIdResourceName(String viewId)3985 public void setViewIdResourceName(String viewId) { 3986 mInfo.setViewIdResourceName(viewId); 3987 } 3988 3989 /** 3990 * Gets the fully qualified resource name of the source view's id. 3991 * 3992 * <p> 3993 * <strong>Note:</strong> The primary usage of this API is for UI test automation 3994 * and in order to report the source view id of an {@link AccessibilityNodeInfoCompat} 3995 * the client has to set the {@link AccessibilityServiceInfoCompat#FLAG_REPORT_VIEW_IDS} 3996 * flag when configuring their {@link android.accessibilityservice.AccessibilityService}. 3997 * </p> 3998 * 3999 * @return The id resource name. 4000 */ getViewIdResourceName()4001 public String getViewIdResourceName() { 4002 return mInfo.getViewIdResourceName(); 4003 } 4004 4005 /** 4006 * Gets the node's live region mode. 4007 * <p> 4008 * A live region is a node that contains information that is important for 4009 * the user and when it changes the user should be notified. For example, 4010 * in a login screen with a TextView that displays an "incorrect password" 4011 * notification, that view should be marked as a live region with mode 4012 * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_POLITE}. 4013 * <p> 4014 * It is the responsibility of the accessibility service to monitor 4015 * {@link AccessibilityEventCompat#TYPE_WINDOW_CONTENT_CHANGED} events 4016 * indicating changes to live region nodes and their children. 4017 * 4018 * @return The live region mode, or 4019 * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_NONE} if the view is 4020 * not a live region. 4021 * @see ViewCompat#getAccessibilityLiveRegion(View) 4022 */ getLiveRegion()4023 public int getLiveRegion() { 4024 return mInfo.getLiveRegion(); 4025 } 4026 4027 /** 4028 * Sets the node's live region mode. 4029 * <p> 4030 * <strong>Note:</strong> Cannot be called from an 4031 * {@link android.accessibilityservice.AccessibilityService}. This class is 4032 * made immutable before being delivered to an AccessibilityService. 4033 * 4034 * @param mode The live region mode, or 4035 * {@link ViewCompat#ACCESSIBILITY_LIVE_REGION_NONE} if the view is 4036 * not a live region. 4037 * @see ViewCompat#setAccessibilityLiveRegion(View, int) 4038 */ setLiveRegion(int mode)4039 public void setLiveRegion(int mode) { 4040 mInfo.setLiveRegion(mode); 4041 } 4042 4043 /** 4044 * Get the drawing order of the view corresponding it this node. 4045 * <p> 4046 * Drawing order is determined only within the node's parent, so this index is only relative 4047 * to its siblings. 4048 * <p> 4049 * In some cases, the drawing order is essentially simultaneous, so it is possible for two 4050 * siblings to return the same value. It is also possible that values will be skipped. 4051 * 4052 * @return The drawing position of the view corresponding to this node relative to its siblings. 4053 */ getDrawingOrder()4054 public int getDrawingOrder() { 4055 if (Build.VERSION.SDK_INT >= 24) { 4056 return mInfo.getDrawingOrder(); 4057 } else { 4058 return 0; 4059 } 4060 } 4061 4062 /** 4063 * Set the drawing order of the view corresponding it this node. 4064 * 4065 * <p> 4066 * <strong>Note:</strong> Cannot be called from an 4067 * {@link android.accessibilityservice.AccessibilityService}. 4068 * This class is made immutable before being delivered to an AccessibilityService. 4069 * </p> 4070 * @param drawingOrderInParent 4071 * @throws IllegalStateException If called from an AccessibilityService. 4072 */ setDrawingOrder(int drawingOrderInParent)4073 public void setDrawingOrder(int drawingOrderInParent) { 4074 if (Build.VERSION.SDK_INT >= 24) { 4075 mInfo.setDrawingOrder(drawingOrderInParent); 4076 } 4077 } 4078 4079 /** 4080 * Gets the collection info if the node is a collection. A collection 4081 * child is always a collection item. 4082 * 4083 * @return The collection info. 4084 */ getCollectionInfo()4085 public CollectionInfoCompat getCollectionInfo() { 4086 AccessibilityNodeInfo.CollectionInfo info = mInfo.getCollectionInfo(); 4087 if (info != null) { 4088 return new CollectionInfoCompat(info); 4089 } 4090 return null; 4091 } 4092 setCollectionInfo(Object collectionInfo)4093 public void setCollectionInfo(Object collectionInfo) { 4094 mInfo.setCollectionInfo((collectionInfo == null) ? null 4095 : (AccessibilityNodeInfo.CollectionInfo) ((CollectionInfoCompat) 4096 collectionInfo).mInfo); 4097 4098 } 4099 setCollectionItemInfo(Object collectionItemInfo)4100 public void setCollectionItemInfo(Object collectionItemInfo) { 4101 mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null 4102 : (AccessibilityNodeInfo.CollectionItemInfo) ((CollectionItemInfoCompat) 4103 collectionItemInfo).mInfo); 4104 } 4105 4106 /** 4107 * Gets the collection item info if the node is a collection item. A collection 4108 * item is always a child of a collection. 4109 * 4110 * @return The collection item info. 4111 */ getCollectionItemInfo()4112 public CollectionItemInfoCompat getCollectionItemInfo() { 4113 AccessibilityNodeInfo.CollectionItemInfo info = mInfo.getCollectionItemInfo(); 4114 if (info != null) { 4115 return new CollectionItemInfoCompat(info); 4116 } 4117 return null; 4118 } 4119 4120 /** 4121 * Gets the range info if this node is a range. 4122 * 4123 * @return The range. 4124 */ getRangeInfo()4125 public RangeInfoCompat getRangeInfo() { 4126 AccessibilityNodeInfo.RangeInfo info = mInfo.getRangeInfo(); 4127 if (info != null) { 4128 return new RangeInfoCompat(info); 4129 } 4130 return null; 4131 } 4132 4133 /** 4134 * Sets the range info if this node is a range. 4135 * <p> 4136 * <strong>Note:</strong> Cannot be called from an 4137 * {@link android.accessibilityservice.AccessibilityService}. 4138 * This class is made immutable before being delivered to an AccessibilityService. 4139 * </p> 4140 * 4141 * @param rangeInfo The range info. 4142 */ setRangeInfo(RangeInfoCompat rangeInfo)4143 public void setRangeInfo(RangeInfoCompat rangeInfo) { 4144 mInfo.setRangeInfo((AccessibilityNodeInfo.RangeInfo) rangeInfo.mInfo); 4145 } 4146 4147 /** 4148 * Gets the {@link android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo 4149 * extra rendering info} if the node is meant to be refreshed with extra data 4150 * to examine rendering related accessibility issues. 4151 * 4152 * @return The {@link android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo 4153 * extra rendering info}. 4154 */ getExtraRenderingInfo()4155 public AccessibilityNodeInfo.@Nullable ExtraRenderingInfo getExtraRenderingInfo() { 4156 if (Build.VERSION.SDK_INT >= 33) { 4157 return Api33Impl.getExtraRenderingInfo(mInfo); 4158 } else { 4159 return null; 4160 } 4161 } 4162 4163 /** 4164 * Gets the actions that can be performed on the node. 4165 * 4166 * @return A list of AccessibilityActions. 4167 */ 4168 @SuppressWarnings({"unchecked", "MixedMutabilityReturnType"}) getActionList()4169 public List<AccessibilityActionCompat> getActionList() { 4170 List<Object> actions = (List<Object>) (List<?>) mInfo.getActionList(); 4171 List<AccessibilityActionCompat> result = new ArrayList<>(); 4172 final int actionCount = actions.size(); 4173 for (int i = 0; i < actionCount; i++) { 4174 Object action = actions.get(i); 4175 result.add(new AccessibilityActionCompat(action)); 4176 } 4177 return result; 4178 } 4179 4180 /** 4181 * Sets if the content of this node is invalid. For example, 4182 * a date is not well-formed. 4183 * <p> 4184 * <strong>Note:</strong> Cannot be called from an 4185 * {@link android.accessibilityservice.AccessibilityService}. 4186 * This class is made immutable before being delivered to an AccessibilityService. 4187 * </p> 4188 * 4189 * @param contentInvalid If the node content is invalid. 4190 */ setContentInvalid(boolean contentInvalid)4191 public void setContentInvalid(boolean contentInvalid) { 4192 mInfo.setContentInvalid(contentInvalid); 4193 } 4194 4195 /** 4196 * Gets if the content of this node is invalid. For example, 4197 * a date is not well-formed. 4198 * 4199 * @return If the node content is invalid. 4200 */ isContentInvalid()4201 public boolean isContentInvalid() { 4202 return mInfo.isContentInvalid(); 4203 } 4204 4205 /** 4206 * Gets whether this node is context clickable. 4207 * 4208 * @return True if the node is context clickable. 4209 */ isContextClickable()4210 public boolean isContextClickable() { 4211 if (Build.VERSION.SDK_INT >= 23) { 4212 return mInfo.isContextClickable(); 4213 } else { 4214 return false; 4215 } 4216 } 4217 4218 /** 4219 * Sets whether this node is context clickable. 4220 * <p> 4221 * <strong>Note:</strong> Cannot be called from an 4222 * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable 4223 * before being delivered to an AccessibilityService. 4224 * </p> 4225 * 4226 * @param contextClickable True if the node is context clickable. 4227 * @throws IllegalStateException If called from an AccessibilityService. 4228 */ setContextClickable(boolean contextClickable)4229 public void setContextClickable(boolean contextClickable) { 4230 if (Build.VERSION.SDK_INT >= 23) { 4231 mInfo.setContextClickable(contextClickable); 4232 } 4233 } 4234 4235 /** 4236 * Gets the hint text of this node. Only applies to nodes where text can be entered. 4237 * 4238 * @return The hint text. 4239 */ getHintText()4240 public @Nullable CharSequence getHintText() { 4241 if (Build.VERSION.SDK_INT >= 26) { 4242 return mInfo.getHintText(); 4243 } else { 4244 return mInfo.getExtras().getCharSequence(HINT_TEXT_KEY); 4245 } 4246 } 4247 4248 /** 4249 * Sets the hint text of this node. Only applies to nodes where text can be entered. 4250 * <p>This method has no effect below API 19</p> 4251 * <p> 4252 * <strong>Note:</strong> Cannot be called from an 4253 * {@link android.accessibilityservice.AccessibilityService}. 4254 * This class is made immutable before being delivered to an AccessibilityService. 4255 * </p> 4256 * 4257 * @param hintText The hint text for this mode. 4258 * 4259 * @throws IllegalStateException If called from an AccessibilityService. 4260 */ setHintText(@ullable CharSequence hintText)4261 public void setHintText(@Nullable CharSequence hintText) { 4262 if (Build.VERSION.SDK_INT >= 26) { 4263 mInfo.setHintText(hintText); 4264 } else { 4265 mInfo.getExtras().putCharSequence(HINT_TEXT_KEY, hintText); 4266 } 4267 } 4268 4269 4270 /** 4271 * Sets the error text of this node. 4272 * <p> 4273 * <strong>Note:</strong> Cannot be called from an 4274 * {@link android.accessibilityservice.AccessibilityService}. 4275 * This class is made immutable before being delivered to an AccessibilityService. 4276 * </p> 4277 * 4278 * @param error The error text. 4279 * 4280 * @throws IllegalStateException If called from an AccessibilityService. 4281 */ setError(CharSequence error)4282 public void setError(CharSequence error) { 4283 mInfo.setError(error); 4284 } 4285 4286 /** 4287 * Gets the error text of this node. 4288 * 4289 * @return The error text. 4290 */ getError()4291 public CharSequence getError() { 4292 return mInfo.getError(); 4293 } 4294 4295 /** 4296 * Sets the view for which the view represented by this info serves as a 4297 * label for accessibility purposes. 4298 * 4299 * @param labeled The view for which this info serves as a label. 4300 */ setLabelFor(View labeled)4301 public void setLabelFor(View labeled) { 4302 mInfo.setLabelFor(labeled); 4303 } 4304 4305 /** 4306 * Sets the view for which the view represented by this info serves as a 4307 * label for accessibility purposes. If <code>virtualDescendantId</code> 4308 * is {@link View#NO_ID} the root is set as the labeled. 4309 * <p> 4310 * A virtual descendant is an imaginary View that is reported as a part of the view 4311 * hierarchy for accessibility purposes. This enables custom views that draw complex 4312 * content to report themselves as a tree of virtual views, thus conveying their 4313 * logical structure. 4314 * </p> 4315 * 4316 * @param root The root whose virtual descendant serves as a label. 4317 * @param virtualDescendantId The id of the virtual descendant. 4318 */ setLabelFor(View root, int virtualDescendantId)4319 public void setLabelFor(View root, int virtualDescendantId) { 4320 mInfo.setLabelFor(root, virtualDescendantId); 4321 } 4322 4323 /** 4324 * Gets the node info for which the view represented by this info serves as 4325 * a label for accessibility purposes. 4326 * 4327 * @return The labeled info. 4328 */ getLabelFor()4329 public AccessibilityNodeInfoCompat getLabelFor() { 4330 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabelFor()); 4331 } 4332 4333 /** 4334 * Sets the view which serves as the label of the view represented by 4335 * this info for accessibility purposes. 4336 * 4337 * @param label The view that labels this node's source. 4338 */ setLabeledBy(View label)4339 public void setLabeledBy(View label) { 4340 mInfo.setLabeledBy(label); 4341 } 4342 4343 /** 4344 * Sets the view which serves as the label of the view represented by 4345 * this info for accessibility purposes. If <code>virtualDescendantId</code> 4346 * is {@link View#NO_ID} the root is set as the label. 4347 * <p> 4348 * A virtual descendant is an imaginary View that is reported as a part of the view 4349 * hierarchy for accessibility purposes. This enables custom views that draw complex 4350 * content to report themselves as a tree of virtual views, thus conveying their 4351 * logical structure. 4352 * </p> 4353 * <p> 4354 * <strong>Note:</strong> Cannot be called from an 4355 * {@link android.accessibilityservice.AccessibilityService}. 4356 * This class is made immutable before being delivered to an AccessibilityService. 4357 * </p> 4358 * 4359 * @param root The root whose virtual descendant labels this node's source. 4360 * @param virtualDescendantId The id of the virtual descendant. 4361 */ setLabeledBy(View root, int virtualDescendantId)4362 public void setLabeledBy(View root, int virtualDescendantId) { 4363 mInfo.setLabeledBy(root, virtualDescendantId); 4364 } 4365 4366 /** 4367 * Gets the node info which serves as the label of the view represented by 4368 * this info for accessibility purposes. 4369 * 4370 * @return The label. 4371 */ getLabeledBy()4372 public AccessibilityNodeInfoCompat getLabeledBy() { 4373 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getLabeledBy()); 4374 } 4375 4376 /** 4377 * Gets if this node opens a popup or a dialog. 4378 * 4379 * @return If the the node opens a popup. 4380 */ canOpenPopup()4381 public boolean canOpenPopup() { 4382 return mInfo.canOpenPopup(); 4383 } 4384 4385 /** 4386 * Sets if this node opens a popup or a dialog. 4387 * <p> 4388 * <strong>Note:</strong> Cannot be called from an 4389 * {@link android.accessibilityservice.AccessibilityService}. 4390 * This class is made immutable before being delivered to an AccessibilityService. 4391 * </p> 4392 * 4393 * @param opensPopup If the the node opens a popup. 4394 */ setCanOpenPopup(boolean opensPopup)4395 public void setCanOpenPopup(boolean opensPopup) { 4396 mInfo.setCanOpenPopup(opensPopup); 4397 } 4398 4399 /** 4400 * Finds {@link AccessibilityNodeInfoCompat}s by the fully qualified view id's resource 4401 * name where a fully qualified id is of the from "package:id/id_resource_name". 4402 * For example, if the target application's package is "foo.bar" and the id 4403 * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz". 4404 * 4405 * <p> 4406 * <strong>Note:</strong> The primary usage of this API is for UI test automation 4407 * and in order to report the fully qualified view id if an 4408 * {@link AccessibilityNodeInfoCompat} the client has to set the 4409 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} 4410 * flag when configuring their {@link android.accessibilityservice.AccessibilityService}. 4411 * </p> 4412 * 4413 * @param viewId The fully qualified resource name of the view id to find. 4414 * @return A list of node info. 4415 */ 4416 @SuppressWarnings("MixedMutabilityReturnType") findAccessibilityNodeInfosByViewId(String viewId)4417 public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(String viewId) { 4418 List<AccessibilityNodeInfo> nodes = mInfo.findAccessibilityNodeInfosByViewId(viewId); 4419 List<AccessibilityNodeInfoCompat> result = new ArrayList<>(); 4420 for (AccessibilityNodeInfo node : nodes) { 4421 result.add(AccessibilityNodeInfoCompat.wrap(node)); 4422 } 4423 return result; 4424 } 4425 4426 /** 4427 * Gets an optional bundle with extra data. The bundle 4428 * is lazily created and never <code>null</code>. 4429 * <p> 4430 * <strong>Note:</strong> It is recommended to use the package 4431 * name of your application as a prefix for the keys to avoid 4432 * collisions which may confuse an accessibility service if the 4433 * same key has different meaning when emitted from different 4434 * applications. 4435 * </p> 4436 * 4437 * @return The bundle. 4438 */ getExtras()4439 public Bundle getExtras() { 4440 return mInfo.getExtras(); 4441 } 4442 4443 /** 4444 * Gets the input type of the source as defined by {@link InputType}. 4445 * 4446 * @return The input type. 4447 */ getInputType()4448 public int getInputType() { 4449 return mInfo.getInputType(); 4450 } 4451 4452 /** 4453 * Sets the input type of the source as defined by {@link InputType}. 4454 * <p> 4455 * <strong>Note:</strong> Cannot be called from an 4456 * {@link android.accessibilityservice.AccessibilityService}. 4457 * This class is made immutable before being delivered to an 4458 * AccessibilityService. 4459 * </p> 4460 * 4461 * @param inputType The input type. 4462 * 4463 * @throws IllegalStateException If called from an AccessibilityService. 4464 */ setInputType(int inputType)4465 public void setInputType(int inputType) { 4466 mInfo.setInputType(inputType); 4467 } 4468 4469 /** 4470 * Get the extra data available for this node. 4471 * <p> 4472 * Some data that is useful for some accessibility services is expensive to compute, and would 4473 * place undue overhead on apps to compute all the time. That data can be requested with 4474 * {@link android.view.accessibility.AccessibilityNodeInfo#refreshWithExtraData(String, Bundle)}. 4475 * 4476 * @return An unmodifiable list of keys corresponding to extra data that can be requested. 4477 * @see #EXTRA_DATA_RENDERING_INFO_KEY 4478 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 4479 */ getAvailableExtraData()4480 public @NonNull List<String> getAvailableExtraData() { 4481 if (Build.VERSION.SDK_INT >= 26) { 4482 return mInfo.getAvailableExtraData(); 4483 } else { 4484 return emptyList(); 4485 } 4486 } 4487 4488 /** 4489 * Set the extra data available for this node. 4490 * <p> 4491 * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that 4492 * it will populate the node's extras with corresponding pieces of information in 4493 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}. 4494 * <p> 4495 * <strong>Note:</strong> Cannot be called from an 4496 * {@link android.accessibilityservice.AccessibilityService}. 4497 * This class is made immutable before being delivered to an AccessibilityService. 4498 * 4499 * @param extraDataKeys A list of types of extra data that are available. 4500 * @see #getAvailableExtraData() 4501 * 4502 * @throws IllegalStateException If called from an AccessibilityService. 4503 */ setAvailableExtraData(@onNull List<String> extraDataKeys)4504 public void setAvailableExtraData(@NonNull List<String> extraDataKeys) { 4505 if (Build.VERSION.SDK_INT >= 26) { 4506 mInfo.setAvailableExtraData(extraDataKeys); 4507 } 4508 } 4509 4510 /** 4511 * Sets the maximum text length, or -1 for no limit. 4512 * <p> 4513 * Typically used to indicate that an editable text field has a limit on 4514 * the number of characters entered. 4515 * <p> 4516 * <strong>Note:</strong> Cannot be called from an 4517 * {@link android.accessibilityservice.AccessibilityService}. 4518 * This class is made immutable before being delivered to an AccessibilityService. 4519 * 4520 * @param max The maximum text length. 4521 * @see #getMaxTextLength() 4522 * 4523 * @throws IllegalStateException If called from an AccessibilityService. 4524 */ setMaxTextLength(int max)4525 public void setMaxTextLength(int max) { 4526 mInfo.setMaxTextLength(max); 4527 } 4528 4529 /** 4530 * Returns the maximum text length for this node. 4531 * 4532 * @return The maximum text length, or -1 for no limit. 4533 * @see #setMaxTextLength(int) 4534 */ getMaxTextLength()4535 public int getMaxTextLength() { 4536 return mInfo.getMaxTextLength(); 4537 } 4538 4539 /** 4540 * Sets the text selection start and end. 4541 * <p> 4542 * <strong>Note:</strong> Cannot be called from an 4543 * {@link android.accessibilityservice.AccessibilityService}. 4544 * This class is made immutable before being delivered to an AccessibilityService. 4545 * </p> 4546 * 4547 * @param start The text selection start. 4548 * @param end The text selection end. 4549 * 4550 * @throws IllegalStateException If called from an AccessibilityService. 4551 */ setTextSelection(int start, int end)4552 public void setTextSelection(int start, int end) { 4553 mInfo.setTextSelection(start, end); 4554 } 4555 4556 /** 4557 * Gets the text selection start. 4558 * 4559 * @return The text selection start if there is selection or -1. 4560 */ getTextSelectionStart()4561 public int getTextSelectionStart() { 4562 return mInfo.getTextSelectionStart(); 4563 } 4564 4565 /** 4566 * Gets the text selection end. 4567 * 4568 * @return The text selection end if there is selection or -1. 4569 */ getTextSelectionEnd()4570 public int getTextSelectionEnd() { 4571 return mInfo.getTextSelectionEnd(); 4572 } 4573 4574 /** 4575 * Gets the node before which this one is visited during traversal. A screen-reader 4576 * must visit the content of this node before the content of the one it precedes. 4577 * 4578 * @return The succeeding node if such or <code>null</code>. 4579 * 4580 * @see #setTraversalBefore(android.view.View) 4581 * @see #setTraversalBefore(android.view.View, int) 4582 */ getTraversalBefore()4583 public AccessibilityNodeInfoCompat getTraversalBefore() { 4584 if (Build.VERSION.SDK_INT >= 22) { 4585 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalBefore()); 4586 } else { 4587 return null; 4588 } 4589 } 4590 4591 /** 4592 * Sets the view before whose node this one should be visited during traversal. A 4593 * screen-reader must visit the content of this node before the content of the one 4594 * it precedes. 4595 * <p> 4596 * <strong>Note:</strong> Cannot be called from an 4597 * {@link android.accessibilityservice.AccessibilityService}. 4598 * This class is made immutable before being delivered to an AccessibilityService. 4599 * </p> 4600 * 4601 * @param view The view providing the preceding node. 4602 * 4603 * @see #getTraversalBefore() 4604 */ setTraversalBefore(View view)4605 public void setTraversalBefore(View view) { 4606 if (Build.VERSION.SDK_INT >= 22) { 4607 mInfo.setTraversalBefore(view); 4608 } 4609 } 4610 4611 /** 4612 * Sets the node before which this one is visited during traversal. A screen-reader 4613 * must visit the content of this node before the content of the one it precedes. 4614 * The successor is a virtual descendant of the given <code>root</code>. If 4615 * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set 4616 * as the successor. 4617 * <p> 4618 * A virtual descendant is an imaginary View that is reported as a part of the view 4619 * hierarchy for accessibility purposes. This enables custom views that draw complex 4620 * content to report them selves as a tree of virtual views, thus conveying their 4621 * logical structure. 4622 * </p> 4623 * <p> 4624 * <strong>Note:</strong> Cannot be called from an 4625 * {@link android.accessibilityservice.AccessibilityService}. 4626 * This class is made immutable before being delivered to an AccessibilityService. 4627 * </p> 4628 * 4629 * @param root The root of the virtual subtree. 4630 * @param virtualDescendantId The id of the virtual descendant. 4631 */ setTraversalBefore(View root, int virtualDescendantId)4632 public void setTraversalBefore(View root, int virtualDescendantId) { 4633 if (Build.VERSION.SDK_INT >= 22) { 4634 mInfo.setTraversalBefore(root, virtualDescendantId); 4635 } 4636 } 4637 4638 /** 4639 * Gets the node after which this one is visited in accessibility traversal. 4640 * A screen-reader must visit the content of the other node before the content 4641 * of this one. 4642 * 4643 * @return The succeeding node if such or <code>null</code>. 4644 * 4645 * @see #setTraversalAfter(android.view.View) 4646 * @see #setTraversalAfter(android.view.View, int) 4647 */ getTraversalAfter()4648 public AccessibilityNodeInfoCompat getTraversalAfter() { 4649 if (Build.VERSION.SDK_INT >= 22) { 4650 return AccessibilityNodeInfoCompat.wrapNonNullInstance(mInfo.getTraversalAfter()); 4651 } else { 4652 return null; 4653 } 4654 } 4655 4656 /** 4657 * Sets the view whose node is visited after this one in accessibility traversal. 4658 * A screen-reader must visit the content of the other node before the content 4659 * of this one. 4660 * <p> 4661 * <strong>Note:</strong> Cannot be called from an 4662 * {@link android.accessibilityservice.AccessibilityService}. 4663 * This class is made immutable before being delivered to an AccessibilityService. 4664 * </p> 4665 * 4666 * @param view The previous view. 4667 * 4668 * @see #getTraversalAfter() 4669 */ setTraversalAfter(View view)4670 public void setTraversalAfter(View view) { 4671 if (Build.VERSION.SDK_INT >= 22) { 4672 mInfo.setTraversalAfter(view); 4673 } 4674 } 4675 4676 /** 4677 * Sets the node after which this one is visited in accessibility traversal. 4678 * A screen-reader must visit the content of the other node before the content 4679 * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID} 4680 * the root is set as the predecessor. 4681 * <p> 4682 * A virtual descendant is an imaginary View that is reported as a part of the view 4683 * hierarchy for accessibility purposes. This enables custom views that draw complex 4684 * content to report them selves as a tree of virtual views, thus conveying their 4685 * logical structure. 4686 * </p> 4687 * <p> 4688 * <strong>Note:</strong> Cannot be called from an 4689 * {@link android.accessibilityservice.AccessibilityService}. 4690 * This class is made immutable before being delivered to an AccessibilityService. 4691 * </p> 4692 * 4693 * @param root The root of the virtual subtree. 4694 * @param virtualDescendantId The id of the virtual descendant. 4695 */ setTraversalAfter(View root, int virtualDescendantId)4696 public void setTraversalAfter(View root, int virtualDescendantId) { 4697 if (Build.VERSION.SDK_INT >= 22) { 4698 mInfo.setTraversalAfter(root, virtualDescendantId); 4699 } 4700 } 4701 4702 /** 4703 * Gets the window to which this node belongs. 4704 * 4705 * @return The window. 4706 * 4707 * @see android.accessibilityservice.AccessibilityService#getWindows() 4708 */ getWindow()4709 public AccessibilityWindowInfoCompat getWindow() { 4710 return AccessibilityWindowInfoCompat.wrapNonNullInstance(mInfo.getWindow()); 4711 } 4712 4713 /** 4714 * Gets if the node can be dismissed. 4715 * 4716 * @return If the node can be dismissed. 4717 */ isDismissable()4718 public boolean isDismissable() { 4719 return mInfo.isDismissable(); 4720 } 4721 4722 /** 4723 * Sets if the node can be dismissed. 4724 * <p> 4725 * <strong>Note:</strong> Cannot be called from an 4726 * {@link android.accessibilityservice.AccessibilityService}. 4727 * This class is made immutable before being delivered to an AccessibilityService. 4728 * </p> 4729 * 4730 * @param dismissable If the node can be dismissed. 4731 */ setDismissable(boolean dismissable)4732 public void setDismissable(boolean dismissable) { 4733 mInfo.setDismissable(dismissable); 4734 } 4735 4736 /** 4737 * Gets if the node is editable. 4738 * 4739 * @return True if the node is editable, false otherwise. 4740 */ isEditable()4741 public boolean isEditable() { 4742 return mInfo.isEditable(); 4743 } 4744 4745 /** 4746 * Sets whether this node is editable. 4747 * <p> 4748 * <strong>Note:</strong> Cannot be called from an 4749 * {@link android.accessibilityservice.AccessibilityService}. 4750 * This class is made immutable before being delivered to an AccessibilityService. 4751 * </p> 4752 * 4753 * @param editable True if the node is editable. 4754 * 4755 * @throws IllegalStateException If called from an AccessibilityService. 4756 */ setEditable(boolean editable)4757 public void setEditable(boolean editable) { 4758 mInfo.setEditable(editable); 4759 } 4760 4761 /** 4762 * Gets if the node is a multi line editable text. 4763 * 4764 * @return True if the node is multi line. 4765 */ isMultiLine()4766 public boolean isMultiLine() { 4767 return mInfo.isMultiLine(); 4768 } 4769 4770 /** 4771 * Sets if the node is a multi line editable text. 4772 * <p> 4773 * <strong>Note:</strong> Cannot be called from an 4774 * {@link android.accessibilityservice.AccessibilityService}. 4775 * This class is made immutable before being delivered to an AccessibilityService. 4776 * </p> 4777 * 4778 * @param multiLine True if the node is multi line. 4779 */ setMultiLine(boolean multiLine)4780 public void setMultiLine(boolean multiLine) { 4781 mInfo.setMultiLine(multiLine); 4782 } 4783 4784 /** 4785 * Gets the tooltip text of this node. 4786 * 4787 * @return The tooltip text. 4788 */ getTooltipText()4789 public @Nullable CharSequence getTooltipText() { 4790 if (Build.VERSION.SDK_INT >= 28) { 4791 return mInfo.getTooltipText(); 4792 } else { 4793 return mInfo.getExtras().getCharSequence(TOOLTIP_TEXT_KEY); 4794 } 4795 } 4796 4797 /** 4798 * Sets the tooltip text of this node. 4799 * <p>This method has no effect below API 19</p> 4800 * <p> 4801 * <strong>Note:</strong> Cannot be called from an 4802 * {@link android.accessibilityservice.AccessibilityService}. 4803 * This class is made immutable before being delivered to an AccessibilityService. 4804 * </p> 4805 * 4806 * @param tooltipText The tooltip text. 4807 * 4808 * @throws IllegalStateException If called from an AccessibilityService. 4809 */ setTooltipText(@ullable CharSequence tooltipText)4810 public void setTooltipText(@Nullable CharSequence tooltipText) { 4811 if (Build.VERSION.SDK_INT >= 28) { 4812 mInfo.setTooltipText(tooltipText); 4813 } else { 4814 mInfo.getExtras().putCharSequence(TOOLTIP_TEXT_KEY, tooltipText); 4815 } 4816 } 4817 4818 /** 4819 * If this node represents a visually distinct region of the screen that may update separately 4820 * from the rest of the window, it is considered a pane. Set the pane title to indicate that 4821 * the node is a pane, and to provide a title for it. 4822 * <p>This method has no effect below API 19</p> 4823 * <p> 4824 * <strong>Note:</strong> Cannot be called from an 4825 * {@link android.accessibilityservice.AccessibilityService}. 4826 * This class is made immutable before being delivered to an AccessibilityService. 4827 * </p> 4828 * @param paneTitle The title of the window represented by this node. 4829 */ setPaneTitle(@ullable CharSequence paneTitle)4830 public void setPaneTitle(@Nullable CharSequence paneTitle) { 4831 if (Build.VERSION.SDK_INT >= 28) { 4832 mInfo.setPaneTitle(paneTitle); 4833 } else { 4834 mInfo.getExtras().putCharSequence(PANE_TITLE_KEY, paneTitle); 4835 } 4836 } 4837 4838 /** 4839 * Get the title of the pane represented by this node. 4840 * 4841 * @return The title of the pane represented by this node, or {@code null} if this node does 4842 * not represent a pane. 4843 */ getPaneTitle()4844 public @Nullable CharSequence getPaneTitle() { 4845 if (Build.VERSION.SDK_INT >= 28) { 4846 return mInfo.getPaneTitle(); 4847 } else { 4848 return mInfo.getExtras().getCharSequence(PANE_TITLE_KEY); 4849 } 4850 } 4851 4852 /** 4853 * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note 4854 * that {@code false} indicates that it is not explicitly marked, not that the node is not 4855 * a focusable unit. Screen readers should generally use other signals, such as 4856 * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive 4857 * focus. 4858 * 4859 * @return {@code true} if the node is specifically marked as a focusable unit for screen 4860 * readers, {@code false} otherwise. 4861 */ isScreenReaderFocusable()4862 public boolean isScreenReaderFocusable() { 4863 if (Build.VERSION.SDK_INT >= 28) { 4864 return mInfo.isScreenReaderFocusable(); 4865 } 4866 return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE); 4867 } 4868 4869 /** 4870 * Sets whether the node should be considered a focusable unit by a screen reader. 4871 * <p>This method has no effect below API 19</p> 4872 * <p> 4873 * <strong>Note:</strong> Cannot be called from an 4874 * {@link android.accessibilityservice.AccessibilityService}. 4875 * This class is made immutable before being delivered to an AccessibilityService. 4876 * </p> 4877 * 4878 * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers, 4879 * {@code false} otherwise. 4880 */ setScreenReaderFocusable(boolean screenReaderFocusable)4881 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 4882 if (Build.VERSION.SDK_INT >= 28) { 4883 mInfo.setScreenReaderFocusable(screenReaderFocusable); 4884 } else { 4885 setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 4886 } 4887 } 4888 4889 /** 4890 * Returns whether the node's text represents a hint for the user to enter text. It should only 4891 * be {@code true} if the node has editable text. 4892 * 4893 * @return {@code true} if the text in the node represents a hint to the user, {@code false} 4894 * otherwise. 4895 */ isShowingHintText()4896 public boolean isShowingHintText() { 4897 if (Build.VERSION.SDK_INT >= 26) { 4898 return mInfo.isShowingHintText(); 4899 } 4900 return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT); 4901 } 4902 4903 /** 4904 * Sets whether the node's text represents a hint for the user to enter text. It should only 4905 * be {@code true} if the node has editable text. 4906 * <p>This method has no effect below API 19</p> 4907 * <p> 4908 * <strong>Note:</strong> Cannot be called from an 4909 * {@link android.accessibilityservice.AccessibilityService}. 4910 * This class is made immutable before being delivered to an AccessibilityService. 4911 * </p> 4912 * 4913 * @param showingHintText {@code true} if the text in the node represents a hint to the user, 4914 * {@code false} otherwise. 4915 */ setShowingHintText(boolean showingHintText)4916 public void setShowingHintText(boolean showingHintText) { 4917 if (Build.VERSION.SDK_INT >= 26) { 4918 mInfo.setShowingHintText(showingHintText); 4919 } else { 4920 setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText); 4921 } 4922 } 4923 4924 /** 4925 * Returns whether node represents a heading. 4926 * <p><strong>Note:</strong> Returns {@code true} if either {@link #setHeading(boolean)} 4927 * marks this node as a heading or if the node has a {@link CollectionItemInfoCompat} that marks 4928 * it as such, to accommodate apps that use the now-deprecated API.</p> 4929 * 4930 * @return {@code true} if the node is a heading, {@code false} otherwise. 4931 */ 4932 @SuppressWarnings("deprecation") isHeading()4933 public boolean isHeading() { 4934 if (Build.VERSION.SDK_INT >= 28) { 4935 return mInfo.isHeading(); 4936 } 4937 if (getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING)) return true; 4938 CollectionItemInfoCompat collectionItemInfo = getCollectionItemInfo(); 4939 return (collectionItemInfo != null) && collectionItemInfo.isHeading(); 4940 } 4941 4942 /** 4943 * Sets whether the node represents a heading. 4944 * <p>This method has no effect below API 19</p> 4945 * <p> 4946 * <strong>Note:</strong> Cannot be called from an 4947 * {@link android.accessibilityservice.AccessibilityService}. 4948 * This class is made immutable before being delivered to an AccessibilityService. 4949 * </p> 4950 * 4951 * @param isHeading {@code true} if the node is a heading, {@code false} otherwise. 4952 */ setHeading(boolean isHeading)4953 public void setHeading(boolean isHeading) { 4954 if (Build.VERSION.SDK_INT >= 28) { 4955 mInfo.setHeading(isHeading); 4956 } else { 4957 setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading); 4958 } 4959 } 4960 4961 /** 4962 * Returns whether node represents a text entry key that is part of a keyboard or keypad. 4963 * 4964 * @return {@code true} if the node is a text entry key, {@code false} otherwise. 4965 */ isTextEntryKey()4966 public boolean isTextEntryKey() { 4967 if (Build.VERSION.SDK_INT >= 29) { 4968 return mInfo.isTextEntryKey(); 4969 } 4970 return getBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY); 4971 } 4972 4973 /** 4974 * Sets whether the node represents a text entry key that is part of a keyboard or keypad. 4975 * <p>This method has no effect below API 19</p> 4976 * <p> 4977 * <strong>Note:</strong> Cannot be called from an 4978 * {@link android.accessibilityservice.AccessibilityService}. 4979 * This class is made immutable before being delivered to an AccessibilityService. 4980 * </p> 4981 * 4982 * @param isTextEntryKey {@code true} if the node is a text entry key, {@code false} otherwise. 4983 */ setTextEntryKey(boolean isTextEntryKey)4984 public void setTextEntryKey(boolean isTextEntryKey) { 4985 if (Build.VERSION.SDK_INT >= 29) { 4986 mInfo.setTextEntryKey(isTextEntryKey); 4987 } else { 4988 setBooleanProperty(BOOLEAN_PROPERTY_IS_TEXT_ENTRY_KEY, isTextEntryKey); 4989 } 4990 } 4991 4992 /** 4993 * Gets whether the node has {@link #setRequestInitialAccessibilityFocus}. 4994 * 4995 * @return True if the node has requested initial accessibility focus. 4996 */ 4997 @SuppressLint("KotlinPropertyAccess") hasRequestInitialAccessibilityFocus()4998 public boolean hasRequestInitialAccessibilityFocus() { 4999 if (Build.VERSION.SDK_INT >= 34) { 5000 return Api34Impl.hasRequestInitialAccessibilityFocus(mInfo); 5001 } else { 5002 return getBooleanProperty(BOOLEAN_PROPERTY_HAS_REQUEST_INITIAL_ACCESSIBILITY_FOCUS); 5003 } 5004 } 5005 5006 /** 5007 * Sets whether the node has requested initial accessibility focus. 5008 * 5009 * <p> 5010 * If the node {@link #hasRequestInitialAccessibilityFocus}, this node would be one of 5011 * candidates to be accessibility focused when the window appears. 5012 * </p> 5013 * 5014 * <p> 5015 * <strong>Note:</strong> Cannot be called from an 5016 * {@link android.accessibilityservice.AccessibilityService}. 5017 * This class is made immutable before being delivered to an AccessibilityService. 5018 * </p> 5019 * 5020 * @param requestInitialAccessibilityFocus True if the node requests to receive initial 5021 * accessibility focus. 5022 * @throws IllegalStateException If called from an AccessibilityService. 5023 */ 5024 @SuppressLint("GetterSetterNames") setRequestInitialAccessibilityFocus(boolean requestInitialAccessibilityFocus)5025 public void setRequestInitialAccessibilityFocus(boolean requestInitialAccessibilityFocus) { 5026 if (Build.VERSION.SDK_INT >= 34) { 5027 Api34Impl.setRequestInitialAccessibilityFocus(mInfo, requestInitialAccessibilityFocus); 5028 } else { 5029 setBooleanProperty(BOOLEAN_PROPERTY_HAS_REQUEST_INITIAL_ACCESSIBILITY_FOCUS, 5030 requestInitialAccessibilityFocus); 5031 } 5032 } 5033 5034 /** 5035 * Refreshes this info with the latest state of the view it represents. 5036 * <p> 5037 * <strong>Note:</strong> If this method returns false this info is obsolete 5038 * since it represents a view that is no longer in the view tree. 5039 * </p> 5040 * @return Whether the refresh succeeded. 5041 */ refresh()5042 public boolean refresh() { 5043 return mInfo.refresh(); 5044 } 5045 5046 /** 5047 * Gets the custom role description. 5048 * @return The role description. 5049 */ getRoleDescription()5050 public @Nullable CharSequence getRoleDescription() { 5051 return mInfo.getExtras().getCharSequence(ROLE_DESCRIPTION_KEY); 5052 } 5053 5054 /** 5055 * Sets the custom role description. 5056 * 5057 * <p> 5058 * The role description allows you to customize the name for the view's semantic 5059 * role. For example, if you create a custom subclass of {@link android.view.View} 5060 * to display a menu bar, you could assign it the role description of "menu bar". 5061 * </p> 5062 * <p> 5063 * <strong>Warning:</strong> For consistency with other applications, you should 5064 * not use the role description to force accessibility services to describe 5065 * standard views (such as buttons or checkboxes) using specific wording. For 5066 * example, you should not set a role description of "check box" or "tick box" for 5067 * a standard {@link android.widget.CheckBox}. Instead let accessibility services 5068 * decide what feedback to provide. 5069 * </p> 5070 * <p> 5071 * <strong>Note:</strong> Cannot be called from an 5072 * {@link android.accessibilityservice.AccessibilityService}. 5073 * This class is made immutable before being delivered to an AccessibilityService. 5074 * </p> 5075 * 5076 * @param roleDescription The role description. 5077 */ setRoleDescription(@ullable CharSequence roleDescription)5078 public void setRoleDescription(@Nullable CharSequence roleDescription) { 5079 mInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, roleDescription); 5080 } 5081 5082 /** 5083 * Get the {@link TouchDelegateInfoCompat} for touch delegate behavior with the represented 5084 * view. It is possible for the same node to be pointed to by several regions. Use 5085 * {@link TouchDelegateInfoCompat#getRegionAt(int)} to get touch delegate target 5086 * {@link Region}, and {@link TouchDelegateInfoCompat#getTargetForRegion(Region)} 5087 * for {@link AccessibilityNodeInfoCompat} from the given region. 5088 * <p> 5089 * Compatibility: 5090 * <ul> 5091 * <li>API < 29: Always returns {@code null}</li> 5092 * </ul> 5093 * 5094 * @return {@link TouchDelegateInfoCompat} or {@code null} if there are no touch delegates 5095 * in this node. 5096 */ getTouchDelegateInfo()5097 public @Nullable TouchDelegateInfoCompat getTouchDelegateInfo() { 5098 if (Build.VERSION.SDK_INT >= 29) { 5099 TouchDelegateInfo delegateInfo = mInfo.getTouchDelegateInfo(); 5100 if (delegateInfo != null) { 5101 return new TouchDelegateInfoCompat(delegateInfo); 5102 } 5103 } 5104 return null; 5105 } 5106 5107 /** 5108 * Set touch delegate info if the represented view has a {@link android.view.TouchDelegate}. 5109 * <p> 5110 * <strong>Note:</strong> Cannot be called from an 5111 * {@link android.accessibilityservice.AccessibilityService}. 5112 * This class is made immutable before being delivered to an 5113 * AccessibilityService. 5114 * </p> 5115 * <p> 5116 * Compatibility: 5117 * <ul> 5118 * <li>API < 29: No-op</li> 5119 * </ul> 5120 * 5121 * @param delegatedInfo {@link TouchDelegateInfoCompat} 5122 * @throws IllegalStateException If called from an AccessibilityService. 5123 */ setTouchDelegateInfo(@onNull TouchDelegateInfoCompat delegatedInfo)5124 public void setTouchDelegateInfo(@NonNull TouchDelegateInfoCompat delegatedInfo) { 5125 if (Build.VERSION.SDK_INT >= 29) { 5126 mInfo.setTouchDelegateInfo(delegatedInfo.mInfo); 5127 } 5128 } 5129 5130 /** 5131 * Connects this node to the View's root so that operations on this node can query the entire 5132 * {@link AccessibilityNodeInfoCompat} tree and perform accessibility actions on nodes. 5133 * 5134 * <p> 5135 * Testing or debugging tools should create this {@link AccessibilityNodeInfoCompat} node using 5136 * {@link ViewCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)} 5137 * or {@link AccessibilityNodeProviderCompat} and call this 5138 * method, then navigate and interact with the node tree by calling methods on the node. 5139 * Calling this method more than once on the same node is a no-op. After calling this method, 5140 * all nodes linked to this node (children, ancestors, etc.) are also queryable. 5141 * </p> 5142 * 5143 * <p> 5144 * Here "query" refers to the following node operations: 5145 * <ul> 5146 * <li>check properties of this node (example: {@link #isScrollable()})</li> 5147 * <li>find and query children (example: {@link #getChild(int)})</li> 5148 * <li>find and query the parent (example: {@link #getParent()})</li> 5149 * <li>find focus (examples: {@link #findFocus(int)}, {@link #focusSearch(int)})</li> 5150 * <li>find and query other nodes (example: 5151 * {@link #findAccessibilityNodeInfosByText(String)}, 5152 * {@link #findAccessibilityNodeInfosByViewId(String)})</li> 5153 * <li>perform actions (example: {@link #performAction(int)})</li> 5154 * </ul> 5155 * </p> 5156 * 5157 * <p> 5158 * This is intended for short-lived inspections from testing or debugging tools in the app 5159 * process, as operations on this node tree will only succeed as long as the associated 5160 * view hierarchy remains attached to a window. {@link AccessibilityNodeInfoCompat} objects can 5161 * quickly become out of sync with their corresponding {@link View} objects; if you wish to 5162 * inspect a changed or different view hierarchy then create a new node from any view in that 5163 * hierarchy and call this method on that new node, instead of disabling & re-enabling the 5164 * connection on the previous node. 5165 * </p> 5166 * <p> 5167 * Compatibility: 5168 * <ul> 5169 * <li>API < 34: No-op</li> 5170 * </ul> 5171 * 5172 * @param view The view that generated this node, or any view in the same view-root hierarchy. 5173 * @param enabled Whether to enable (true) or disable (false) querying from the app process. 5174 * @throws IllegalStateException If called from an {@link AccessibilityService}, or if provided 5175 * a {@link View} that is not attached to a window. 5176 */ setQueryFromAppProcessEnabled(@onNull View view, boolean enabled)5177 public void setQueryFromAppProcessEnabled(@NonNull View view, boolean enabled) { 5178 if (Build.VERSION.SDK_INT >= 34) { 5179 Api34Impl.setQueryFromAppProcessEnabled(mInfo, view, enabled); 5180 } 5181 } 5182 5183 /** 5184 * Returns the supplemental description of this {@link AccessibilityNodeInfoCompat}. 5185 * <p> 5186 * A supplemental description provides brief supplemental information for this node, such as 5187 * the purpose of the node when that purpose is not conveyed within its textual representation. 5188 * For example, if a dropdown select has a purpose of setting font family, the supplemental 5189 * description could be "font family". If this node has children, its supplemental description 5190 * serves as additional information and is not intended to replace any existing information in 5191 * the subtree. This is different from the {@link #getContentDescription()} in that this 5192 * description is purely supplemental while a content description may be used to replace a 5193 * description for a node or its subtree that an assistive technology would otherwise compute 5194 * based on other properties of the node and its descendants. 5195 * 5196 * @return The supplemental description. 5197 * @see #setSupplementalDescription(CharSequence) 5198 * @see #getContentDescription() 5199 */ 5200 @Nullable getSupplementalDescription()5201 public CharSequence getSupplementalDescription() { 5202 if (Build.VERSION.SDK_INT >= 36) { 5203 return Api36Impl.getSupplementalDescription(mInfo); 5204 } else { 5205 return mInfo.getExtras().getCharSequence(SUPPLEMENTAL_DESCRIPTION_KEY); 5206 } 5207 } 5208 5209 /** 5210 * Sets the supplemental description of this {@link AccessibilityNodeInfoCompat}. 5211 * <p> 5212 * A supplemental description provides brief supplemental information for this node, such as 5213 * the purpose of the node when that purpose is not conveyed within its textual representation. 5214 * For example, if a dropdown select has a purpose of setting font family, the supplemental 5215 * description could be "font family". If this node has children, its supplemental description 5216 * serves as additional information and is not intended to replace any existing information in 5217 * the subtree. This is different from the {@link #setContentDescription(CharSequence)} in that 5218 * this description is purely supplemental while a content description may be used to replace a 5219 * description for a node or its subtree that an assistive technology would otherwise compute 5220 * based on other properties of the node and its descendants. 5221 * 5222 * <p> 5223 * <strong>Note:</strong> Cannot be called from an {@link 5224 * android.accessibilityservice.AccessibilityService}. This class is made immutable before being 5225 * delivered to an AccessibilityService. 5226 * 5227 * @param supplementalDescription The supplemental description. 5228 * @throws IllegalStateException If called from an AccessibilityService. 5229 * @see #getSupplementalDescription() 5230 * @see #setContentDescription(CharSequence) 5231 */ setSupplementalDescription(@ullable CharSequence supplementalDescription)5232 public void setSupplementalDescription(@Nullable CharSequence supplementalDescription) { 5233 if (Build.VERSION.SDK_INT >= 36) { 5234 Api36Impl.setSupplementalDescription(mInfo, supplementalDescription); 5235 } else { 5236 mInfo.getExtras() 5237 .putCharSequence(SUPPLEMENTAL_DESCRIPTION_KEY, supplementalDescription); 5238 } 5239 } 5240 5241 @Override hashCode()5242 public int hashCode() { 5243 return (mInfo == null) ? 0 : mInfo.hashCode(); 5244 } 5245 5246 @Override equals(Object obj)5247 public boolean equals(Object obj) { 5248 if (this == obj) { 5249 return true; 5250 } 5251 if (obj == null) { 5252 return false; 5253 } 5254 if (!(obj instanceof AccessibilityNodeInfoCompat)) { 5255 return false; 5256 } 5257 AccessibilityNodeInfoCompat other = (AccessibilityNodeInfoCompat) obj; 5258 if (mInfo == null) { 5259 if (other.mInfo != null) { 5260 return false; 5261 } 5262 } else if (!mInfo.equals(other.mInfo)) { 5263 return false; 5264 } 5265 if (mVirtualDescendantId != other.mVirtualDescendantId) { 5266 return false; 5267 } 5268 if (mParentVirtualDescendantId != other.mParentVirtualDescendantId) { 5269 return false; 5270 } 5271 return true; 5272 } 5273 5274 @SuppressWarnings("deprecation") 5275 @Override toString()5276 public @NonNull String toString() { 5277 StringBuilder builder = new StringBuilder(); 5278 builder.append(super.toString()); 5279 5280 Rect bounds = new Rect(); 5281 5282 getBoundsInParent(bounds); 5283 builder.append("; boundsInParent: " + bounds); 5284 5285 getBoundsInScreen(bounds); 5286 builder.append("; boundsInScreen: " + bounds); 5287 5288 getBoundsInWindow(bounds); 5289 builder.append("; boundsInWindow: " + bounds); 5290 5291 builder.append("; packageName: ").append(getPackageName()); 5292 builder.append("; className: ").append(getClassName()); 5293 builder.append("; text: ").append(getText()); 5294 builder.append("; error: ").append(getError()); 5295 builder.append("; maxTextLength: ").append(getMaxTextLength()); 5296 builder.append("; stateDescription: ").append(getStateDescription()); 5297 builder.append("; contentDescription: ").append(getContentDescription()); 5298 builder.append("; supplementalDescription: ").append(getSupplementalDescription()); 5299 builder.append("; tooltipText: ").append(getTooltipText()); 5300 builder.append("; viewIdResName: ").append(getViewIdResourceName()); 5301 builder.append("; uniqueId: ").append(getUniqueId()); 5302 5303 builder.append("; checkable: ").append(isCheckable()); 5304 builder.append("; checked: ").append(getCheckedString()); 5305 builder.append("; fieldRequired: ").append(isFieldRequired()); 5306 builder.append("; focusable: ").append(isFocusable()); 5307 builder.append("; focused: ").append(isFocused()); 5308 builder.append("; selected: ").append(isSelected()); 5309 builder.append("; clickable: ").append(isClickable()); 5310 builder.append("; longClickable: ").append(isLongClickable()); 5311 builder.append("; contextClickable: ").append(isContextClickable()); 5312 builder.append("; expandedState: ").append( 5313 getExpandedStateSymbolicName(getExpandedState())); 5314 builder.append("; enabled: ").append(isEnabled()); 5315 builder.append("; password: ").append(isPassword()); 5316 builder.append("; scrollable: " + isScrollable()); 5317 builder.append("; containerTitle: ").append(getContainerTitle()); 5318 builder.append("; granularScrollingSupported: ").append(isGranularScrollingSupported()); 5319 builder.append("; importantForAccessibility: ").append(isImportantForAccessibility()); 5320 builder.append("; visible: ").append(isVisibleToUser()); 5321 builder.append("; isTextSelectable: ").append(isTextSelectable()); 5322 builder.append("; accessibilityDataSensitive: ").append(isAccessibilityDataSensitive()); 5323 5324 builder.append("; ["); 5325 List<AccessibilityActionCompat> actions = getActionList(); 5326 for (int i = 0; i < actions.size(); i++) { 5327 AccessibilityActionCompat action = actions.get(i); 5328 String actionName = getActionSymbolicName(action.getId()); 5329 if (actionName.equals("ACTION_UNKNOWN") && action.getLabel() != null) { 5330 actionName = action.getLabel().toString(); 5331 } 5332 builder.append(actionName); 5333 if (i != actions.size() - 1) { 5334 builder.append(", "); 5335 } 5336 } 5337 builder.append("]"); 5338 5339 return builder.toString(); 5340 } 5341 setBooleanProperty(int property, boolean value)5342 private void setBooleanProperty(int property, boolean value) { 5343 Bundle extras = getExtras(); 5344 if (extras != null) { 5345 int booleanProperties = extras.getInt(BOOLEAN_PROPERTY_KEY, 0); 5346 booleanProperties &= ~property; 5347 booleanProperties |= value ? property : 0; 5348 extras.putInt(BOOLEAN_PROPERTY_KEY, booleanProperties); 5349 } 5350 } 5351 getBooleanProperty(int property)5352 private boolean getBooleanProperty(int property) { 5353 Bundle extras = getExtras(); 5354 if (extras == null) return false; 5355 return (extras.getInt(BOOLEAN_PROPERTY_KEY, 0) & property) == property; 5356 } 5357 getCheckedString()5358 private String getCheckedString() { 5359 @CheckedState int checkedState = getChecked(); 5360 if (checkedState == AccessibilityNodeInfo.CHECKED_STATE_TRUE) { 5361 return "TRUE"; 5362 } else if (checkedState == AccessibilityNodeInfo.CHECKED_STATE_PARTIAL) { 5363 return "PARTIAL"; 5364 } else { 5365 return "FALSE"; 5366 } 5367 } 5368 getActionSymbolicName(int action)5369 static String getActionSymbolicName(int action) { 5370 switch (action) { 5371 case ACTION_FOCUS: 5372 return "ACTION_FOCUS"; 5373 case ACTION_CLEAR_FOCUS: 5374 return "ACTION_CLEAR_FOCUS"; 5375 case ACTION_SELECT: 5376 return "ACTION_SELECT"; 5377 case ACTION_CLEAR_SELECTION: 5378 return "ACTION_CLEAR_SELECTION"; 5379 case ACTION_CLICK: 5380 return "ACTION_CLICK"; 5381 case ACTION_LONG_CLICK: 5382 return "ACTION_LONG_CLICK"; 5383 case ACTION_ACCESSIBILITY_FOCUS: 5384 return "ACTION_ACCESSIBILITY_FOCUS"; 5385 case ACTION_CLEAR_ACCESSIBILITY_FOCUS: 5386 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS"; 5387 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY: 5388 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY"; 5389 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: 5390 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY"; 5391 case ACTION_NEXT_HTML_ELEMENT: 5392 return "ACTION_NEXT_HTML_ELEMENT"; 5393 case ACTION_PREVIOUS_HTML_ELEMENT: 5394 return "ACTION_PREVIOUS_HTML_ELEMENT"; 5395 case ACTION_SCROLL_FORWARD: 5396 return "ACTION_SCROLL_FORWARD"; 5397 case ACTION_SCROLL_BACKWARD: 5398 return "ACTION_SCROLL_BACKWARD"; 5399 case ACTION_CUT: 5400 return "ACTION_CUT"; 5401 case ACTION_COPY: 5402 return "ACTION_COPY"; 5403 case ACTION_PASTE: 5404 return "ACTION_PASTE"; 5405 case ACTION_SET_SELECTION: 5406 return "ACTION_SET_SELECTION"; 5407 case ACTION_EXPAND: 5408 return "ACTION_EXPAND"; 5409 case ACTION_COLLAPSE: 5410 return "ACTION_COLLAPSE"; 5411 case ACTION_SET_TEXT: 5412 return "ACTION_SET_TEXT"; 5413 case android.R.id.accessibilityActionScrollUp: 5414 return "ACTION_SCROLL_UP"; 5415 case android.R.id.accessibilityActionScrollLeft: 5416 return "ACTION_SCROLL_LEFT"; 5417 case android.R.id.accessibilityActionScrollDown: 5418 return "ACTION_SCROLL_DOWN"; 5419 case android.R.id.accessibilityActionScrollRight: 5420 return "ACTION_SCROLL_RIGHT"; 5421 case android.R.id.accessibilityActionPageDown: 5422 return "ACTION_PAGE_DOWN"; 5423 case android.R.id.accessibilityActionPageUp: 5424 return "ACTION_PAGE_UP"; 5425 case android.R.id.accessibilityActionPageLeft: 5426 return "ACTION_PAGE_LEFT"; 5427 case android.R.id.accessibilityActionPageRight: 5428 return "ACTION_PAGE_RIGHT"; 5429 case android.R.id.accessibilityActionShowOnScreen: 5430 return "ACTION_SHOW_ON_SCREEN"; 5431 case android.R.id.accessibilityActionScrollToPosition: 5432 return "ACTION_SCROLL_TO_POSITION"; 5433 case android.R.id.accessibilityActionContextClick: 5434 return "ACTION_CONTEXT_CLICK"; 5435 case android.R.id.accessibilityActionSetProgress: 5436 return "ACTION_SET_PROGRESS"; 5437 case android.R.id.accessibilityActionMoveWindow: 5438 return "ACTION_MOVE_WINDOW"; 5439 case android.R.id.accessibilityActionShowTooltip: 5440 return "ACTION_SHOW_TOOLTIP"; 5441 case android.R.id.accessibilityActionHideTooltip: 5442 return "ACTION_HIDE_TOOLTIP"; 5443 case android.R.id.accessibilityActionPressAndHold: 5444 return "ACTION_PRESS_AND_HOLD"; 5445 case android.R.id.accessibilityActionImeEnter: 5446 return "ACTION_IME_ENTER"; 5447 case android.R.id.accessibilityActionDragStart: 5448 return "ACTION_DRAG_START"; 5449 case android.R.id.accessibilityActionDragDrop: 5450 return "ACTION_DRAG_DROP"; 5451 case android.R.id.accessibilityActionDragCancel: 5452 return "ACTION_DRAG_CANCEL"; 5453 case android.R.id.accessibilityActionScrollInDirection: 5454 return "ACTION_SCROLL_IN_DIRECTION"; 5455 default: 5456 return "ACTION_UNKNOWN"; 5457 } 5458 } 5459 getExpandedStateSymbolicName(@xpandedState int state)5460 static String getExpandedStateSymbolicName(@ExpandedState int state) { 5461 switch(state) { 5462 case AccessibilityNodeInfo.EXPANDED_STATE_UNDEFINED: 5463 return "UNDEFINED"; 5464 case AccessibilityNodeInfo.EXPANDED_STATE_COLLAPSED: 5465 return "COLLAPSED"; 5466 case AccessibilityNodeInfo.EXPANDED_STATE_PARTIAL: 5467 return "PARTIAL"; 5468 case AccessibilityNodeInfo.EXPANDED_STATE_FULL: 5469 return "FULL"; 5470 default: 5471 return "UNKNOWN"; 5472 } 5473 } 5474 5475 @RequiresApi(30) 5476 private static class Api30Impl { Api30Impl()5477 private Api30Impl() { 5478 // This class is non instantiable. 5479 } 5480 setStateDescription(AccessibilityNodeInfo info, CharSequence stateDescription)5481 public static void setStateDescription(AccessibilityNodeInfo info, 5482 CharSequence stateDescription) { 5483 info.setStateDescription(stateDescription); 5484 } 5485 getStateDescription(AccessibilityNodeInfo info)5486 public static CharSequence getStateDescription(AccessibilityNodeInfo info) { 5487 return info.getStateDescription(); 5488 } 5489 createRangeInfo(int type, float min, float max, float current)5490 public static Object createRangeInfo(int type, float min, float max, float current) { 5491 return new AccessibilityNodeInfo.RangeInfo(type, min, max, current); 5492 } 5493 } 5494 5495 @RequiresApi(33) 5496 private static class Api33Impl { Api33Impl()5497 private Api33Impl() { 5498 // This class is non instantiable. 5499 } 5500 getExtraRenderingInfo( AccessibilityNodeInfo info)5501 public static AccessibilityNodeInfo.ExtraRenderingInfo getExtraRenderingInfo( 5502 AccessibilityNodeInfo info) { 5503 return info.getExtraRenderingInfo(); 5504 } 5505 isTextSelectable(AccessibilityNodeInfo info)5506 public static boolean isTextSelectable(AccessibilityNodeInfo info) { 5507 return info.isTextSelectable(); 5508 } 5509 setTextSelectable(AccessibilityNodeInfo info, boolean selectable)5510 public static void setTextSelectable(AccessibilityNodeInfo info, boolean selectable) { 5511 info.setTextSelectable(selectable); 5512 } 5513 buildCollectionItemInfoCompat( boolean heading, int columnIndex, int rowIndex, int columnSpan, int rowSpan, boolean selected, String rowTitle, String columnTitle)5514 public static CollectionItemInfoCompat buildCollectionItemInfoCompat( 5515 boolean heading, int columnIndex, int rowIndex, int columnSpan, 5516 int rowSpan, boolean selected, String rowTitle, String columnTitle) { 5517 return new CollectionItemInfoCompat( 5518 new AccessibilityNodeInfo.CollectionItemInfo.Builder() 5519 .setHeading(heading).setColumnIndex(columnIndex) 5520 .setRowIndex(rowIndex) 5521 .setColumnSpan(columnSpan) 5522 .setRowSpan(rowSpan) 5523 .setSelected(selected) 5524 .setRowTitle(rowTitle) 5525 .setColumnTitle(columnTitle) 5526 .build()); 5527 } 5528 getChild(AccessibilityNodeInfo info, int index, int prefetchingStrategy)5529 public static AccessibilityNodeInfoCompat getChild(AccessibilityNodeInfo info, int index, 5530 int prefetchingStrategy) { 5531 return AccessibilityNodeInfoCompat.wrapNonNullInstance(info.getChild(index, 5532 prefetchingStrategy)); 5533 } 5534 getParent(AccessibilityNodeInfo info, int prefetchingStrategy)5535 public static AccessibilityNodeInfoCompat getParent(AccessibilityNodeInfo info, 5536 int prefetchingStrategy) { 5537 return AccessibilityNodeInfoCompat.wrapNonNullInstance(info.getParent( 5538 prefetchingStrategy)); 5539 } 5540 getUniqueId(AccessibilityNodeInfo info)5541 public static String getUniqueId(AccessibilityNodeInfo info) { 5542 return info.getUniqueId(); 5543 } 5544 setUniqueId(AccessibilityNodeInfo info, String uniqueId)5545 public static void setUniqueId(AccessibilityNodeInfo info, String uniqueId) { 5546 info.setUniqueId(uniqueId); 5547 } 5548 getCollectionItemRowTitle(Object info)5549 public static String getCollectionItemRowTitle(Object info) { 5550 return ((AccessibilityNodeInfo.CollectionItemInfo) info).getRowTitle(); 5551 5552 } 5553 getCollectionItemColumnTitle(Object info)5554 public static String getCollectionItemColumnTitle(Object info) { 5555 return ((AccessibilityNodeInfo.CollectionItemInfo) info).getColumnTitle(); 5556 } 5557 } 5558 5559 @RequiresApi(34) 5560 private static class Api34Impl { Api34Impl()5561 private Api34Impl() { 5562 // This class is non instantiable. 5563 } 5564 isAccessibilityDataSensitive(AccessibilityNodeInfo info)5565 public static boolean isAccessibilityDataSensitive(AccessibilityNodeInfo info) { 5566 return info.isAccessibilityDataSensitive(); 5567 } 5568 setAccessibilityDataSensitive(AccessibilityNodeInfo info, boolean accessibilityDataSensitive)5569 public static void setAccessibilityDataSensitive(AccessibilityNodeInfo info, 5570 boolean accessibilityDataSensitive) { 5571 info.setAccessibilityDataSensitive(accessibilityDataSensitive); 5572 } 5573 getContainerTitle(AccessibilityNodeInfo info)5574 public static CharSequence getContainerTitle(AccessibilityNodeInfo info) { 5575 return info.getContainerTitle(); 5576 } 5577 setContainerTitle(AccessibilityNodeInfo info, CharSequence containerTitle)5578 public static void setContainerTitle(AccessibilityNodeInfo info, 5579 CharSequence containerTitle) { 5580 info.setContainerTitle(containerTitle); 5581 } 5582 getBoundsInWindow(AccessibilityNodeInfo info, Rect bounds)5583 public static void getBoundsInWindow(AccessibilityNodeInfo info, Rect bounds) { 5584 info.getBoundsInWindow(bounds); 5585 } 5586 setBoundsInWindow(AccessibilityNodeInfo info, Rect bounds)5587 public static void setBoundsInWindow(AccessibilityNodeInfo info, Rect bounds) { 5588 info.setBoundsInWindow(bounds); 5589 } 5590 hasRequestInitialAccessibilityFocus(AccessibilityNodeInfo info)5591 public static boolean hasRequestInitialAccessibilityFocus(AccessibilityNodeInfo info) { 5592 return info.hasRequestInitialAccessibilityFocus(); 5593 } 5594 setRequestInitialAccessibilityFocus(AccessibilityNodeInfo info, boolean requestInitialAccessibilityFocus)5595 public static void setRequestInitialAccessibilityFocus(AccessibilityNodeInfo info, 5596 boolean requestInitialAccessibilityFocus) { 5597 info.setRequestInitialAccessibilityFocus(requestInitialAccessibilityFocus); 5598 } 5599 getMinDurationBetweenContentChangeMillis(AccessibilityNodeInfo info)5600 public static long getMinDurationBetweenContentChangeMillis(AccessibilityNodeInfo info) { 5601 return info.getMinDurationBetweenContentChanges().toMillis(); 5602 } 5603 setMinDurationBetweenContentChangeMillis(AccessibilityNodeInfo info, long duration)5604 public static void setMinDurationBetweenContentChangeMillis(AccessibilityNodeInfo info, 5605 long duration) { 5606 info.setMinDurationBetweenContentChanges(Duration.ofMillis(duration)); 5607 } 5608 setQueryFromAppProcessEnabled(AccessibilityNodeInfo info, View view, boolean enabled)5609 public static void setQueryFromAppProcessEnabled(AccessibilityNodeInfo info, View view, 5610 boolean enabled) { 5611 info.setQueryFromAppProcessEnabled(view, enabled); 5612 } 5613 getActionScrollInDirection()5614 public static AccessibilityNodeInfo.AccessibilityAction getActionScrollInDirection() { 5615 return AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_IN_DIRECTION; 5616 } 5617 } 5618 5619 @RequiresApi(35) 5620 private static class Api35Impl { Api35Impl()5621 private Api35Impl() { 5622 // This class is non instantiable. 5623 } 5624 getItemCount(Object info)5625 public static int getItemCount(Object info) { 5626 return ((AccessibilityNodeInfo.CollectionInfo) info).getItemCount(); 5627 } 5628 getImportantForAccessibilityItemCount(Object info)5629 public static int getImportantForAccessibilityItemCount(Object info) { 5630 return ((AccessibilityNodeInfo.CollectionInfo) info) 5631 .getImportantForAccessibilityItemCount(); 5632 } 5633 buildCollectionInfoCompat(int rowCount, int columnCount, boolean hierarchical, int selectionMode, int itemCount, int importantForAccessibilityItemCount)5634 public static CollectionInfoCompat buildCollectionInfoCompat(int rowCount, int columnCount, 5635 boolean hierarchical, int selectionMode, int itemCount, 5636 int importantForAccessibilityItemCount) { 5637 return new CollectionInfoCompat(new AccessibilityNodeInfo.CollectionInfo.Builder() 5638 .setRowCount(rowCount) 5639 .setColumnCount(columnCount) 5640 .setHierarchical(hierarchical) 5641 .setSelectionMode(selectionMode) 5642 .setItemCount(itemCount) 5643 .setImportantForAccessibilityItemCount(importantForAccessibilityItemCount) 5644 .build()); 5645 } 5646 } 5647 5648 @RequiresApi(36) 5649 private static class Api36Impl { Api36Impl()5650 private Api36Impl() { 5651 // This class is non instantiable. 5652 } 5653 5654 @ExpandedState getExpandedState(AccessibilityNodeInfo info)5655 public static int getExpandedState(AccessibilityNodeInfo info) { 5656 return info.getExpandedState(); 5657 } 5658 setExpandedState(AccessibilityNodeInfo info, @ExpandedState int state)5659 public static void setExpandedState(AccessibilityNodeInfo info, @ExpandedState int state) { 5660 info.setExpandedState(state); 5661 } 5662 isFieldRequired(AccessibilityNodeInfo info)5663 public static boolean isFieldRequired(AccessibilityNodeInfo info) { 5664 return info.isFieldRequired(); 5665 } 5666 setFieldRequired(AccessibilityNodeInfo info, boolean required)5667 public static void setFieldRequired(AccessibilityNodeInfo info, boolean required) { 5668 info.setFieldRequired(required); 5669 } 5670 5671 @Nullable getSupplementalDescription(AccessibilityNodeInfo info)5672 public static CharSequence getSupplementalDescription(AccessibilityNodeInfo info) { 5673 return info.getSupplementalDescription(); 5674 } 5675 setSupplementalDescription( AccessibilityNodeInfo info, @Nullable CharSequence supplementalDescription)5676 public static void setSupplementalDescription( 5677 AccessibilityNodeInfo info, @Nullable CharSequence supplementalDescription) { 5678 info.setSupplementalDescription(supplementalDescription); 5679 } 5680 5681 @CheckedState getChecked(AccessibilityNodeInfo info)5682 private static int getChecked(AccessibilityNodeInfo info) { 5683 return info.getChecked(); 5684 } 5685 setChecked(AccessibilityNodeInfo info, @CheckedState int checked)5686 private static void setChecked(AccessibilityNodeInfo info, @CheckedState int checked) { 5687 info.setChecked(checked); 5688 } 5689 } 5690 } 5691