AccessibilityNodeInfo.java revision d89905f0a46dea3d8ca8d0bacc0c33db488e0b36
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 17package android.view.accessibility; 18 19import static com.android.internal.util.BitUtils.bitAt; 20import static com.android.internal.util.BitUtils.isBitSet; 21 22import static java.util.Collections.EMPTY_LIST; 23 24import android.accessibilityservice.AccessibilityService; 25import android.accessibilityservice.AccessibilityServiceInfo; 26import android.annotation.Nullable; 27import android.annotation.TestApi; 28import android.graphics.Rect; 29import android.os.Bundle; 30import android.os.Parcel; 31import android.os.Parcelable; 32import android.text.InputType; 33import android.text.Spannable; 34import android.text.SpannableStringBuilder; 35import android.text.Spanned; 36import android.text.TextUtils; 37import android.text.style.AccessibilityClickableSpan; 38import android.text.style.AccessibilityURLSpan; 39import android.text.style.ClickableSpan; 40import android.text.style.URLSpan; 41import android.util.ArraySet; 42import android.util.LongArray; 43import android.util.Pools.SynchronizedPool; 44import android.view.View; 45 46import com.android.internal.R; 47import com.android.internal.util.CollectionUtils; 48 49import java.util.ArrayList; 50import java.util.Collections; 51import java.util.List; 52import java.util.Objects; 53import java.util.concurrent.atomic.AtomicInteger; 54 55/** 56 * This class represents a node of the window content as well as actions that 57 * can be requested from its source. From the point of view of an 58 * {@link android.accessibilityservice.AccessibilityService} a window's content is 59 * presented as a tree of accessibility node infos, which may or may not map one-to-one 60 * to the view hierarchy. In other words, a custom view is free to report itself as 61 * a tree of accessibility node info. 62 * </p> 63 * <p> 64 * Once an accessibility node info is delivered to an accessibility service it is 65 * made immutable and calling a state mutation method generates an error. 66 * </p> 67 * <p> 68 * Please refer to {@link android.accessibilityservice.AccessibilityService} for 69 * details about how to obtain a handle to window content as a tree of accessibility 70 * node info as well as details about the security model. 71 * </p> 72 * <div class="special reference"> 73 * <h3>Developer Guides</h3> 74 * <p>For more information about making applications accessible, read the 75 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 76 * developer guide.</p> 77 * </div> 78 * 79 * @see android.accessibilityservice.AccessibilityService 80 * @see AccessibilityEvent 81 * @see AccessibilityManager 82 */ 83public class AccessibilityNodeInfo implements Parcelable { 84 85 private static final boolean DEBUG = false; 86 87 /** @hide */ 88 public static final int UNDEFINED_CONNECTION_ID = -1; 89 90 /** @hide */ 91 public static final int UNDEFINED_SELECTION_INDEX = -1; 92 93 /** @hide */ 94 public static final int UNDEFINED_ITEM_ID = Integer.MAX_VALUE; 95 96 /** @hide */ 97 public static final int ROOT_ITEM_ID = Integer.MAX_VALUE - 1; 98 99 /** @hide */ 100 public static final long UNDEFINED_NODE_ID = makeNodeId(UNDEFINED_ITEM_ID, UNDEFINED_ITEM_ID); 101 102 /** @hide */ 103 public static final long ROOT_NODE_ID = makeNodeId(ROOT_ITEM_ID, 104 AccessibilityNodeProvider.HOST_VIEW_ID); 105 106 /** @hide */ 107 public static final int FLAG_PREFETCH_PREDECESSORS = 0x00000001; 108 109 /** @hide */ 110 public static final int FLAG_PREFETCH_SIBLINGS = 0x00000002; 111 112 /** @hide */ 113 public static final int FLAG_PREFETCH_DESCENDANTS = 0x00000004; 114 115 /** @hide */ 116 public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x00000008; 117 118 /** @hide */ 119 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010; 120 121 // Actions. 122 123 /** 124 * Action that gives input focus to the node. 125 */ 126 public static final int ACTION_FOCUS = 0x00000001; 127 128 /** 129 * Action that clears input focus of the node. 130 */ 131 public static final int ACTION_CLEAR_FOCUS = 0x00000002; 132 133 /** 134 * Action that selects the node. 135 */ 136 public static final int ACTION_SELECT = 0x00000004; 137 138 /** 139 * Action that deselects the node. 140 */ 141 public static final int ACTION_CLEAR_SELECTION = 0x00000008; 142 143 /** 144 * Action that clicks on the node info. 145 * 146 * See {@link AccessibilityAction#ACTION_CLICK} 147 */ 148 public static final int ACTION_CLICK = 0x00000010; 149 150 /** 151 * Action that long clicks on the node. 152 */ 153 public static final int ACTION_LONG_CLICK = 0x00000020; 154 155 /** 156 * Action that gives accessibility focus to the node. 157 */ 158 public static final int ACTION_ACCESSIBILITY_FOCUS = 0x00000040; 159 160 /** 161 * Action that clears accessibility focus of the node. 162 */ 163 public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 0x00000080; 164 165 /** 166 * Action that requests to go to the next entity in this node's text 167 * at a given movement granularity. For example, move to the next character, 168 * word, etc. 169 * <p> 170 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, 171 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 172 * <strong>Example:</strong> Move to the previous character and do not extend selection. 173 * <code><pre><p> 174 * Bundle arguments = new Bundle(); 175 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 176 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 177 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 178 * false); 179 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments); 180 * </code></pre></p> 181 * </p> 182 * 183 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 184 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 185 * 186 * @see #setMovementGranularities(int) 187 * @see #getMovementGranularities() 188 * 189 * @see #MOVEMENT_GRANULARITY_CHARACTER 190 * @see #MOVEMENT_GRANULARITY_WORD 191 * @see #MOVEMENT_GRANULARITY_LINE 192 * @see #MOVEMENT_GRANULARITY_PARAGRAPH 193 * @see #MOVEMENT_GRANULARITY_PAGE 194 */ 195 public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 0x00000100; 196 197 /** 198 * Action that requests to go to the previous entity in this node's text 199 * at a given movement granularity. For example, move to the next character, 200 * word, etc. 201 * <p> 202 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<, 203 * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 204 * <strong>Example:</strong> Move to the next character and do not extend selection. 205 * <code><pre><p> 206 * Bundle arguments = new Bundle(); 207 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 208 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 209 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 210 * false); 211 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, 212 * arguments); 213 * </code></pre></p> 214 * </p> 215 * 216 * @see #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 217 * @see #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 218 * 219 * @see #setMovementGranularities(int) 220 * @see #getMovementGranularities() 221 * 222 * @see #MOVEMENT_GRANULARITY_CHARACTER 223 * @see #MOVEMENT_GRANULARITY_WORD 224 * @see #MOVEMENT_GRANULARITY_LINE 225 * @see #MOVEMENT_GRANULARITY_PARAGRAPH 226 * @see #MOVEMENT_GRANULARITY_PAGE 227 */ 228 public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 0x00000200; 229 230 /** 231 * Action to move to the next HTML element of a given type. For example, move 232 * to the BUTTON, INPUT, TABLE, etc. 233 * <p> 234 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 235 * <strong>Example:</strong> 236 * <code><pre><p> 237 * Bundle arguments = new Bundle(); 238 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 239 * info.performAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, arguments); 240 * </code></pre></p> 241 * </p> 242 */ 243 public static final int ACTION_NEXT_HTML_ELEMENT = 0x00000400; 244 245 /** 246 * Action to move to the previous HTML element of a given type. For example, move 247 * to the BUTTON, INPUT, TABLE, etc. 248 * <p> 249 * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 250 * <strong>Example:</strong> 251 * <code><pre><p> 252 * Bundle arguments = new Bundle(); 253 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 254 * info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, arguments); 255 * </code></pre></p> 256 * </p> 257 */ 258 public static final int ACTION_PREVIOUS_HTML_ELEMENT = 0x00000800; 259 260 /** 261 * Action to scroll the node content forward. 262 */ 263 public static final int ACTION_SCROLL_FORWARD = 0x00001000; 264 265 /** 266 * Action to scroll the node content backward. 267 */ 268 public static final int ACTION_SCROLL_BACKWARD = 0x00002000; 269 270 /** 271 * Action to copy the current selection to the clipboard. 272 */ 273 public static final int ACTION_COPY = 0x00004000; 274 275 /** 276 * Action to paste the current clipboard content. 277 */ 278 public static final int ACTION_PASTE = 0x00008000; 279 280 /** 281 * Action to cut the current selection and place it to the clipboard. 282 */ 283 public static final int ACTION_CUT = 0x00010000; 284 285 /** 286 * Action to set the selection. Performing this action with no arguments 287 * clears the selection. 288 * <p> 289 * <strong>Arguments:</strong> 290 * {@link #ACTION_ARGUMENT_SELECTION_START_INT}, 291 * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br> 292 * <strong>Example:</strong> 293 * <code><pre><p> 294 * Bundle arguments = new Bundle(); 295 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1); 296 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2); 297 * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments); 298 * </code></pre></p> 299 * </p> 300 * 301 * @see #ACTION_ARGUMENT_SELECTION_START_INT 302 * @see #ACTION_ARGUMENT_SELECTION_END_INT 303 */ 304 public static final int ACTION_SET_SELECTION = 0x00020000; 305 306 /** 307 * Action to expand an expandable node. 308 */ 309 public static final int ACTION_EXPAND = 0x00040000; 310 311 /** 312 * Action to collapse an expandable node. 313 */ 314 public static final int ACTION_COLLAPSE = 0x00080000; 315 316 /** 317 * Action to dismiss a dismissable node. 318 */ 319 public static final int ACTION_DISMISS = 0x00100000; 320 321 /** 322 * Action that sets the text of the node. Performing the action without argument, using <code> 323 * null</code> or empty {@link CharSequence} will clear the text. This action will also put the 324 * cursor at the end of text. 325 * <p> 326 * <strong>Arguments:</strong> 327 * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> 328 * <strong>Example:</strong> 329 * <code><pre><p> 330 * Bundle arguments = new Bundle(); 331 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, 332 * "android"); 333 * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 334 * </code></pre></p> 335 */ 336 public static final int ACTION_SET_TEXT = 0x00200000; 337 338 /** @hide */ 339 public static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT; 340 341 /** 342 * Mask to see if the value is larger than the largest ACTION_ constant 343 */ 344 private static final int ACTION_TYPE_MASK = 0xFF000000; 345 346 // Action arguments 347 348 /** 349 * Argument for which movement granularity to be used when traversing the node text. 350 * <p> 351 * <strong>Type:</strong> int<br> 352 * <strong>Actions:</strong> 353 * <ul> 354 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li> 355 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li> 356 * </ul> 357 * </p> 358 * 359 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 360 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 361 */ 362 public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = 363 "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; 364 365 /** 366 * Argument for which HTML element to get moving to the next/previous HTML element. 367 * <p> 368 * <strong>Type:</strong> String<br> 369 * <strong>Actions:</strong> 370 * <ul> 371 * <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li> 372 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li> 373 * </ul> 374 * </p> 375 * 376 * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT 377 * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT 378 */ 379 public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = 380 "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; 381 382 /** 383 * Argument for whether when moving at granularity to extend the selection 384 * or to move it otherwise. 385 * <p> 386 * <strong>Type:</strong> boolean<br> 387 * <strong>Actions:</strong> 388 * <ul> 389 * <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li> 390 * <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li> 391 * </ul> 392 * 393 * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 394 * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 395 */ 396 public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = 397 "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN"; 398 399 /** 400 * Argument for specifying the selection start. 401 * <p> 402 * <strong>Type:</strong> int<br> 403 * <strong>Actions:</strong> 404 * <ul> 405 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li> 406 * </ul> 407 * 408 * @see AccessibilityAction#ACTION_SET_SELECTION 409 */ 410 public static final String ACTION_ARGUMENT_SELECTION_START_INT = 411 "ACTION_ARGUMENT_SELECTION_START_INT"; 412 413 /** 414 * Argument for specifying the selection end. 415 * <p> 416 * <strong>Type:</strong> int<br> 417 * <strong>Actions:</strong> 418 * <ul> 419 * <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li> 420 * </ul> 421 * 422 * @see AccessibilityAction#ACTION_SET_SELECTION 423 */ 424 public static final String ACTION_ARGUMENT_SELECTION_END_INT = 425 "ACTION_ARGUMENT_SELECTION_END_INT"; 426 427 /** 428 * Argument for specifying the text content to set. 429 * <p> 430 * <strong>Type:</strong> CharSequence<br> 431 * <strong>Actions:</strong> 432 * <ul> 433 * <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li> 434 * </ul> 435 * 436 * @see AccessibilityAction#ACTION_SET_TEXT 437 */ 438 public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = 439 "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE"; 440 441 /** 442 * Argument for specifying the collection row to make visible on screen. 443 * <p> 444 * <strong>Type:</strong> int<br> 445 * <strong>Actions:</strong> 446 * <ul> 447 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li> 448 * </ul> 449 * 450 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION 451 */ 452 public static final String ACTION_ARGUMENT_ROW_INT = 453 "android.view.accessibility.action.ARGUMENT_ROW_INT"; 454 455 /** 456 * Argument for specifying the collection column to make visible on screen. 457 * <p> 458 * <strong>Type:</strong> int<br> 459 * <strong>Actions:</strong> 460 * <ul> 461 * <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li> 462 * </ul> 463 * 464 * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION 465 */ 466 public static final String ACTION_ARGUMENT_COLUMN_INT = 467 "android.view.accessibility.action.ARGUMENT_COLUMN_INT"; 468 469 /** 470 * Argument for specifying the progress value to set. 471 * <p> 472 * <strong>Type:</strong> float<br> 473 * <strong>Actions:</strong> 474 * <ul> 475 * <li>{@link AccessibilityAction#ACTION_SET_PROGRESS}</li> 476 * </ul> 477 * 478 * @see AccessibilityAction#ACTION_SET_PROGRESS 479 */ 480 public static final String ACTION_ARGUMENT_PROGRESS_VALUE = 481 "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE"; 482 483 /** 484 * Argument for specifying the x coordinate to which to move a window. 485 * <p> 486 * <strong>Type:</strong> int<br> 487 * <strong>Actions:</strong> 488 * <ul> 489 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li> 490 * </ul> 491 * 492 * @see AccessibilityAction#ACTION_MOVE_WINDOW 493 */ 494 public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = 495 "ACTION_ARGUMENT_MOVE_WINDOW_X"; 496 497 /** 498 * Argument for specifying the y coordinate to which to move a window. 499 * <p> 500 * <strong>Type:</strong> int<br> 501 * <strong>Actions:</strong> 502 * <ul> 503 * <li>{@link AccessibilityAction#ACTION_MOVE_WINDOW}</li> 504 * </ul> 505 * 506 * @see AccessibilityAction#ACTION_MOVE_WINDOW 507 */ 508 public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = 509 "ACTION_ARGUMENT_MOVE_WINDOW_Y"; 510 511 /** 512 * Argument to pass the {@link AccessibilityClickableSpan}. 513 * For use with R.id.accessibilityActionClickOnClickableSpan 514 * @hide 515 */ 516 public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN = 517 "android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN"; 518 519 // Focus types 520 521 /** 522 * The input focus. 523 */ 524 public static final int FOCUS_INPUT = 1; 525 526 /** 527 * The accessibility focus. 528 */ 529 public static final int FOCUS_ACCESSIBILITY = 2; 530 531 // Movement granularities 532 533 /** 534 * Movement granularity bit for traversing the text of a node by character. 535 */ 536 public static final int MOVEMENT_GRANULARITY_CHARACTER = 0x00000001; 537 538 /** 539 * Movement granularity bit for traversing the text of a node by word. 540 */ 541 public static final int MOVEMENT_GRANULARITY_WORD = 0x00000002; 542 543 /** 544 * Movement granularity bit for traversing the text of a node by line. 545 */ 546 public static final int MOVEMENT_GRANULARITY_LINE = 0x00000004; 547 548 /** 549 * Movement granularity bit for traversing the text of a node by paragraph. 550 */ 551 public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 0x00000008; 552 553 /** 554 * Movement granularity bit for traversing the text of a node by page. 555 */ 556 public static final int MOVEMENT_GRANULARITY_PAGE = 0x00000010; 557 558 /** 559 * Key used to request and locate extra data for text character location. This key requests that 560 * an array of {@link android.graphics.RectF}s be added to the extras. This request is made with 561 * {@link #refreshWithExtraData(String, Bundle)}. The arguments taken by this request are two 562 * integers: {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX} and 563 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH}. The starting index must be valid 564 * inside the CharSequence returned by {@link #getText()}, and the length must be positive. 565 * <p> 566 * The data can be retrieved from the {@code Bundle} returned by {@link #getExtras()} using this 567 * string as a key for {@link Bundle#getParcelableArray(String)}. The 568 * {@link android.graphics.RectF} will be null for characters that either do not exist or are 569 * off the screen. 570 * 571 * {@see #refreshWithExtraData(String, Bundle)} 572 */ 573 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = 574 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY"; 575 576 /** 577 * Integer argument specifying the start index of the requested text location data. Must be 578 * valid inside the CharSequence returned by {@link #getText()}. 579 * 580 * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} 581 */ 582 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = 583 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX"; 584 585 /** 586 * Integer argument specifying the end index of the requested text location data. Must be 587 * positive. 588 * 589 * {@see EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} 590 */ 591 public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = 592 "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; 593 594 /** @hide */ 595 public static final String EXTRA_DATA_REQUESTED_KEY = 596 "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested"; 597 598 // Boolean attributes. 599 600 private static final int BOOLEAN_PROPERTY_CHECKABLE = 0x00000001; 601 602 private static final int BOOLEAN_PROPERTY_CHECKED = 0x00000002; 603 604 private static final int BOOLEAN_PROPERTY_FOCUSABLE = 0x00000004; 605 606 private static final int BOOLEAN_PROPERTY_FOCUSED = 0x00000008; 607 608 private static final int BOOLEAN_PROPERTY_SELECTED = 0x00000010; 609 610 private static final int BOOLEAN_PROPERTY_CLICKABLE = 0x00000020; 611 612 private static final int BOOLEAN_PROPERTY_LONG_CLICKABLE = 0x00000040; 613 614 private static final int BOOLEAN_PROPERTY_ENABLED = 0x00000080; 615 616 private static final int BOOLEAN_PROPERTY_PASSWORD = 0x00000100; 617 618 private static final int BOOLEAN_PROPERTY_SCROLLABLE = 0x00000200; 619 620 private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 0x00000400; 621 622 private static final int BOOLEAN_PROPERTY_VISIBLE_TO_USER = 0x00000800; 623 624 private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000; 625 626 private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00002000; 627 628 private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00004000; 629 630 private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00008000; 631 632 private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00010000; 633 634 private static final int BOOLEAN_PROPERTY_CONTEXT_CLICKABLE = 0x00020000; 635 636 private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000; 637 638 private static final int BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE = 0x0080000; 639 640 private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000; 641 642 private static final int BOOLEAN_PROPERTY_IS_HEADING = 0x0200000; 643 644 /** 645 * Bits that provide the id of a virtual descendant of a view. 646 */ 647 private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L; 648 /** 649 * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a 650 * virtual descendant of a view. Such a descendant does not exist in the view 651 * hierarchy and is only reported via the accessibility APIs. 652 */ 653 private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32; 654 655 private static AtomicInteger sNumInstancesInUse; 656 657 /** 658 * Gets the accessibility view id which identifies a View in the view three. 659 * 660 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}. 661 * @return The accessibility view id part of the node id. 662 * 663 * @hide 664 */ 665 public static int getAccessibilityViewId(long accessibilityNodeId) { 666 return (int) accessibilityNodeId; 667 } 668 669 /** 670 * Gets the virtual descendant id which identifies an imaginary view in a 671 * containing View. 672 * 673 * @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}. 674 * @return The virtual view id part of the node id. 675 * 676 * @hide 677 */ 678 public static int getVirtualDescendantId(long accessibilityNodeId) { 679 return (int) ((accessibilityNodeId & VIRTUAL_DESCENDANT_ID_MASK) 680 >> VIRTUAL_DESCENDANT_ID_SHIFT); 681 } 682 683 /** 684 * Makes a node id by shifting the <code>virtualDescendantId</code> 685 * by {@link #VIRTUAL_DESCENDANT_ID_SHIFT} and taking 686 * the bitwise or with the <code>accessibilityViewId</code>. 687 * 688 * @param accessibilityViewId A View accessibility id. 689 * @param virtualDescendantId A virtual descendant id. 690 * @return The node id. 691 * 692 * @hide 693 */ 694 public static long makeNodeId(int accessibilityViewId, int virtualDescendantId) { 695 return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId; 696 } 697 698 // Housekeeping. 699 private static final int MAX_POOL_SIZE = 50; 700 private static final SynchronizedPool<AccessibilityNodeInfo> sPool = 701 new SynchronizedPool<>(MAX_POOL_SIZE); 702 703 private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo(); 704 705 private boolean mSealed; 706 707 // Data. 708 private int mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 709 private long mSourceNodeId = UNDEFINED_NODE_ID; 710 private long mParentNodeId = UNDEFINED_NODE_ID; 711 private long mLabelForId = UNDEFINED_NODE_ID; 712 private long mLabeledById = UNDEFINED_NODE_ID; 713 private long mTraversalBefore = UNDEFINED_NODE_ID; 714 private long mTraversalAfter = UNDEFINED_NODE_ID; 715 716 private int mBooleanProperties; 717 private final Rect mBoundsInParent = new Rect(); 718 private final Rect mBoundsInScreen = new Rect(); 719 private int mDrawingOrderInParent; 720 721 private CharSequence mPackageName; 722 private CharSequence mClassName; 723 // Hidden, unparceled value used to hold the original value passed to setText 724 private CharSequence mOriginalText; 725 private CharSequence mText; 726 private CharSequence mHintText; 727 private CharSequence mError; 728 private CharSequence mPaneTitle; 729 private CharSequence mContentDescription; 730 private CharSequence mTooltipText; 731 private String mViewIdResourceName; 732 private ArrayList<String> mExtraDataKeys; 733 734 private LongArray mChildNodeIds; 735 private ArrayList<AccessibilityAction> mActions; 736 737 private int mMaxTextLength = -1; 738 private int mMovementGranularities; 739 740 private int mTextSelectionStart = UNDEFINED_SELECTION_INDEX; 741 private int mTextSelectionEnd = UNDEFINED_SELECTION_INDEX; 742 private int mInputType = InputType.TYPE_NULL; 743 private int mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE; 744 745 private Bundle mExtras; 746 747 private int mConnectionId = UNDEFINED_CONNECTION_ID; 748 749 private RangeInfo mRangeInfo; 750 private CollectionInfo mCollectionInfo; 751 private CollectionItemInfo mCollectionItemInfo; 752 753 /** 754 * Hide constructor from clients. 755 */ 756 private AccessibilityNodeInfo() { 757 /* do nothing */ 758 } 759 760 /** 761 * Sets the source. 762 * <p> 763 * <strong>Note:</strong> Cannot be called from an 764 * {@link android.accessibilityservice.AccessibilityService}. 765 * This class is made immutable before being delivered to an AccessibilityService. 766 * </p> 767 * 768 * @param source The info source. 769 */ 770 public void setSource(View source) { 771 setSource(source, AccessibilityNodeProvider.HOST_VIEW_ID); 772 } 773 774 /** 775 * Sets the source to be a virtual descendant of the given <code>root</code>. 776 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root 777 * is set as the source. 778 * <p> 779 * A virtual descendant is an imaginary View that is reported as a part of the view 780 * hierarchy for accessibility purposes. This enables custom views that draw complex 781 * content to report themselves as a tree of virtual views, thus conveying their 782 * logical structure. 783 * </p> 784 * <p> 785 * <strong>Note:</strong> Cannot be called from an 786 * {@link android.accessibilityservice.AccessibilityService}. 787 * This class is made immutable before being delivered to an AccessibilityService. 788 * </p> 789 * 790 * @param root The root of the virtual subtree. 791 * @param virtualDescendantId The id of the virtual descendant. 792 */ 793 public void setSource(View root, int virtualDescendantId) { 794 enforceNotSealed(); 795 mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID; 796 final int rootAccessibilityViewId = 797 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 798 mSourceNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 799 } 800 801 /** 802 * Find the view that has the specified focus type. The search starts from 803 * the view represented by this node info. 804 * 805 * @param focus The focus to find. One of {@link #FOCUS_INPUT} or 806 * {@link #FOCUS_ACCESSIBILITY}. 807 * @return The node info of the focused view or null. 808 * 809 * @see #FOCUS_INPUT 810 * @see #FOCUS_ACCESSIBILITY 811 */ 812 public AccessibilityNodeInfo findFocus(int focus) { 813 enforceSealed(); 814 enforceValidFocusType(focus); 815 if (!canPerformRequestOverConnection(mSourceNodeId)) { 816 return null; 817 } 818 return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId, 819 mSourceNodeId, focus); 820 } 821 822 /** 823 * Searches for the nearest view in the specified direction that can take 824 * the input focus. 825 * 826 * @param direction The direction. Can be one of: 827 * {@link View#FOCUS_DOWN}, 828 * {@link View#FOCUS_UP}, 829 * {@link View#FOCUS_LEFT}, 830 * {@link View#FOCUS_RIGHT}, 831 * {@link View#FOCUS_FORWARD}, 832 * {@link View#FOCUS_BACKWARD}. 833 * 834 * @return The node info for the view that can take accessibility focus. 835 */ 836 public AccessibilityNodeInfo focusSearch(int direction) { 837 enforceSealed(); 838 enforceValidFocusDirection(direction); 839 if (!canPerformRequestOverConnection(mSourceNodeId)) { 840 return null; 841 } 842 return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId, 843 mSourceNodeId, direction); 844 } 845 846 /** 847 * Gets the id of the window from which the info comes from. 848 * 849 * @return The window id. 850 */ 851 public int getWindowId() { 852 return mWindowId; 853 } 854 855 /** 856 * Refreshes this info with the latest state of the view it represents. 857 * <p> 858 * <strong>Note:</strong> If this method returns false this info is obsolete 859 * since it represents a view that is no longer in the view tree and should 860 * be recycled. 861 * </p> 862 * 863 * @param bypassCache Whether to bypass the cache. 864 * @return Whether the refresh succeeded. 865 * 866 * @hide 867 */ 868 public boolean refresh(Bundle arguments, boolean bypassCache) { 869 enforceSealed(); 870 if (!canPerformRequestOverConnection(mSourceNodeId)) { 871 return false; 872 } 873 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 874 AccessibilityNodeInfo refreshedInfo = client.findAccessibilityNodeInfoByAccessibilityId( 875 mConnectionId, mWindowId, mSourceNodeId, bypassCache, 0, arguments); 876 if (refreshedInfo == null) { 877 return false; 878 } 879 // Hard-to-reproduce bugs seem to be due to some tools recycling a node on another 880 // thread. If that happens, the init will re-seal the node, which then is in a bad state 881 // when it is obtained. Enforce sealing again before we init to fail when a node has been 882 // recycled during a refresh to catch such errors earlier. 883 enforceSealed(); 884 init(refreshedInfo); 885 refreshedInfo.recycle(); 886 return true; 887 } 888 889 /** 890 * Refreshes this info with the latest state of the view it represents. 891 * 892 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented 893 * by this node is no longer in the view tree (and thus this node is obsolete and should be 894 * recycled). 895 */ 896 public boolean refresh() { 897 return refresh(null, true); 898 } 899 900 /** 901 * Refreshes this info with the latest state of the view it represents, and request new 902 * data be added by the View. 903 * 904 * @param extraDataKey A bitmask of the extra data requested. Data that must be requested 905 * with this mechanism is generally expensive to retrieve, so should only be 906 * requested when needed. See 907 * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and 908 * {@link #getAvailableExtraData()}. 909 * @param args A bundle of arguments for the request. These depend on the particular request. 910 * 911 * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented 912 * by this node is no longer in the view tree (and thus this node is obsolete and should be 913 * recycled). 914 */ 915 public boolean refreshWithExtraData(String extraDataKey, Bundle args) { 916 args.putString(EXTRA_DATA_REQUESTED_KEY, extraDataKey); 917 return refresh(args, true); 918 } 919 920 /** 921 * Returns the array containing the IDs of this node's children. 922 * 923 * @hide 924 */ 925 public LongArray getChildNodeIds() { 926 return mChildNodeIds; 927 } 928 929 /** 930 * Returns the id of the child at the specified index. 931 * 932 * @throws IndexOutOfBoundsException when index < 0 || index >= 933 * getChildCount() 934 * @hide 935 */ 936 public long getChildId(int index) { 937 if (mChildNodeIds == null) { 938 throw new IndexOutOfBoundsException(); 939 } 940 return mChildNodeIds.get(index); 941 } 942 943 /** 944 * Gets the number of children. 945 * 946 * @return The child count. 947 */ 948 public int getChildCount() { 949 return mChildNodeIds == null ? 0 : mChildNodeIds.size(); 950 } 951 952 /** 953 * Get the child at given index. 954 * <p> 955 * <strong>Note:</strong> It is a client responsibility to recycle the 956 * received info by calling {@link AccessibilityNodeInfo#recycle()} 957 * to avoid creating of multiple instances. 958 * </p> 959 * 960 * @param index The child index. 961 * @return The child node. 962 * 963 * @throws IllegalStateException If called outside of an AccessibilityService. 964 * 965 */ 966 public AccessibilityNodeInfo getChild(int index) { 967 enforceSealed(); 968 if (mChildNodeIds == null) { 969 return null; 970 } 971 if (!canPerformRequestOverConnection(mSourceNodeId)) { 972 return null; 973 } 974 final long childId = mChildNodeIds.get(index); 975 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 976 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mWindowId, 977 childId, false, FLAG_PREFETCH_DESCENDANTS, null); 978 } 979 980 /** 981 * Adds a child. 982 * <p> 983 * <strong>Note:</strong> Cannot be called from an 984 * {@link android.accessibilityservice.AccessibilityService}. 985 * This class is made immutable before being delivered to an AccessibilityService. 986 * </p> 987 * 988 * @param child The child. 989 * 990 * @throws IllegalStateException If called from an AccessibilityService. 991 */ 992 public void addChild(View child) { 993 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, true); 994 } 995 996 /** 997 * Unchecked version of {@link #addChild(View)} that does not verify 998 * uniqueness. For framework use only. 999 * 1000 * @hide 1001 */ 1002 public void addChildUnchecked(View child) { 1003 addChildInternal(child, AccessibilityNodeProvider.HOST_VIEW_ID, false); 1004 } 1005 1006 /** 1007 * Removes a child. If the child was not previously added to the node, 1008 * calling this method has no effect. 1009 * <p> 1010 * <strong>Note:</strong> Cannot be called from an 1011 * {@link android.accessibilityservice.AccessibilityService}. 1012 * This class is made immutable before being delivered to an AccessibilityService. 1013 * </p> 1014 * 1015 * @param child The child. 1016 * @return true if the child was present 1017 * 1018 * @throws IllegalStateException If called from an AccessibilityService. 1019 */ 1020 public boolean removeChild(View child) { 1021 return removeChild(child, AccessibilityNodeProvider.HOST_VIEW_ID); 1022 } 1023 1024 /** 1025 * Adds a virtual child which is a descendant of the given <code>root</code>. 1026 * If <code>virtualDescendantId</code> is {@link View#NO_ID} the root 1027 * is added as a child. 1028 * <p> 1029 * A virtual descendant is an imaginary View that is reported as a part of the view 1030 * hierarchy for accessibility purposes. This enables custom views that draw complex 1031 * content to report them selves as a tree of virtual views, thus conveying their 1032 * logical structure. 1033 * </p> 1034 * 1035 * @param root The root of the virtual subtree. 1036 * @param virtualDescendantId The id of the virtual child. 1037 */ 1038 public void addChild(View root, int virtualDescendantId) { 1039 addChildInternal(root, virtualDescendantId, true); 1040 } 1041 1042 private void addChildInternal(View root, int virtualDescendantId, boolean checked) { 1043 enforceNotSealed(); 1044 if (mChildNodeIds == null) { 1045 mChildNodeIds = new LongArray(); 1046 } 1047 final int rootAccessibilityViewId = 1048 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1049 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1050 // If we're checking uniqueness and the ID already exists, abort. 1051 if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) { 1052 return; 1053 } 1054 mChildNodeIds.add(childNodeId); 1055 } 1056 1057 /** 1058 * Removes a virtual child which is a descendant of the given 1059 * <code>root</code>. If the child was not previously added to the node, 1060 * calling this method has no effect. 1061 * 1062 * @param root The root of the virtual subtree. 1063 * @param virtualDescendantId The id of the virtual child. 1064 * @return true if the child was present 1065 * @see #addChild(View, int) 1066 */ 1067 public boolean removeChild(View root, int virtualDescendantId) { 1068 enforceNotSealed(); 1069 final LongArray childIds = mChildNodeIds; 1070 if (childIds == null) { 1071 return false; 1072 } 1073 final int rootAccessibilityViewId = 1074 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1075 final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1076 final int index = childIds.indexOf(childNodeId); 1077 if (index < 0) { 1078 return false; 1079 } 1080 childIds.remove(index); 1081 return true; 1082 } 1083 1084 /** 1085 * Gets the actions that can be performed on the node. 1086 */ 1087 public List<AccessibilityAction> getActionList() { 1088 return CollectionUtils.emptyIfNull(mActions); 1089 } 1090 1091 /** 1092 * Gets the actions that can be performed on the node. 1093 * 1094 * @return The bit mask of with actions. 1095 * 1096 * @see AccessibilityNodeInfo#ACTION_FOCUS 1097 * @see AccessibilityNodeInfo#ACTION_CLEAR_FOCUS 1098 * @see AccessibilityNodeInfo#ACTION_SELECT 1099 * @see AccessibilityNodeInfo#ACTION_CLEAR_SELECTION 1100 * @see AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS 1101 * @see AccessibilityNodeInfo#ACTION_CLEAR_ACCESSIBILITY_FOCUS 1102 * @see AccessibilityNodeInfo#ACTION_CLICK 1103 * @see AccessibilityNodeInfo#ACTION_LONG_CLICK 1104 * @see AccessibilityNodeInfo#ACTION_NEXT_AT_MOVEMENT_GRANULARITY 1105 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 1106 * @see AccessibilityNodeInfo#ACTION_NEXT_HTML_ELEMENT 1107 * @see AccessibilityNodeInfo#ACTION_PREVIOUS_HTML_ELEMENT 1108 * @see AccessibilityNodeInfo#ACTION_SCROLL_FORWARD 1109 * @see AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD 1110 * 1111 * @deprecated Use {@link #getActionList()}. 1112 */ 1113 @Deprecated 1114 public int getActions() { 1115 int returnValue = 0; 1116 1117 if (mActions == null) { 1118 return returnValue; 1119 } 1120 1121 final int actionSize = mActions.size(); 1122 for (int i = 0; i < actionSize; i++) { 1123 int actionId = mActions.get(i).getId(); 1124 if (actionId <= LAST_LEGACY_STANDARD_ACTION) { 1125 returnValue |= actionId; 1126 } 1127 } 1128 1129 return returnValue; 1130 } 1131 1132 /** 1133 * Adds an action that can be performed on the node. 1134 * <p> 1135 * To add a standard action use the static constants on {@link AccessibilityAction}. 1136 * To add a custom action create a new {@link AccessibilityAction} by passing in a 1137 * resource id from your application as the action id and an optional label that 1138 * describes the action. To override one of the standard actions use as the action 1139 * id of a standard action id such as {@link #ACTION_CLICK} and an optional label that 1140 * describes the action. 1141 * </p> 1142 * <p> 1143 * <strong>Note:</strong> Cannot be called from an 1144 * {@link android.accessibilityservice.AccessibilityService}. 1145 * This class is made immutable before being delivered to an AccessibilityService. 1146 * </p> 1147 * 1148 * @param action The action. 1149 * 1150 * @throws IllegalStateException If called from an AccessibilityService. 1151 */ 1152 public void addAction(AccessibilityAction action) { 1153 enforceNotSealed(); 1154 1155 addActionUnchecked(action); 1156 } 1157 1158 private void addActionUnchecked(AccessibilityAction action) { 1159 if (action == null) { 1160 return; 1161 } 1162 1163 if (mActions == null) { 1164 mActions = new ArrayList<>(); 1165 } 1166 1167 mActions.remove(action); 1168 mActions.add(action); 1169 } 1170 1171 /** 1172 * Adds an action that can be performed on the node. 1173 * <p> 1174 * <strong>Note:</strong> Cannot be called from an 1175 * {@link android.accessibilityservice.AccessibilityService}. 1176 * This class is made immutable before being delivered to an AccessibilityService. 1177 * </p> 1178 * 1179 * @param action The action. 1180 * 1181 * @throws IllegalStateException If called from an AccessibilityService. 1182 * @throws IllegalArgumentException If the argument is not one of the standard actions. 1183 * 1184 * @deprecated This has been deprecated for {@link #addAction(AccessibilityAction)} 1185 */ 1186 @Deprecated 1187 public void addAction(int action) { 1188 enforceNotSealed(); 1189 1190 if ((action & ACTION_TYPE_MASK) != 0) { 1191 throw new IllegalArgumentException("Action is not a combination of the standard " + 1192 "actions: " + action); 1193 } 1194 1195 addStandardActions(action); 1196 } 1197 1198 /** 1199 * Removes an action that can be performed on the node. If the action was 1200 * not already added to the node, calling this method has no effect. 1201 * <p> 1202 * <strong>Note:</strong> Cannot be called from an 1203 * {@link android.accessibilityservice.AccessibilityService}. 1204 * This class is made immutable before being delivered to an AccessibilityService. 1205 * </p> 1206 * 1207 * @param action The action to be removed. 1208 * 1209 * @throws IllegalStateException If called from an AccessibilityService. 1210 * @deprecated Use {@link #removeAction(AccessibilityAction)} 1211 */ 1212 @Deprecated 1213 public void removeAction(int action) { 1214 enforceNotSealed(); 1215 1216 removeAction(getActionSingleton(action)); 1217 } 1218 1219 /** 1220 * Removes an action that can be performed on the node. If the action was 1221 * not already added to the node, calling this method has no effect. 1222 * <p> 1223 * <strong>Note:</strong> Cannot be called from an 1224 * {@link android.accessibilityservice.AccessibilityService}. 1225 * This class is made immutable before being delivered to an AccessibilityService. 1226 * </p> 1227 * 1228 * @param action The action to be removed. 1229 * @return The action removed from the list of actions. 1230 * 1231 * @throws IllegalStateException If called from an AccessibilityService. 1232 */ 1233 public boolean removeAction(AccessibilityAction action) { 1234 enforceNotSealed(); 1235 1236 if (mActions == null || action == null) { 1237 return false; 1238 } 1239 1240 return mActions.remove(action); 1241 } 1242 1243 /** 1244 * Removes all actions. 1245 * 1246 * @hide 1247 */ 1248 public void removeAllActions() { 1249 if (mActions != null) { 1250 mActions.clear(); 1251 } 1252 } 1253 1254 /** 1255 * Gets the node before which this one is visited during traversal. A screen-reader 1256 * must visit the content of this node before the content of the one it precedes. 1257 * 1258 * @return The succeeding node if such or <code>null</code>. 1259 * 1260 * @see #setTraversalBefore(android.view.View) 1261 * @see #setTraversalBefore(android.view.View, int) 1262 */ 1263 public AccessibilityNodeInfo getTraversalBefore() { 1264 enforceSealed(); 1265 return getNodeForAccessibilityId(mTraversalBefore); 1266 } 1267 1268 /** 1269 * Sets the view before whose node this one should be visited during traversal. A 1270 * screen-reader must visit the content of this node before the content of the one 1271 * it precedes. 1272 * <p> 1273 * <strong>Note:</strong> Cannot be called from an 1274 * {@link android.accessibilityservice.AccessibilityService}. 1275 * This class is made immutable before being delivered to an AccessibilityService. 1276 * </p> 1277 * 1278 * @param view The view providing the preceding node. 1279 * 1280 * @see #getTraversalBefore() 1281 */ 1282 public void setTraversalBefore(View view) { 1283 setTraversalBefore(view, AccessibilityNodeProvider.HOST_VIEW_ID); 1284 } 1285 1286 /** 1287 * Sets the node before which this one is visited during traversal. A screen-reader 1288 * must visit the content of this node before the content of the one it precedes. 1289 * The successor is a virtual descendant of the given <code>root</code>. If 1290 * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set 1291 * as the successor. 1292 * <p> 1293 * A virtual descendant is an imaginary View that is reported as a part of the view 1294 * hierarchy for accessibility purposes. This enables custom views that draw complex 1295 * content to report them selves as a tree of virtual views, thus conveying their 1296 * logical structure. 1297 * </p> 1298 * <p> 1299 * <strong>Note:</strong> Cannot be called from an 1300 * {@link android.accessibilityservice.AccessibilityService}. 1301 * This class is made immutable before being delivered to an AccessibilityService. 1302 * </p> 1303 * 1304 * @param root The root of the virtual subtree. 1305 * @param virtualDescendantId The id of the virtual descendant. 1306 */ 1307 public void setTraversalBefore(View root, int virtualDescendantId) { 1308 enforceNotSealed(); 1309 final int rootAccessibilityViewId = (root != null) 1310 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1311 mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1312 } 1313 1314 /** 1315 * Gets the node after which this one is visited in accessibility traversal. 1316 * A screen-reader must visit the content of the other node before the content 1317 * of this one. 1318 * 1319 * @return The succeeding node if such or <code>null</code>. 1320 * 1321 * @see #setTraversalAfter(android.view.View) 1322 * @see #setTraversalAfter(android.view.View, int) 1323 */ 1324 public AccessibilityNodeInfo getTraversalAfter() { 1325 enforceSealed(); 1326 return getNodeForAccessibilityId(mTraversalAfter); 1327 } 1328 1329 /** 1330 * Sets the view whose node is visited after this one in accessibility traversal. 1331 * A screen-reader must visit the content of the other node before the content 1332 * of this one. 1333 * <p> 1334 * <strong>Note:</strong> Cannot be called from an 1335 * {@link android.accessibilityservice.AccessibilityService}. 1336 * This class is made immutable before being delivered to an AccessibilityService. 1337 * </p> 1338 * 1339 * @param view The previous view. 1340 * 1341 * @see #getTraversalAfter() 1342 */ 1343 public void setTraversalAfter(View view) { 1344 setTraversalAfter(view, AccessibilityNodeProvider.HOST_VIEW_ID); 1345 } 1346 1347 /** 1348 * Sets the node after which this one is visited in accessibility traversal. 1349 * A screen-reader must visit the content of the other node before the content 1350 * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID} 1351 * the root is set as the predecessor. 1352 * <p> 1353 * A virtual descendant is an imaginary View that is reported as a part of the view 1354 * hierarchy for accessibility purposes. This enables custom views that draw complex 1355 * content to report them selves as a tree of virtual views, thus conveying their 1356 * logical structure. 1357 * </p> 1358 * <p> 1359 * <strong>Note:</strong> Cannot be called from an 1360 * {@link android.accessibilityservice.AccessibilityService}. 1361 * This class is made immutable before being delivered to an AccessibilityService. 1362 * </p> 1363 * 1364 * @param root The root of the virtual subtree. 1365 * @param virtualDescendantId The id of the virtual descendant. 1366 */ 1367 public void setTraversalAfter(View root, int virtualDescendantId) { 1368 enforceNotSealed(); 1369 final int rootAccessibilityViewId = (root != null) 1370 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1371 mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1372 } 1373 1374 /** 1375 * Get the extra data available for this node. 1376 * <p> 1377 * Some data that is useful for some accessibility services is expensive to compute, and would 1378 * place undue overhead on apps to compute all the time. That data can be requested with 1379 * {@link #refreshWithExtraData(String, Bundle)}. 1380 * 1381 * @return An unmodifiable list of keys corresponding to extra data that can be requested. 1382 * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY 1383 */ 1384 public List<String> getAvailableExtraData() { 1385 if (mExtraDataKeys != null) { 1386 return Collections.unmodifiableList(mExtraDataKeys); 1387 } else { 1388 return EMPTY_LIST; 1389 } 1390 } 1391 1392 /** 1393 * Set the extra data available for this node. 1394 * <p> 1395 * <strong>Note:</strong> When a {@code View} passes in a non-empty list, it promises that 1396 * it will populate the node's extras with corresponding pieces of information in 1397 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle)}. 1398 * <p> 1399 * <strong>Note:</strong> Cannot be called from an 1400 * {@link android.accessibilityservice.AccessibilityService}. 1401 * This class is made immutable before being delivered to an AccessibilityService. 1402 * 1403 * @param extraDataKeys A list of types of extra data that are available. 1404 * @see #getAvailableExtraData() 1405 * 1406 * @throws IllegalStateException If called from an AccessibilityService. 1407 */ 1408 public void setAvailableExtraData(List<String> extraDataKeys) { 1409 enforceNotSealed(); 1410 mExtraDataKeys = new ArrayList<>(extraDataKeys); 1411 } 1412 1413 /** 1414 * Sets the maximum text length, or -1 for no limit. 1415 * <p> 1416 * Typically used to indicate that an editable text field has a limit on 1417 * the number of characters entered. 1418 * <p> 1419 * <strong>Note:</strong> Cannot be called from an 1420 * {@link android.accessibilityservice.AccessibilityService}. 1421 * This class is made immutable before being delivered to an AccessibilityService. 1422 * 1423 * @param max The maximum text length. 1424 * @see #getMaxTextLength() 1425 * 1426 * @throws IllegalStateException If called from an AccessibilityService. 1427 */ 1428 public void setMaxTextLength(int max) { 1429 enforceNotSealed(); 1430 mMaxTextLength = max; 1431 } 1432 1433 /** 1434 * Returns the maximum text length for this node. 1435 * 1436 * @return The maximum text length, or -1 for no limit. 1437 * @see #setMaxTextLength(int) 1438 */ 1439 public int getMaxTextLength() { 1440 return mMaxTextLength; 1441 } 1442 1443 /** 1444 * Sets the movement granularities for traversing the text of this node. 1445 * <p> 1446 * <strong>Note:</strong> Cannot be called from an 1447 * {@link android.accessibilityservice.AccessibilityService}. 1448 * This class is made immutable before being delivered to an AccessibilityService. 1449 * </p> 1450 * 1451 * @param granularities The bit mask with granularities. 1452 * 1453 * @throws IllegalStateException If called from an AccessibilityService. 1454 */ 1455 public void setMovementGranularities(int granularities) { 1456 enforceNotSealed(); 1457 mMovementGranularities = granularities; 1458 } 1459 1460 /** 1461 * Gets the movement granularities for traversing the text of this node. 1462 * 1463 * @return The bit mask with granularities. 1464 */ 1465 public int getMovementGranularities() { 1466 return mMovementGranularities; 1467 } 1468 1469 /** 1470 * Performs an action on the node. 1471 * <p> 1472 * <strong>Note:</strong> An action can be performed only if the request is made 1473 * from an {@link android.accessibilityservice.AccessibilityService}. 1474 * </p> 1475 * 1476 * @param action The action to perform. 1477 * @return True if the action was performed. 1478 * 1479 * @throws IllegalStateException If called outside of an AccessibilityService. 1480 */ 1481 public boolean performAction(int action) { 1482 enforceSealed(); 1483 if (!canPerformRequestOverConnection(mSourceNodeId)) { 1484 return false; 1485 } 1486 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1487 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId, 1488 action, null); 1489 } 1490 1491 /** 1492 * Performs an action on the node. 1493 * <p> 1494 * <strong>Note:</strong> An action can be performed only if the request is made 1495 * from an {@link android.accessibilityservice.AccessibilityService}. 1496 * </p> 1497 * 1498 * @param action The action to perform. 1499 * @param arguments A bundle with additional arguments. 1500 * @return True if the action was performed. 1501 * 1502 * @throws IllegalStateException If called outside of an AccessibilityService. 1503 */ 1504 public boolean performAction(int action, Bundle arguments) { 1505 enforceSealed(); 1506 if (!canPerformRequestOverConnection(mSourceNodeId)) { 1507 return false; 1508 } 1509 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1510 return client.performAccessibilityAction(mConnectionId, mWindowId, mSourceNodeId, 1511 action, arguments); 1512 } 1513 1514 /** 1515 * Finds {@link AccessibilityNodeInfo}s by text. The match is case 1516 * insensitive containment. The search is relative to this info i.e. 1517 * this info is the root of the traversed tree. 1518 * 1519 * <p> 1520 * <strong>Note:</strong> It is a client responsibility to recycle the 1521 * received info by calling {@link AccessibilityNodeInfo#recycle()} 1522 * to avoid creating of multiple instances. 1523 * </p> 1524 * 1525 * @param text The searched text. 1526 * @return A list of node info. 1527 */ 1528 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) { 1529 enforceSealed(); 1530 if (!canPerformRequestOverConnection(mSourceNodeId)) { 1531 return Collections.emptyList(); 1532 } 1533 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1534 return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId, 1535 text); 1536 } 1537 1538 /** 1539 * Finds {@link AccessibilityNodeInfo}s by the fully qualified view id's resource 1540 * name where a fully qualified id is of the from "package:id/id_resource_name". 1541 * For example, if the target application's package is "foo.bar" and the id 1542 * resource name is "baz", the fully qualified resource id is "foo.bar:id/baz". 1543 * 1544 * <p> 1545 * <strong>Note:</strong> It is a client responsibility to recycle the 1546 * received info by calling {@link AccessibilityNodeInfo#recycle()} 1547 * to avoid creating of multiple instances. 1548 * </p> 1549 * <p> 1550 * <strong>Note:</strong> The primary usage of this API is for UI test automation 1551 * and in order to report the fully qualified view id if an {@link AccessibilityNodeInfo} 1552 * the client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} 1553 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}. 1554 * </p> 1555 * 1556 * @param viewId The fully qualified resource name of the view id to find. 1557 * @return A list of node info. 1558 */ 1559 public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) { 1560 enforceSealed(); 1561 if (!canPerformRequestOverConnection(mSourceNodeId)) { 1562 return Collections.emptyList(); 1563 } 1564 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1565 return client.findAccessibilityNodeInfosByViewId(mConnectionId, mWindowId, mSourceNodeId, 1566 viewId); 1567 } 1568 1569 /** 1570 * Gets the window to which this node belongs. 1571 * 1572 * @return The window. 1573 * 1574 * @see android.accessibilityservice.AccessibilityService#getWindows() 1575 */ 1576 public AccessibilityWindowInfo getWindow() { 1577 enforceSealed(); 1578 if (!canPerformRequestOverConnection(mSourceNodeId)) { 1579 return null; 1580 } 1581 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 1582 return client.getWindow(mConnectionId, mWindowId); 1583 } 1584 1585 /** 1586 * Gets the parent. 1587 * <p> 1588 * <strong>Note:</strong> It is a client responsibility to recycle the 1589 * received info by calling {@link AccessibilityNodeInfo#recycle()} 1590 * to avoid creating of multiple instances. 1591 * </p> 1592 * 1593 * @return The parent. 1594 */ 1595 public AccessibilityNodeInfo getParent() { 1596 enforceSealed(); 1597 return getNodeForAccessibilityId(mParentNodeId); 1598 } 1599 1600 /** 1601 * @return The parent node id. 1602 * 1603 * @hide 1604 */ 1605 public long getParentNodeId() { 1606 return mParentNodeId; 1607 } 1608 1609 /** 1610 * Sets the parent. 1611 * <p> 1612 * <strong>Note:</strong> Cannot be called from an 1613 * {@link android.accessibilityservice.AccessibilityService}. 1614 * This class is made immutable before being delivered to an AccessibilityService. 1615 * </p> 1616 * 1617 * @param parent The parent. 1618 * 1619 * @throws IllegalStateException If called from an AccessibilityService. 1620 */ 1621 public void setParent(View parent) { 1622 setParent(parent, AccessibilityNodeProvider.HOST_VIEW_ID); 1623 } 1624 1625 /** 1626 * Sets the parent to be a virtual descendant of the given <code>root</code>. 1627 * If <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root 1628 * is set as the parent. 1629 * <p> 1630 * A virtual descendant is an imaginary View that is reported as a part of the view 1631 * hierarchy for accessibility purposes. This enables custom views that draw complex 1632 * content to report them selves as a tree of virtual views, thus conveying their 1633 * logical structure. 1634 * </p> 1635 * <p> 1636 * <strong>Note:</strong> Cannot be called from an 1637 * {@link android.accessibilityservice.AccessibilityService}. 1638 * This class is made immutable before being delivered to an AccessibilityService. 1639 * </p> 1640 * 1641 * @param root The root of the virtual subtree. 1642 * @param virtualDescendantId The id of the virtual descendant. 1643 */ 1644 public void setParent(View root, int virtualDescendantId) { 1645 enforceNotSealed(); 1646 final int rootAccessibilityViewId = 1647 (root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 1648 mParentNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 1649 } 1650 1651 /** 1652 * Gets the node bounds in parent coordinates. 1653 * 1654 * @param outBounds The output node bounds. 1655 */ 1656 public void getBoundsInParent(Rect outBounds) { 1657 outBounds.set(mBoundsInParent.left, mBoundsInParent.top, 1658 mBoundsInParent.right, mBoundsInParent.bottom); 1659 } 1660 1661 /** 1662 * Sets the node bounds in parent coordinates. 1663 * <p> 1664 * <strong>Note:</strong> Cannot be called from an 1665 * {@link android.accessibilityservice.AccessibilityService}. 1666 * This class is made immutable before being delivered to an AccessibilityService. 1667 * </p> 1668 * 1669 * @param bounds The node bounds. 1670 * 1671 * @throws IllegalStateException If called from an AccessibilityService. 1672 */ 1673 public void setBoundsInParent(Rect bounds) { 1674 enforceNotSealed(); 1675 mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom); 1676 } 1677 1678 /** 1679 * Gets the node bounds in screen coordinates. 1680 * 1681 * @param outBounds The output node bounds. 1682 */ 1683 public void getBoundsInScreen(Rect outBounds) { 1684 outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top, 1685 mBoundsInScreen.right, mBoundsInScreen.bottom); 1686 } 1687 1688 /** 1689 * Returns the actual rect containing the node bounds in screen coordinates. 1690 * 1691 * @hide Not safe to expose outside the framework. 1692 */ 1693 public Rect getBoundsInScreen() { 1694 return mBoundsInScreen; 1695 } 1696 1697 /** 1698 * Sets the node bounds in screen coordinates. 1699 * <p> 1700 * <strong>Note:</strong> Cannot be called from an 1701 * {@link android.accessibilityservice.AccessibilityService}. 1702 * This class is made immutable before being delivered to an AccessibilityService. 1703 * </p> 1704 * 1705 * @param bounds The node bounds. 1706 * 1707 * @throws IllegalStateException If called from an AccessibilityService. 1708 */ 1709 public void setBoundsInScreen(Rect bounds) { 1710 enforceNotSealed(); 1711 mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom); 1712 } 1713 1714 /** 1715 * Gets whether this node is checkable. 1716 * 1717 * @return True if the node is checkable. 1718 */ 1719 public boolean isCheckable() { 1720 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE); 1721 } 1722 1723 /** 1724 * Sets whether this node is checkable. 1725 * <p> 1726 * <strong>Note:</strong> Cannot be called from an 1727 * {@link android.accessibilityservice.AccessibilityService}. 1728 * This class is made immutable before being delivered to an AccessibilityService. 1729 * </p> 1730 * 1731 * @param checkable True if the node is checkable. 1732 * 1733 * @throws IllegalStateException If called from an AccessibilityService. 1734 */ 1735 public void setCheckable(boolean checkable) { 1736 setBooleanProperty(BOOLEAN_PROPERTY_CHECKABLE, checkable); 1737 } 1738 1739 /** 1740 * Gets whether this node is checked. 1741 * 1742 * @return True if the node is checked. 1743 */ 1744 public boolean isChecked() { 1745 return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED); 1746 } 1747 1748 /** 1749 * Sets whether this node is checked. 1750 * <p> 1751 * <strong>Note:</strong> Cannot be called from an 1752 * {@link android.accessibilityservice.AccessibilityService}. 1753 * This class is made immutable before being delivered to an AccessibilityService. 1754 * </p> 1755 * 1756 * @param checked True if the node is checked. 1757 * 1758 * @throws IllegalStateException If called from an AccessibilityService. 1759 */ 1760 public void setChecked(boolean checked) { 1761 setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked); 1762 } 1763 1764 /** 1765 * Gets whether this node is focusable. 1766 * 1767 * @return True if the node is focusable. 1768 */ 1769 public boolean isFocusable() { 1770 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE); 1771 } 1772 1773 /** 1774 * Sets whether this node is focusable. 1775 * <p> 1776 * <strong>Note:</strong> Cannot be called from an 1777 * {@link android.accessibilityservice.AccessibilityService}. 1778 * This class is made immutable before being delivered to an AccessibilityService. 1779 * </p> 1780 * 1781 * @param focusable True if the node is focusable. 1782 * 1783 * @throws IllegalStateException If called from an AccessibilityService. 1784 */ 1785 public void setFocusable(boolean focusable) { 1786 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSABLE, focusable); 1787 } 1788 1789 /** 1790 * Gets whether this node is focused. 1791 * 1792 * @return True if the node is focused. 1793 */ 1794 public boolean isFocused() { 1795 return getBooleanProperty(BOOLEAN_PROPERTY_FOCUSED); 1796 } 1797 1798 /** 1799 * Sets whether this node is focused. 1800 * <p> 1801 * <strong>Note:</strong> Cannot be called from an 1802 * {@link android.accessibilityservice.AccessibilityService}. 1803 * This class is made immutable before being delivered to an AccessibilityService. 1804 * </p> 1805 * 1806 * @param focused True if the node is focused. 1807 * 1808 * @throws IllegalStateException If called from an AccessibilityService. 1809 */ 1810 public void setFocused(boolean focused) { 1811 setBooleanProperty(BOOLEAN_PROPERTY_FOCUSED, focused); 1812 } 1813 1814 /** 1815 * Gets whether this node is visible to the user. 1816 * 1817 * @return Whether the node is visible to the user. 1818 */ 1819 public boolean isVisibleToUser() { 1820 return getBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER); 1821 } 1822 1823 /** 1824 * Sets whether this node is visible to the user. 1825 * <p> 1826 * <strong>Note:</strong> Cannot be called from an 1827 * {@link android.accessibilityservice.AccessibilityService}. 1828 * This class is made immutable before being delivered to an AccessibilityService. 1829 * </p> 1830 * 1831 * @param visibleToUser Whether the node is visible to the user. 1832 * 1833 * @throws IllegalStateException If called from an AccessibilityService. 1834 */ 1835 public void setVisibleToUser(boolean visibleToUser) { 1836 setBooleanProperty(BOOLEAN_PROPERTY_VISIBLE_TO_USER, visibleToUser); 1837 } 1838 1839 /** 1840 * Gets whether this node is accessibility focused. 1841 * 1842 * @return True if the node is accessibility focused. 1843 */ 1844 public boolean isAccessibilityFocused() { 1845 return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED); 1846 } 1847 1848 /** 1849 * Sets whether this node is accessibility focused. 1850 * <p> 1851 * <strong>Note:</strong> Cannot be called from an 1852 * {@link android.accessibilityservice.AccessibilityService}. 1853 * This class is made immutable before being delivered to an AccessibilityService. 1854 * </p> 1855 * 1856 * @param focused True if the node is accessibility focused. 1857 * 1858 * @throws IllegalStateException If called from an AccessibilityService. 1859 */ 1860 public void setAccessibilityFocused(boolean focused) { 1861 setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused); 1862 } 1863 1864 /** 1865 * Gets whether this node is selected. 1866 * 1867 * @return True if the node is selected. 1868 */ 1869 public boolean isSelected() { 1870 return getBooleanProperty(BOOLEAN_PROPERTY_SELECTED); 1871 } 1872 1873 /** 1874 * Sets whether this node is selected. 1875 * <p> 1876 * <strong>Note:</strong> Cannot be called from an 1877 * {@link android.accessibilityservice.AccessibilityService}. 1878 * This class is made immutable before being delivered to an AccessibilityService. 1879 * </p> 1880 * 1881 * @param selected True if the node is selected. 1882 * 1883 * @throws IllegalStateException If called from an AccessibilityService. 1884 */ 1885 public void setSelected(boolean selected) { 1886 setBooleanProperty(BOOLEAN_PROPERTY_SELECTED, selected); 1887 } 1888 1889 /** 1890 * Gets whether this node is clickable. 1891 * 1892 * @return True if the node is clickable. 1893 */ 1894 public boolean isClickable() { 1895 return getBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE); 1896 } 1897 1898 /** 1899 * Sets whether this node is clickable. 1900 * <p> 1901 * <strong>Note:</strong> Cannot be called from an 1902 * {@link android.accessibilityservice.AccessibilityService}. 1903 * This class is made immutable before being delivered to an AccessibilityService. 1904 * </p> 1905 * 1906 * @param clickable True if the node is clickable. 1907 * 1908 * @throws IllegalStateException If called from an AccessibilityService. 1909 */ 1910 public void setClickable(boolean clickable) { 1911 setBooleanProperty(BOOLEAN_PROPERTY_CLICKABLE, clickable); 1912 } 1913 1914 /** 1915 * Gets whether this node is long clickable. 1916 * 1917 * @return True if the node is long clickable. 1918 */ 1919 public boolean isLongClickable() { 1920 return getBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE); 1921 } 1922 1923 /** 1924 * Sets whether this node is long clickable. 1925 * <p> 1926 * <strong>Note:</strong> Cannot be called from an 1927 * {@link android.accessibilityservice.AccessibilityService}. 1928 * This class is made immutable before being delivered to an AccessibilityService. 1929 * </p> 1930 * 1931 * @param longClickable True if the node is long clickable. 1932 * 1933 * @throws IllegalStateException If called from an AccessibilityService. 1934 */ 1935 public void setLongClickable(boolean longClickable) { 1936 setBooleanProperty(BOOLEAN_PROPERTY_LONG_CLICKABLE, longClickable); 1937 } 1938 1939 /** 1940 * Gets whether this node is enabled. 1941 * 1942 * @return True if the node is enabled. 1943 */ 1944 public boolean isEnabled() { 1945 return getBooleanProperty(BOOLEAN_PROPERTY_ENABLED); 1946 } 1947 1948 /** 1949 * Sets whether this node is enabled. 1950 * <p> 1951 * <strong>Note:</strong> Cannot be called from an 1952 * {@link android.accessibilityservice.AccessibilityService}. 1953 * This class is made immutable before being delivered to an AccessibilityService. 1954 * </p> 1955 * 1956 * @param enabled True if the node is enabled. 1957 * 1958 * @throws IllegalStateException If called from an AccessibilityService. 1959 */ 1960 public void setEnabled(boolean enabled) { 1961 setBooleanProperty(BOOLEAN_PROPERTY_ENABLED, enabled); 1962 } 1963 1964 /** 1965 * Gets whether this node is a password. 1966 * 1967 * @return True if the node is a password. 1968 */ 1969 public boolean isPassword() { 1970 return getBooleanProperty(BOOLEAN_PROPERTY_PASSWORD); 1971 } 1972 1973 /** 1974 * Sets whether this node is a password. 1975 * <p> 1976 * <strong>Note:</strong> Cannot be called from an 1977 * {@link android.accessibilityservice.AccessibilityService}. 1978 * This class is made immutable before being delivered to an AccessibilityService. 1979 * </p> 1980 * 1981 * @param password True if the node is a password. 1982 * 1983 * @throws IllegalStateException If called from an AccessibilityService. 1984 */ 1985 public void setPassword(boolean password) { 1986 setBooleanProperty(BOOLEAN_PROPERTY_PASSWORD, password); 1987 } 1988 1989 /** 1990 * Gets if the node is scrollable. 1991 * 1992 * @return True if the node is scrollable, false otherwise. 1993 */ 1994 public boolean isScrollable() { 1995 return getBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE); 1996 } 1997 1998 /** 1999 * Sets if the node is scrollable. 2000 * <p> 2001 * <strong>Note:</strong> Cannot be called from an 2002 * {@link android.accessibilityservice.AccessibilityService}. 2003 * This class is made immutable before being delivered to an AccessibilityService. 2004 * </p> 2005 * 2006 * @param scrollable True if the node is scrollable, false otherwise. 2007 * 2008 * @throws IllegalStateException If called from an AccessibilityService. 2009 */ 2010 public void setScrollable(boolean scrollable) { 2011 setBooleanProperty(BOOLEAN_PROPERTY_SCROLLABLE, scrollable); 2012 } 2013 2014 /** 2015 * Gets if the node is editable. 2016 * 2017 * @return True if the node is editable, false otherwise. 2018 */ 2019 public boolean isEditable() { 2020 return getBooleanProperty(BOOLEAN_PROPERTY_EDITABLE); 2021 } 2022 2023 /** 2024 * Sets whether this node is editable. 2025 * <p> 2026 * <strong>Note:</strong> Cannot be called from an 2027 * {@link android.accessibilityservice.AccessibilityService}. 2028 * This class is made immutable before being delivered to an AccessibilityService. 2029 * </p> 2030 * 2031 * @param editable True if the node is editable. 2032 * 2033 * @throws IllegalStateException If called from an AccessibilityService. 2034 */ 2035 public void setEditable(boolean editable) { 2036 setBooleanProperty(BOOLEAN_PROPERTY_EDITABLE, editable); 2037 } 2038 2039 /** 2040 * If this node represents a visually distinct region of the screen that may update separately 2041 * from the rest of the window, it is considered a pane. Set the pane title to indicate that 2042 * the node is a pane, and to provide a title for it. 2043 * <p> 2044 * <strong>Note:</strong> Cannot be called from an 2045 * {@link android.accessibilityservice.AccessibilityService}. 2046 * This class is made immutable before being delivered to an AccessibilityService. 2047 * </p> 2048 * @param paneTitle The title of the pane represented by this node. 2049 */ 2050 public void setPaneTitle(@Nullable CharSequence paneTitle) { 2051 enforceNotSealed(); 2052 mPaneTitle = (paneTitle == null) 2053 ? null : paneTitle.subSequence(0, paneTitle.length()); 2054 } 2055 2056 /** 2057 * Get the title of the pane represented by this node. 2058 * 2059 * @return The title of the pane represented by this node, or {@code null} if this node does 2060 * not represent a pane. 2061 */ 2062 public @Nullable CharSequence getPaneTitle() { 2063 return mPaneTitle; 2064 } 2065 2066 /** 2067 * Get the drawing order of the view corresponding it this node. 2068 * <p> 2069 * Drawing order is determined only within the node's parent, so this index is only relative 2070 * to its siblings. 2071 * <p> 2072 * In some cases, the drawing order is essentially simultaneous, so it is possible for two 2073 * siblings to return the same value. It is also possible that values will be skipped. 2074 * 2075 * @return The drawing position of the view corresponding to this node relative to its siblings. 2076 */ 2077 public int getDrawingOrder() { 2078 return mDrawingOrderInParent; 2079 } 2080 2081 /** 2082 * Set the drawing order of the view corresponding it this node. 2083 * 2084 * <p> 2085 * <strong>Note:</strong> Cannot be called from an 2086 * {@link android.accessibilityservice.AccessibilityService}. 2087 * This class is made immutable before being delivered to an AccessibilityService. 2088 * </p> 2089 * @param drawingOrderInParent 2090 * @throws IllegalStateException If called from an AccessibilityService. 2091 */ 2092 public void setDrawingOrder(int drawingOrderInParent) { 2093 enforceNotSealed(); 2094 mDrawingOrderInParent = drawingOrderInParent; 2095 } 2096 2097 /** 2098 * Gets the collection info if the node is a collection. A collection 2099 * child is always a collection item. 2100 * 2101 * @return The collection info. 2102 */ 2103 public CollectionInfo getCollectionInfo() { 2104 return mCollectionInfo; 2105 } 2106 2107 /** 2108 * Sets the collection info if the node is a collection. A collection 2109 * child is always a collection item. 2110 * <p> 2111 * <strong>Note:</strong> Cannot be called from an 2112 * {@link android.accessibilityservice.AccessibilityService}. 2113 * This class is made immutable before being delivered to an AccessibilityService. 2114 * </p> 2115 * 2116 * @param collectionInfo The collection info. 2117 */ 2118 public void setCollectionInfo(CollectionInfo collectionInfo) { 2119 enforceNotSealed(); 2120 mCollectionInfo = collectionInfo; 2121 } 2122 2123 /** 2124 * Gets the collection item info if the node is a collection item. A collection 2125 * item is always a child of a collection. 2126 * 2127 * @return The collection item info. 2128 */ 2129 public CollectionItemInfo getCollectionItemInfo() { 2130 return mCollectionItemInfo; 2131 } 2132 2133 /** 2134 * Sets the collection item info if the node is a collection item. A collection 2135 * item is always a child of a collection. 2136 * <p> 2137 * <strong>Note:</strong> Cannot be called from an 2138 * {@link android.accessibilityservice.AccessibilityService}. 2139 * This class is made immutable before being delivered to an AccessibilityService. 2140 * </p> 2141 */ 2142 public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) { 2143 enforceNotSealed(); 2144 mCollectionItemInfo = collectionItemInfo; 2145 } 2146 2147 /** 2148 * Gets the range info if this node is a range. 2149 * 2150 * @return The range. 2151 */ 2152 public RangeInfo getRangeInfo() { 2153 return mRangeInfo; 2154 } 2155 2156 /** 2157 * Sets the range info if this node is a range. 2158 * <p> 2159 * <strong>Note:</strong> Cannot be called from an 2160 * {@link android.accessibilityservice.AccessibilityService}. 2161 * This class is made immutable before being delivered to an AccessibilityService. 2162 * </p> 2163 * 2164 * @param rangeInfo The range info. 2165 */ 2166 public void setRangeInfo(RangeInfo rangeInfo) { 2167 enforceNotSealed(); 2168 mRangeInfo = rangeInfo; 2169 } 2170 2171 /** 2172 * Gets if the content of this node is invalid. For example, 2173 * a date is not well-formed. 2174 * 2175 * @return If the node content is invalid. 2176 */ 2177 public boolean isContentInvalid() { 2178 return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID); 2179 } 2180 2181 /** 2182 * Sets if the content of this node is invalid. For example, 2183 * a date is not well-formed. 2184 * <p> 2185 * <strong>Note:</strong> Cannot be called from an 2186 * {@link android.accessibilityservice.AccessibilityService}. 2187 * This class is made immutable before being delivered to an AccessibilityService. 2188 * </p> 2189 * 2190 * @param contentInvalid If the node content is invalid. 2191 */ 2192 public void setContentInvalid(boolean contentInvalid) { 2193 setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid); 2194 } 2195 2196 /** 2197 * Gets whether this node is context clickable. 2198 * 2199 * @return True if the node is context clickable. 2200 */ 2201 public boolean isContextClickable() { 2202 return getBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE); 2203 } 2204 2205 /** 2206 * Sets whether this node is context clickable. 2207 * <p> 2208 * <strong>Note:</strong> Cannot be called from an 2209 * {@link android.accessibilityservice.AccessibilityService}. This class is made immutable 2210 * before being delivered to an AccessibilityService. 2211 * </p> 2212 * 2213 * @param contextClickable True if the node is context clickable. 2214 * @throws IllegalStateException If called from an AccessibilityService. 2215 */ 2216 public void setContextClickable(boolean contextClickable) { 2217 setBooleanProperty(BOOLEAN_PROPERTY_CONTEXT_CLICKABLE, contextClickable); 2218 } 2219 2220 /** 2221 * Gets the node's live region mode. 2222 * <p> 2223 * A live region is a node that contains information that is important for 2224 * the user and when it changes the user should be notified. For example, 2225 * in a login screen with a TextView that displays an "incorrect password" 2226 * notification, that view should be marked as a live region with mode 2227 * {@link View#ACCESSIBILITY_LIVE_REGION_POLITE}. 2228 * <p> 2229 * It is the responsibility of the accessibility service to monitor 2230 * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events indicating 2231 * changes to live region nodes and their children. 2232 * 2233 * @return The live region mode, or 2234 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a 2235 * live region. 2236 * @see android.view.View#getAccessibilityLiveRegion() 2237 */ 2238 public int getLiveRegion() { 2239 return mLiveRegion; 2240 } 2241 2242 /** 2243 * Sets the node's live region mode. 2244 * <p> 2245 * <strong>Note:</strong> Cannot be called from an 2246 * {@link android.accessibilityservice.AccessibilityService}. This class is 2247 * made immutable before being delivered to an AccessibilityService. 2248 * 2249 * @param mode The live region mode, or 2250 * {@link View#ACCESSIBILITY_LIVE_REGION_NONE} if the view is not a 2251 * live region. 2252 * @see android.view.View#setAccessibilityLiveRegion(int) 2253 */ 2254 public void setLiveRegion(int mode) { 2255 enforceNotSealed(); 2256 mLiveRegion = mode; 2257 } 2258 2259 /** 2260 * Gets if the node is a multi line editable text. 2261 * 2262 * @return True if the node is multi line. 2263 */ 2264 public boolean isMultiLine() { 2265 return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE); 2266 } 2267 2268 /** 2269 * Sets if the node is a multi line editable text. 2270 * <p> 2271 * <strong>Note:</strong> Cannot be called from an 2272 * {@link android.accessibilityservice.AccessibilityService}. 2273 * This class is made immutable before being delivered to an AccessibilityService. 2274 * </p> 2275 * 2276 * @param multiLine True if the node is multi line. 2277 */ 2278 public void setMultiLine(boolean multiLine) { 2279 setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine); 2280 } 2281 2282 /** 2283 * Gets if this node opens a popup or a dialog. 2284 * 2285 * @return If the the node opens a popup. 2286 */ 2287 public boolean canOpenPopup() { 2288 return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP); 2289 } 2290 2291 /** 2292 * Sets if this node opens a popup or a dialog. 2293 * <p> 2294 * <strong>Note:</strong> Cannot be called from an 2295 * {@link android.accessibilityservice.AccessibilityService}. 2296 * This class is made immutable before being delivered to an AccessibilityService. 2297 * </p> 2298 * 2299 * @param opensPopup If the the node opens a popup. 2300 */ 2301 public void setCanOpenPopup(boolean opensPopup) { 2302 enforceNotSealed(); 2303 setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup); 2304 } 2305 2306 /** 2307 * Gets if the node can be dismissed. 2308 * 2309 * @return If the node can be dismissed. 2310 */ 2311 public boolean isDismissable() { 2312 return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE); 2313 } 2314 2315 /** 2316 * Sets if the node can be dismissed. 2317 * <p> 2318 * <strong>Note:</strong> Cannot be called from an 2319 * {@link android.accessibilityservice.AccessibilityService}. 2320 * This class is made immutable before being delivered to an AccessibilityService. 2321 * </p> 2322 * 2323 * @param dismissable If the node can be dismissed. 2324 */ 2325 public void setDismissable(boolean dismissable) { 2326 setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable); 2327 } 2328 2329 /** 2330 * Returns whether the node originates from a view considered important for accessibility. 2331 * 2332 * @return {@code true} if the node originates from a view considered important for 2333 * accessibility, {@code false} otherwise 2334 * 2335 * @see View#isImportantForAccessibility() 2336 */ 2337 public boolean isImportantForAccessibility() { 2338 return getBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE); 2339 } 2340 2341 /** 2342 * Sets whether the node is considered important for accessibility. 2343 * <p> 2344 * <strong>Note:</strong> Cannot be called from an 2345 * {@link android.accessibilityservice.AccessibilityService}. 2346 * This class is made immutable before being delivered to an AccessibilityService. 2347 * </p> 2348 * 2349 * @param important {@code true} if the node is considered important for accessibility, 2350 * {@code false} otherwise 2351 */ 2352 public void setImportantForAccessibility(boolean important) { 2353 setBooleanProperty(BOOLEAN_PROPERTY_IMPORTANCE, important); 2354 } 2355 2356 /** 2357 * Returns whether the node is explicitly marked as a focusable unit by a screen reader. Note 2358 * that {@code false} indicates that it is not explicitly marked, not that the node is not 2359 * a focusable unit. Screen readers should generally use other signals, such as 2360 * {@link #isFocusable()}, or the presence of text in a node, to determine what should receive 2361 * focus. 2362 * 2363 * @return {@code true} if the node is specifically marked as a focusable unit for screen 2364 * readers, {@code false} otherwise. 2365 * 2366 * @see View#isScreenReaderFocusable() 2367 */ 2368 public boolean isScreenReaderFocusable() { 2369 return getBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE); 2370 } 2371 2372 /** 2373 * Sets whether the node should be considered a focusable unit by a screen reader. 2374 * <p> 2375 * <strong>Note:</strong> Cannot be called from an 2376 * {@link android.accessibilityservice.AccessibilityService}. 2377 * This class is made immutable before being delivered to an AccessibilityService. 2378 * </p> 2379 * 2380 * @param screenReaderFocusable {@code true} if the node is a focusable unit for screen readers, 2381 * {@code false} otherwise. 2382 */ 2383 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 2384 setBooleanProperty(BOOLEAN_PROPERTY_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 2385 } 2386 2387 /** 2388 * Returns whether the node's text represents a hint for the user to enter text. It should only 2389 * be {@code true} if the node has editable text. 2390 * 2391 * @return {@code true} if the text in the node represents a hint to the user, {@code false} 2392 * otherwise. 2393 */ 2394 public boolean isShowingHintText() { 2395 return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT); 2396 } 2397 2398 /** 2399 * Sets whether the node's text represents a hint for the user to enter text. It should only 2400 * be {@code true} if the node has editable text. 2401 * <p> 2402 * <strong>Note:</strong> Cannot be called from an 2403 * {@link android.accessibilityservice.AccessibilityService}. 2404 * This class is made immutable before being delivered to an AccessibilityService. 2405 * </p> 2406 * 2407 * @param showingHintText {@code true} if the text in the node represents a hint to the user, 2408 * {@code false} otherwise. 2409 */ 2410 public void setShowingHintText(boolean showingHintText) { 2411 setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText); 2412 } 2413 2414 /** 2415 * Returns whether node represents a heading. 2416 * 2417 * @return {@code true} if the node is a heading, {@code false} otherwise. 2418 */ 2419 public boolean isHeading() { 2420 return getBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING); 2421 } 2422 2423 /** 2424 * Sets whether the node represents a heading. 2425 * 2426 * <p> 2427 * <strong>Note:</strong> Cannot be called from an 2428 * {@link android.accessibilityservice.AccessibilityService}. 2429 * This class is made immutable before being delivered to an AccessibilityService. 2430 * </p> 2431 * 2432 * @param isHeading {@code true} if the node is a heading, {@code false} otherwise. 2433 */ 2434 public void setHeading(boolean isHeading) { 2435 setBooleanProperty(BOOLEAN_PROPERTY_IS_HEADING, isHeading); 2436 } 2437 2438 /** 2439 * Gets the package this node comes from. 2440 * 2441 * @return The package name. 2442 */ 2443 public CharSequence getPackageName() { 2444 return mPackageName; 2445 } 2446 2447 /** 2448 * Sets the package this node comes from. 2449 * <p> 2450 * <strong>Note:</strong> Cannot be called from an 2451 * {@link android.accessibilityservice.AccessibilityService}. 2452 * This class is made immutable before being delivered to an AccessibilityService. 2453 * </p> 2454 * 2455 * @param packageName The package name. 2456 * 2457 * @throws IllegalStateException If called from an AccessibilityService. 2458 */ 2459 public void setPackageName(CharSequence packageName) { 2460 enforceNotSealed(); 2461 mPackageName = packageName; 2462 } 2463 2464 /** 2465 * Gets the class this node comes from. 2466 * 2467 * @return The class name. 2468 */ 2469 public CharSequence getClassName() { 2470 return mClassName; 2471 } 2472 2473 /** 2474 * Sets the class this node comes from. 2475 * <p> 2476 * <strong>Note:</strong> Cannot be called from an 2477 * {@link android.accessibilityservice.AccessibilityService}. 2478 * This class is made immutable before being delivered to an AccessibilityService. 2479 * </p> 2480 * 2481 * @param className The class name. 2482 * 2483 * @throws IllegalStateException If called from an AccessibilityService. 2484 */ 2485 public void setClassName(CharSequence className) { 2486 enforceNotSealed(); 2487 mClassName = className; 2488 } 2489 2490 /** 2491 * Gets the text of this node. 2492 * <p> 2493 * <strong>Note:</strong> If the text contains {@link ClickableSpan}s or {@link URLSpan}s, 2494 * these spans will have been replaced with ones whose {@link ClickableSpan#onClick(View)} 2495 * can be called from an {@link AccessibilityService}. When called from a service, the 2496 * {@link View} argument is ignored and the corresponding span will be found on the view that 2497 * this {@code AccessibilityNodeInfo} represents and called with that view as its argument. 2498 * <p> 2499 * This treatment of {@link ClickableSpan}s means that the text returned from this method may 2500 * different slightly one passed to {@link #setText(CharSequence)}, although they will be 2501 * equivalent according to {@link TextUtils#equals(CharSequence, CharSequence)}. The 2502 * {@link ClickableSpan#onClick(View)} of any spans, however, will generally not work outside 2503 * of an accessibility service. 2504 * </p> 2505 * 2506 * @return The text. 2507 */ 2508 public CharSequence getText() { 2509 // Attach this node to any spans that need it 2510 if (mText instanceof Spanned) { 2511 Spanned spanned = (Spanned) mText; 2512 AccessibilityClickableSpan[] clickableSpans = 2513 spanned.getSpans(0, mText.length(), AccessibilityClickableSpan.class); 2514 for (int i = 0; i < clickableSpans.length; i++) { 2515 clickableSpans[i].copyConnectionDataFrom(this); 2516 } 2517 AccessibilityURLSpan[] urlSpans = 2518 spanned.getSpans(0, mText.length(), AccessibilityURLSpan.class); 2519 for (int i = 0; i < urlSpans.length; i++) { 2520 urlSpans[i].copyConnectionDataFrom(this); 2521 } 2522 } 2523 return mText; 2524 } 2525 2526 /** 2527 * Get the text passed to setText before any changes to the spans. 2528 * @hide 2529 */ 2530 public CharSequence getOriginalText() { 2531 return mOriginalText; 2532 } 2533 2534 /** 2535 * Sets the text of this node. 2536 * <p> 2537 * <strong>Note:</strong> Cannot be called from an 2538 * {@link android.accessibilityservice.AccessibilityService}. 2539 * This class is made immutable before being delivered to an AccessibilityService. 2540 * </p> 2541 * 2542 * @param text The text. 2543 * 2544 * @throws IllegalStateException If called from an AccessibilityService. 2545 */ 2546 public void setText(CharSequence text) { 2547 enforceNotSealed(); 2548 mOriginalText = text; 2549 // Replace any ClickableSpans in mText with placeholders 2550 if (text instanceof Spanned) { 2551 ClickableSpan[] spans = 2552 ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class); 2553 if (spans.length > 0) { 2554 Spannable spannable = new SpannableStringBuilder(text); 2555 for (int i = 0; i < spans.length; i++) { 2556 ClickableSpan span = spans[i]; 2557 if ((span instanceof AccessibilityClickableSpan) 2558 || (span instanceof AccessibilityURLSpan)) { 2559 // We've already done enough 2560 break; 2561 } 2562 int spanToReplaceStart = spannable.getSpanStart(span); 2563 int spanToReplaceEnd = spannable.getSpanEnd(span); 2564 int spanToReplaceFlags = spannable.getSpanFlags(span); 2565 spannable.removeSpan(span); 2566 ClickableSpan replacementSpan = (span instanceof URLSpan) 2567 ? new AccessibilityURLSpan((URLSpan) span) 2568 : new AccessibilityClickableSpan(span.getId()); 2569 spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd, 2570 spanToReplaceFlags); 2571 } 2572 mText = spannable; 2573 return; 2574 } 2575 } 2576 mText = (text == null) ? null : text.subSequence(0, text.length()); 2577 } 2578 2579 /** 2580 * Gets the hint text of this node. Only applies to nodes where text can be entered. 2581 * 2582 * @return The hint text. 2583 */ 2584 public CharSequence getHintText() { 2585 return mHintText; 2586 } 2587 2588 /** 2589 * Sets the hint text of this node. Only applies to nodes where text can be entered. 2590 * <p> 2591 * <strong>Note:</strong> Cannot be called from an 2592 * {@link android.accessibilityservice.AccessibilityService}. 2593 * This class is made immutable before being delivered to an AccessibilityService. 2594 * </p> 2595 * 2596 * @param hintText The hint text for this mode. 2597 * 2598 * @throws IllegalStateException If called from an AccessibilityService. 2599 */ 2600 public void setHintText(CharSequence hintText) { 2601 enforceNotSealed(); 2602 mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length()); 2603 } 2604 2605 /** 2606 * Sets the error text of this node. 2607 * <p> 2608 * <strong>Note:</strong> Cannot be called from an 2609 * {@link android.accessibilityservice.AccessibilityService}. 2610 * This class is made immutable before being delivered to an AccessibilityService. 2611 * </p> 2612 * 2613 * @param error The error text. 2614 * 2615 * @throws IllegalStateException If called from an AccessibilityService. 2616 */ 2617 public void setError(CharSequence error) { 2618 enforceNotSealed(); 2619 mError = (error == null) ? null : error.subSequence(0, error.length()); 2620 } 2621 2622 /** 2623 * Gets the error text of this node. 2624 * 2625 * @return The error text. 2626 */ 2627 public CharSequence getError() { 2628 return mError; 2629 } 2630 2631 /** 2632 * Gets the content description of this node. 2633 * 2634 * @return The content description. 2635 */ 2636 public CharSequence getContentDescription() { 2637 return mContentDescription; 2638 } 2639 2640 /** 2641 * Sets the content description of this node. 2642 * <p> 2643 * <strong>Note:</strong> Cannot be called from an 2644 * {@link android.accessibilityservice.AccessibilityService}. 2645 * This class is made immutable before being delivered to an AccessibilityService. 2646 * </p> 2647 * 2648 * @param contentDescription The content description. 2649 * 2650 * @throws IllegalStateException If called from an AccessibilityService. 2651 */ 2652 public void setContentDescription(CharSequence contentDescription) { 2653 enforceNotSealed(); 2654 mContentDescription = (contentDescription == null) ? null 2655 : contentDescription.subSequence(0, contentDescription.length()); 2656 } 2657 2658 /** 2659 * Gets the tooltip text of this node. 2660 * 2661 * @return The tooltip text. 2662 */ 2663 @Nullable 2664 public CharSequence getTooltipText() { 2665 return mTooltipText; 2666 } 2667 2668 /** 2669 * Sets the tooltip text of this node. 2670 * <p> 2671 * <strong>Note:</strong> Cannot be called from an 2672 * {@link android.accessibilityservice.AccessibilityService}. 2673 * This class is made immutable before being delivered to an AccessibilityService. 2674 * </p> 2675 * 2676 * @param tooltipText The tooltip text. 2677 * 2678 * @throws IllegalStateException If called from an AccessibilityService. 2679 */ 2680 public void setTooltipText(@Nullable CharSequence tooltipText) { 2681 enforceNotSealed(); 2682 mTooltipText = (tooltipText == null) ? null 2683 : tooltipText.subSequence(0, tooltipText.length()); 2684 } 2685 2686 /** 2687 * Sets the view for which the view represented by this info serves as a 2688 * label for accessibility purposes. 2689 * 2690 * @param labeled The view for which this info serves as a label. 2691 */ 2692 public void setLabelFor(View labeled) { 2693 setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID); 2694 } 2695 2696 /** 2697 * Sets the view for which the view represented by this info serves as a 2698 * label for accessibility purposes. If <code>virtualDescendantId</code> 2699 * is {@link View#NO_ID} the root is set as the labeled. 2700 * <p> 2701 * A virtual descendant is an imaginary View that is reported as a part of the view 2702 * hierarchy for accessibility purposes. This enables custom views that draw complex 2703 * content to report themselves as a tree of virtual views, thus conveying their 2704 * logical structure. 2705 * </p> 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 root The root whose virtual descendant serves as a label. 2713 * @param virtualDescendantId The id of the virtual descendant. 2714 */ 2715 public void setLabelFor(View root, int virtualDescendantId) { 2716 enforceNotSealed(); 2717 final int rootAccessibilityViewId = (root != null) 2718 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 2719 mLabelForId = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 2720 } 2721 2722 /** 2723 * Gets the node info for which the view represented by this info serves as 2724 * a label for accessibility purposes. 2725 * <p> 2726 * <strong>Note:</strong> It is a client responsibility to recycle the 2727 * received info by calling {@link AccessibilityNodeInfo#recycle()} 2728 * to avoid creating of multiple instances. 2729 * </p> 2730 * 2731 * @return The labeled info. 2732 */ 2733 public AccessibilityNodeInfo getLabelFor() { 2734 enforceSealed(); 2735 return getNodeForAccessibilityId(mLabelForId); 2736 } 2737 2738 /** 2739 * Sets the view which serves as the label of the view represented by 2740 * this info for accessibility purposes. 2741 * 2742 * @param label The view that labels this node's source. 2743 */ 2744 public void setLabeledBy(View label) { 2745 setLabeledBy(label, AccessibilityNodeProvider.HOST_VIEW_ID); 2746 } 2747 2748 /** 2749 * Sets the view which serves as the label of the view represented by 2750 * this info for accessibility purposes. If <code>virtualDescendantId</code> 2751 * is {@link View#NO_ID} the root is set as the label. 2752 * <p> 2753 * A virtual descendant is an imaginary View that is reported as a part of the view 2754 * hierarchy for accessibility purposes. This enables custom views that draw complex 2755 * content to report themselves as a tree of virtual views, thus conveying their 2756 * logical structure. 2757 * </p> 2758 * <p> 2759 * <strong>Note:</strong> Cannot be called from an 2760 * {@link android.accessibilityservice.AccessibilityService}. 2761 * This class is made immutable before being delivered to an AccessibilityService. 2762 * </p> 2763 * 2764 * @param root The root whose virtual descendant labels this node's source. 2765 * @param virtualDescendantId The id of the virtual descendant. 2766 */ 2767 public void setLabeledBy(View root, int virtualDescendantId) { 2768 enforceNotSealed(); 2769 final int rootAccessibilityViewId = (root != null) 2770 ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID; 2771 mLabeledById = makeNodeId(rootAccessibilityViewId, virtualDescendantId); 2772 } 2773 2774 /** 2775 * Gets the node info which serves as the label of the view represented by 2776 * this info for accessibility purposes. 2777 * <p> 2778 * <strong>Note:</strong> It is a client responsibility to recycle the 2779 * received info by calling {@link AccessibilityNodeInfo#recycle()} 2780 * to avoid creating of multiple instances. 2781 * </p> 2782 * 2783 * @return The label. 2784 */ 2785 public AccessibilityNodeInfo getLabeledBy() { 2786 enforceSealed(); 2787 return getNodeForAccessibilityId(mLabeledById); 2788 } 2789 2790 /** 2791 * Sets the fully qualified resource name of the source view's id. 2792 * 2793 * <p> 2794 * <strong>Note:</strong> Cannot be called from an 2795 * {@link android.accessibilityservice.AccessibilityService}. 2796 * This class is made immutable before being delivered to an AccessibilityService. 2797 * </p> 2798 * 2799 * @param viewIdResName The id resource name. 2800 */ 2801 public void setViewIdResourceName(String viewIdResName) { 2802 enforceNotSealed(); 2803 mViewIdResourceName = viewIdResName; 2804 } 2805 2806 /** 2807 * Gets the fully qualified resource name of the source view's id. 2808 * 2809 * <p> 2810 * <strong>Note:</strong> The primary usage of this API is for UI test automation 2811 * and in order to report the source view id of an {@link AccessibilityNodeInfo} the 2812 * client has to set the {@link AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS} 2813 * flag when configuring his {@link android.accessibilityservice.AccessibilityService}. 2814 * </p> 2815 2816 * @return The id resource name. 2817 */ 2818 public String getViewIdResourceName() { 2819 return mViewIdResourceName; 2820 } 2821 2822 /** 2823 * Gets the text selection start or the cursor position. 2824 * <p> 2825 * If no text is selected, both this method and 2826 * {@link AccessibilityNodeInfo#getTextSelectionEnd()} return the same value: 2827 * the current location of the cursor. 2828 * </p> 2829 * 2830 * @return The text selection start, the cursor location if there is no selection, or -1 if 2831 * there is no text selection and no cursor. 2832 */ 2833 public int getTextSelectionStart() { 2834 return mTextSelectionStart; 2835 } 2836 2837 /** 2838 * Gets the text selection end if text is selected. 2839 * <p> 2840 * If no text is selected, both this method and 2841 * {@link AccessibilityNodeInfo#getTextSelectionStart()} return the same value: 2842 * the current location of the cursor. 2843 * </p> 2844 * 2845 * @return The text selection end, the cursor location if there is no selection, or -1 if 2846 * there is no text selection and no cursor. 2847 */ 2848 public int getTextSelectionEnd() { 2849 return mTextSelectionEnd; 2850 } 2851 2852 /** 2853 * Sets the text selection start and end. 2854 * <p> 2855 * <strong>Note:</strong> Cannot be called from an 2856 * {@link android.accessibilityservice.AccessibilityService}. 2857 * This class is made immutable before being delivered to an AccessibilityService. 2858 * </p> 2859 * 2860 * @param start The text selection start. 2861 * @param end The text selection end. 2862 * 2863 * @throws IllegalStateException If called from an AccessibilityService. 2864 */ 2865 public void setTextSelection(int start, int end) { 2866 enforceNotSealed(); 2867 mTextSelectionStart = start; 2868 mTextSelectionEnd = end; 2869 } 2870 2871 /** 2872 * Gets the input type of the source as defined by {@link InputType}. 2873 * 2874 * @return The input type. 2875 */ 2876 public int getInputType() { 2877 return mInputType; 2878 } 2879 2880 /** 2881 * Sets the input type of the source as defined by {@link InputType}. 2882 * <p> 2883 * <strong>Note:</strong> Cannot be called from an 2884 * {@link android.accessibilityservice.AccessibilityService}. 2885 * This class is made immutable before being delivered to an 2886 * AccessibilityService. 2887 * </p> 2888 * 2889 * @param inputType The input type. 2890 * 2891 * @throws IllegalStateException If called from an AccessibilityService. 2892 */ 2893 public void setInputType(int inputType) { 2894 enforceNotSealed(); 2895 mInputType = inputType; 2896 } 2897 2898 /** 2899 * Gets an optional bundle with extra data. The bundle 2900 * is lazily created and never <code>null</code>. 2901 * <p> 2902 * <strong>Note:</strong> It is recommended to use the package 2903 * name of your application as a prefix for the keys to avoid 2904 * collisions which may confuse an accessibility service if the 2905 * same key has different meaning when emitted from different 2906 * applications. 2907 * </p> 2908 * 2909 * @return The bundle. 2910 */ 2911 public Bundle getExtras() { 2912 if (mExtras == null) { 2913 mExtras = new Bundle(); 2914 } 2915 return mExtras; 2916 } 2917 2918 /** 2919 * Check if a node has an extras bundle 2920 * @hide 2921 */ 2922 public boolean hasExtras() { 2923 return mExtras != null; 2924 } 2925 2926 /** 2927 * Gets the value of a boolean property. 2928 * 2929 * @param property The property. 2930 * @return The value. 2931 */ 2932 private boolean getBooleanProperty(int property) { 2933 return (mBooleanProperties & property) != 0; 2934 } 2935 2936 /** 2937 * Sets a boolean property. 2938 * 2939 * @param property The property. 2940 * @param value The value. 2941 * 2942 * @throws IllegalStateException If called from an AccessibilityService. 2943 */ 2944 private void setBooleanProperty(int property, boolean value) { 2945 enforceNotSealed(); 2946 if (value) { 2947 mBooleanProperties |= property; 2948 } else { 2949 mBooleanProperties &= ~property; 2950 } 2951 } 2952 2953 /** 2954 * Sets the unique id of the IAccessibilityServiceConnection over which 2955 * this instance can send requests to the system. 2956 * 2957 * @param connectionId The connection id. 2958 * 2959 * @hide 2960 */ 2961 public void setConnectionId(int connectionId) { 2962 enforceNotSealed(); 2963 mConnectionId = connectionId; 2964 } 2965 2966 /** 2967 * Get the connection ID. 2968 * 2969 * @return The connection id 2970 * 2971 * @hide 2972 */ 2973 public int getConnectionId() { 2974 return mConnectionId; 2975 } 2976 2977 /** 2978 * {@inheritDoc} 2979 */ 2980 @Override 2981 public int describeContents() { 2982 return 0; 2983 } 2984 2985 /** 2986 * Sets the id of the source node. 2987 * 2988 * @param sourceId The id. 2989 * @param windowId The window id. 2990 * 2991 * @hide 2992 */ 2993 public void setSourceNodeId(long sourceId, int windowId) { 2994 enforceNotSealed(); 2995 mSourceNodeId = sourceId; 2996 mWindowId = windowId; 2997 } 2998 2999 /** 3000 * Gets the id of the source node. 3001 * 3002 * @return The id. 3003 * 3004 * @hide 3005 */ 3006 public long getSourceNodeId() { 3007 return mSourceNodeId; 3008 } 3009 3010 /** 3011 * Sets if this instance is sealed. 3012 * 3013 * @param sealed Whether is sealed. 3014 * 3015 * @hide 3016 */ 3017 public void setSealed(boolean sealed) { 3018 mSealed = sealed; 3019 } 3020 3021 /** 3022 * Gets if this instance is sealed. 3023 * 3024 * @return Whether is sealed. 3025 * 3026 * @hide 3027 */ 3028 public boolean isSealed() { 3029 return mSealed; 3030 } 3031 3032 /** 3033 * Enforces that this instance is sealed. 3034 * 3035 * @throws IllegalStateException If this instance is not sealed. 3036 * 3037 * @hide 3038 */ 3039 protected void enforceSealed() { 3040 if (!isSealed()) { 3041 throw new IllegalStateException("Cannot perform this " 3042 + "action on a not sealed instance."); 3043 } 3044 } 3045 3046 private void enforceValidFocusDirection(int direction) { 3047 switch (direction) { 3048 case View.FOCUS_DOWN: 3049 case View.FOCUS_UP: 3050 case View.FOCUS_LEFT: 3051 case View.FOCUS_RIGHT: 3052 case View.FOCUS_FORWARD: 3053 case View.FOCUS_BACKWARD: 3054 return; 3055 default: 3056 throw new IllegalArgumentException("Unknown direction: " + direction); 3057 } 3058 } 3059 3060 private void enforceValidFocusType(int focusType) { 3061 switch (focusType) { 3062 case FOCUS_INPUT: 3063 case FOCUS_ACCESSIBILITY: 3064 return; 3065 default: 3066 throw new IllegalArgumentException("Unknown focus type: " + focusType); 3067 } 3068 } 3069 3070 /** 3071 * Enforces that this instance is not sealed. 3072 * 3073 * @throws IllegalStateException If this instance is sealed. 3074 * 3075 * @hide 3076 */ 3077 protected void enforceNotSealed() { 3078 if (isSealed()) { 3079 throw new IllegalStateException("Cannot perform this " 3080 + "action on a sealed instance."); 3081 } 3082 } 3083 3084 /** 3085 * Returns a cached instance if such is available otherwise a new one 3086 * and sets the source. 3087 * 3088 * @param source The source view. 3089 * @return An instance. 3090 * 3091 * @see #setSource(View) 3092 */ 3093 public static AccessibilityNodeInfo obtain(View source) { 3094 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 3095 info.setSource(source); 3096 return info; 3097 } 3098 3099 /** 3100 * Returns a cached instance if such is available otherwise a new one 3101 * and sets the source. 3102 * 3103 * @param root The root of the virtual subtree. 3104 * @param virtualDescendantId The id of the virtual descendant. 3105 * @return An instance. 3106 * 3107 * @see #setSource(View, int) 3108 */ 3109 public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) { 3110 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 3111 info.setSource(root, virtualDescendantId); 3112 return info; 3113 } 3114 3115 /** 3116 * Returns a cached instance if such is available otherwise a new one. 3117 * 3118 * @return An instance. 3119 */ 3120 public static AccessibilityNodeInfo obtain() { 3121 AccessibilityNodeInfo info = sPool.acquire(); 3122 if (sNumInstancesInUse != null) { 3123 sNumInstancesInUse.incrementAndGet(); 3124 } 3125 return (info != null) ? info : new AccessibilityNodeInfo(); 3126 } 3127 3128 /** 3129 * Returns a cached instance if such is available or a new one is 3130 * create. The returned instance is initialized from the given 3131 * <code>info</code>. 3132 * 3133 * @param info The other info. 3134 * @return An instance. 3135 */ 3136 public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) { 3137 AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain(); 3138 infoClone.init(info); 3139 return infoClone; 3140 } 3141 3142 /** 3143 * Return an instance back to be reused. 3144 * <p> 3145 * <strong>Note:</strong> You must not touch the object after calling this function. 3146 * 3147 * @throws IllegalStateException If the info is already recycled. 3148 */ 3149 public void recycle() { 3150 clear(); 3151 sPool.release(this); 3152 if (sNumInstancesInUse != null) { 3153 sNumInstancesInUse.decrementAndGet(); 3154 } 3155 } 3156 3157 /** 3158 * Specify a counter that will be incremented on obtain() and decremented on recycle() 3159 * 3160 * @hide 3161 */ 3162 @TestApi 3163 public static void setNumInstancesInUseCounter(AtomicInteger counter) { 3164 sNumInstancesInUse = counter; 3165 } 3166 3167 /** 3168 * {@inheritDoc} 3169 * <p> 3170 * <strong>Note:</strong> After the instance is written to a parcel it 3171 * is recycled. You must not touch the object after calling this function. 3172 * </p> 3173 */ 3174 @Override 3175 public void writeToParcel(Parcel parcel, int flags) { 3176 // Write bit set of indices of fields with values differing from default 3177 long nonDefaultFields = 0; 3178 int fieldIndex = 0; // index of the current field 3179 if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex); 3180 fieldIndex++; 3181 if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex); 3182 fieldIndex++; 3183 if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex); 3184 fieldIndex++; 3185 if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex); 3186 fieldIndex++; 3187 if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex); 3188 fieldIndex++; 3189 if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex); 3190 fieldIndex++; 3191 if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex); 3192 fieldIndex++; 3193 if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex); 3194 fieldIndex++; 3195 if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex); 3196 fieldIndex++; 3197 if (!Objects.equals(mChildNodeIds, DEFAULT.mChildNodeIds)) { 3198 nonDefaultFields |= bitAt(fieldIndex); 3199 } 3200 fieldIndex++; 3201 if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) { 3202 nonDefaultFields |= bitAt(fieldIndex); 3203 } 3204 fieldIndex++; 3205 if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) { 3206 nonDefaultFields |= bitAt(fieldIndex); 3207 } 3208 fieldIndex++; 3209 if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex); 3210 fieldIndex++; 3211 if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex); 3212 fieldIndex++; 3213 if (mMovementGranularities != DEFAULT.mMovementGranularities) { 3214 nonDefaultFields |= bitAt(fieldIndex); 3215 } 3216 fieldIndex++; 3217 if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex); 3218 fieldIndex++; 3219 if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) { 3220 nonDefaultFields |= bitAt(fieldIndex); 3221 } 3222 fieldIndex++; 3223 if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex); 3224 fieldIndex++; 3225 if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex); 3226 fieldIndex++; 3227 if (!Objects.equals(mHintText, DEFAULT.mHintText)) { 3228 nonDefaultFields |= bitAt(fieldIndex); 3229 } 3230 fieldIndex++; 3231 if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex); 3232 fieldIndex++; 3233 if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) { 3234 nonDefaultFields |= bitAt(fieldIndex); 3235 } 3236 fieldIndex++; 3237 if (!Objects.equals(mPaneTitle, DEFAULT.mPaneTitle)) { 3238 nonDefaultFields |= bitAt(fieldIndex); 3239 } 3240 fieldIndex++; 3241 if (!Objects.equals(mTooltipText, DEFAULT.mTooltipText)) { 3242 nonDefaultFields |= bitAt(fieldIndex); 3243 } 3244 fieldIndex++; 3245 if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) { 3246 nonDefaultFields |= bitAt(fieldIndex); 3247 } 3248 fieldIndex++; 3249 if (mTextSelectionStart != DEFAULT.mTextSelectionStart) { 3250 nonDefaultFields |= bitAt(fieldIndex); 3251 } 3252 fieldIndex++; 3253 if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) { 3254 nonDefaultFields |= bitAt(fieldIndex); 3255 } 3256 fieldIndex++; 3257 if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex); 3258 fieldIndex++; 3259 if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex); 3260 fieldIndex++; 3261 if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) { 3262 nonDefaultFields |= bitAt(fieldIndex); 3263 } 3264 fieldIndex++; 3265 if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) { 3266 nonDefaultFields |= bitAt(fieldIndex); 3267 } 3268 fieldIndex++; 3269 if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex); 3270 fieldIndex++; 3271 if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex); 3272 fieldIndex++; 3273 if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) { 3274 nonDefaultFields |= bitAt(fieldIndex); 3275 } 3276 fieldIndex++; 3277 if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) { 3278 nonDefaultFields |= bitAt(fieldIndex); 3279 } 3280 int totalFields = fieldIndex; 3281 parcel.writeLong(nonDefaultFields); 3282 3283 fieldIndex = 0; 3284 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0); 3285 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId); 3286 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId); 3287 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId); 3288 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId); 3289 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById); 3290 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore); 3291 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter); 3292 3293 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId); 3294 3295 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3296 final LongArray childIds = mChildNodeIds; 3297 if (childIds == null) { 3298 parcel.writeInt(0); 3299 } else { 3300 final int childIdsSize = childIds.size(); 3301 parcel.writeInt(childIdsSize); 3302 for (int i = 0; i < childIdsSize; i++) { 3303 parcel.writeLong(childIds.get(i)); 3304 } 3305 } 3306 } 3307 3308 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3309 parcel.writeInt(mBoundsInParent.top); 3310 parcel.writeInt(mBoundsInParent.bottom); 3311 parcel.writeInt(mBoundsInParent.left); 3312 parcel.writeInt(mBoundsInParent.right); 3313 } 3314 3315 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3316 parcel.writeInt(mBoundsInScreen.top); 3317 parcel.writeInt(mBoundsInScreen.bottom); 3318 parcel.writeInt(mBoundsInScreen.left); 3319 parcel.writeInt(mBoundsInScreen.right); 3320 } 3321 3322 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3323 if (mActions != null && !mActions.isEmpty()) { 3324 final int actionCount = mActions.size(); 3325 3326 int nonStandardActionCount = 0; 3327 int defaultStandardActions = 0; 3328 for (int i = 0; i < actionCount; i++) { 3329 AccessibilityAction action = mActions.get(i); 3330 if (isDefaultStandardAction(action)) { 3331 defaultStandardActions |= action.mSerializationFlag; 3332 } else { 3333 nonStandardActionCount++; 3334 } 3335 } 3336 parcel.writeInt(defaultStandardActions); 3337 3338 parcel.writeInt(nonStandardActionCount); 3339 for (int i = 0; i < actionCount; i++) { 3340 AccessibilityAction action = mActions.get(i); 3341 if (!isDefaultStandardAction(action)) { 3342 parcel.writeInt(action.getId()); 3343 parcel.writeCharSequence(action.getLabel()); 3344 } 3345 } 3346 } else { 3347 parcel.writeInt(0); 3348 parcel.writeInt(0); 3349 } 3350 } 3351 3352 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength); 3353 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities); 3354 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties); 3355 3356 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName); 3357 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName); 3358 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText); 3359 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText); 3360 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError); 3361 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3362 parcel.writeCharSequence(mContentDescription); 3363 } 3364 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPaneTitle); 3365 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mTooltipText); 3366 3367 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName); 3368 3369 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart); 3370 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd); 3371 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType); 3372 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion); 3373 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent); 3374 3375 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys); 3376 3377 if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras); 3378 3379 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3380 parcel.writeInt(mRangeInfo.getType()); 3381 parcel.writeFloat(mRangeInfo.getMin()); 3382 parcel.writeFloat(mRangeInfo.getMax()); 3383 parcel.writeFloat(mRangeInfo.getCurrent()); 3384 } 3385 3386 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3387 parcel.writeInt(mCollectionInfo.getRowCount()); 3388 parcel.writeInt(mCollectionInfo.getColumnCount()); 3389 parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0); 3390 parcel.writeInt(mCollectionInfo.getSelectionMode()); 3391 } 3392 3393 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3394 parcel.writeInt(mCollectionItemInfo.getRowIndex()); 3395 parcel.writeInt(mCollectionItemInfo.getRowSpan()); 3396 parcel.writeInt(mCollectionItemInfo.getColumnIndex()); 3397 parcel.writeInt(mCollectionItemInfo.getColumnSpan()); 3398 parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0); 3399 parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0); 3400 } 3401 3402 if (DEBUG) { 3403 fieldIndex--; 3404 if (totalFields != fieldIndex) { 3405 throw new IllegalStateException("Number of fields mismatch: " + totalFields 3406 + " vs " + fieldIndex); 3407 } 3408 } 3409 3410 // Since instances of this class are fetched via synchronous i.e. blocking 3411 // calls in IPCs we always recycle as soon as the instance is marshaled. 3412 recycle(); 3413 } 3414 3415 /** 3416 * Initializes this instance from another one. 3417 * 3418 * @param other The other instance. 3419 */ 3420 private void init(AccessibilityNodeInfo other) { 3421 mSealed = other.mSealed; 3422 mSourceNodeId = other.mSourceNodeId; 3423 mParentNodeId = other.mParentNodeId; 3424 mLabelForId = other.mLabelForId; 3425 mLabeledById = other.mLabeledById; 3426 mTraversalBefore = other.mTraversalBefore; 3427 mTraversalAfter = other.mTraversalAfter; 3428 mWindowId = other.mWindowId; 3429 mConnectionId = other.mConnectionId; 3430 mBoundsInParent.set(other.mBoundsInParent); 3431 mBoundsInScreen.set(other.mBoundsInScreen); 3432 mPackageName = other.mPackageName; 3433 mClassName = other.mClassName; 3434 mText = other.mText; 3435 mHintText = other.mHintText; 3436 mError = other.mError; 3437 mContentDescription = other.mContentDescription; 3438 mPaneTitle = other.mPaneTitle; 3439 mTooltipText = other.mTooltipText; 3440 mViewIdResourceName = other.mViewIdResourceName; 3441 3442 if (mActions != null) mActions.clear(); 3443 final ArrayList<AccessibilityAction> otherActions = other.mActions; 3444 if (otherActions != null && otherActions.size() > 0) { 3445 if (mActions == null) { 3446 mActions = new ArrayList(otherActions); 3447 } else { 3448 mActions.addAll(other.mActions); 3449 } 3450 } 3451 3452 mBooleanProperties = other.mBooleanProperties; 3453 mMaxTextLength = other.mMaxTextLength; 3454 mMovementGranularities = other.mMovementGranularities; 3455 3456 3457 if (mChildNodeIds != null) mChildNodeIds.clear(); 3458 final LongArray otherChildNodeIds = other.mChildNodeIds; 3459 if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) { 3460 if (mChildNodeIds == null) { 3461 mChildNodeIds = otherChildNodeIds.clone(); 3462 } else { 3463 mChildNodeIds.addAll(otherChildNodeIds); 3464 } 3465 } 3466 3467 mTextSelectionStart = other.mTextSelectionStart; 3468 mTextSelectionEnd = other.mTextSelectionEnd; 3469 mInputType = other.mInputType; 3470 mLiveRegion = other.mLiveRegion; 3471 mDrawingOrderInParent = other.mDrawingOrderInParent; 3472 3473 mExtraDataKeys = other.mExtraDataKeys; 3474 3475 mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null; 3476 3477 if (mRangeInfo != null) mRangeInfo.recycle(); 3478 mRangeInfo = (other.mRangeInfo != null) 3479 ? RangeInfo.obtain(other.mRangeInfo) : null; 3480 if (mCollectionInfo != null) mCollectionInfo.recycle(); 3481 mCollectionInfo = (other.mCollectionInfo != null) 3482 ? CollectionInfo.obtain(other.mCollectionInfo) : null; 3483 if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); 3484 mCollectionItemInfo = (other.mCollectionItemInfo != null) 3485 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null; 3486 } 3487 3488 /** 3489 * Creates a new instance from a {@link Parcel}. 3490 * 3491 * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}. 3492 */ 3493 private void initFromParcel(Parcel parcel) { 3494 // Bit mask of non-default-valued field indices 3495 long nonDefaultFields = parcel.readLong(); 3496 int fieldIndex = 0; 3497 final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++) 3498 ? (parcel.readInt() == 1) 3499 : DEFAULT.mSealed; 3500 if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong(); 3501 if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt(); 3502 if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong(); 3503 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong(); 3504 if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong(); 3505 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong(); 3506 if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong(); 3507 3508 if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt(); 3509 3510 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3511 final int childrenSize = parcel.readInt(); 3512 if (childrenSize <= 0) { 3513 mChildNodeIds = null; 3514 } else { 3515 mChildNodeIds = new LongArray(childrenSize); 3516 for (int i = 0; i < childrenSize; i++) { 3517 final long childId = parcel.readLong(); 3518 mChildNodeIds.add(childId); 3519 } 3520 } 3521 } 3522 3523 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3524 mBoundsInParent.top = parcel.readInt(); 3525 mBoundsInParent.bottom = parcel.readInt(); 3526 mBoundsInParent.left = parcel.readInt(); 3527 mBoundsInParent.right = parcel.readInt(); 3528 } 3529 3530 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3531 mBoundsInScreen.top = parcel.readInt(); 3532 mBoundsInScreen.bottom = parcel.readInt(); 3533 mBoundsInScreen.left = parcel.readInt(); 3534 mBoundsInScreen.right = parcel.readInt(); 3535 } 3536 3537 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3538 final int standardActions = parcel.readInt(); 3539 addStandardActions(standardActions); 3540 final int nonStandardActionCount = parcel.readInt(); 3541 for (int i = 0; i < nonStandardActionCount; i++) { 3542 final AccessibilityAction action = new AccessibilityAction( 3543 parcel.readInt(), parcel.readCharSequence()); 3544 addActionUnchecked(action); 3545 } 3546 } 3547 3548 if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt(); 3549 if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt(); 3550 if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt(); 3551 3552 if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence(); 3553 if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence(); 3554 if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence(); 3555 if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence(); 3556 if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence(); 3557 if (isBitSet(nonDefaultFields, fieldIndex++)) { 3558 mContentDescription = parcel.readCharSequence(); 3559 } 3560 if (isBitSet(nonDefaultFields, fieldIndex++)) mPaneTitle = parcel.readString(); 3561 if (isBitSet(nonDefaultFields, fieldIndex++)) mTooltipText = parcel.readCharSequence(); 3562 if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString(); 3563 3564 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt(); 3565 if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt(); 3566 3567 if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt(); 3568 if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt(); 3569 if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt(); 3570 3571 mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++) 3572 ? parcel.createStringArrayList() 3573 : null; 3574 3575 mExtras = isBitSet(nonDefaultFields, fieldIndex++) 3576 ? parcel.readBundle() 3577 : null; 3578 3579 if (mRangeInfo != null) mRangeInfo.recycle(); 3580 mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++) 3581 ? RangeInfo.obtain( 3582 parcel.readInt(), 3583 parcel.readFloat(), 3584 parcel.readFloat(), 3585 parcel.readFloat()) 3586 : null; 3587 3588 if (mCollectionInfo != null) mCollectionInfo.recycle(); 3589 mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++) 3590 ? CollectionInfo.obtain( 3591 parcel.readInt(), 3592 parcel.readInt(), 3593 parcel.readInt() == 1, 3594 parcel.readInt()) 3595 : null; 3596 3597 if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); 3598 mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++) 3599 ? CollectionItemInfo.obtain( 3600 parcel.readInt(), 3601 parcel.readInt(), 3602 parcel.readInt(), 3603 parcel.readInt(), 3604 parcel.readInt() == 1, 3605 parcel.readInt() == 1) 3606 : null; 3607 3608 mSealed = sealed; 3609 } 3610 3611 /** 3612 * Clears the state of this instance. 3613 */ 3614 private void clear() { 3615 init(DEFAULT); 3616 } 3617 3618 private static boolean isDefaultStandardAction(AccessibilityAction action) { 3619 return action.mSerializationFlag != -1 && TextUtils.isEmpty(action.getLabel()); 3620 } 3621 3622 private static AccessibilityAction getActionSingleton(int actionId) { 3623 final int actions = AccessibilityAction.sStandardActions.size(); 3624 for (int i = 0; i < actions; i++) { 3625 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i); 3626 if (actionId == currentAction.getId()) { 3627 return currentAction; 3628 } 3629 } 3630 3631 return null; 3632 } 3633 3634 private static AccessibilityAction getActionSingletonBySerializationFlag(int flag) { 3635 final int actions = AccessibilityAction.sStandardActions.size(); 3636 for (int i = 0; i < actions; i++) { 3637 AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i); 3638 if (flag == currentAction.mSerializationFlag) { 3639 return currentAction; 3640 } 3641 } 3642 3643 return null; 3644 } 3645 3646 private void addStandardActions(int serializationIdMask) { 3647 int remainingIds = serializationIdMask; 3648 while (remainingIds > 0) { 3649 final int id = 1 << Integer.numberOfTrailingZeros(remainingIds); 3650 remainingIds &= ~id; 3651 AccessibilityAction action = getActionSingletonBySerializationFlag(id); 3652 addAction(action); 3653 } 3654 } 3655 3656 /** 3657 * Gets the human readable action symbolic name. 3658 * 3659 * @param action The action. 3660 * @return The symbolic name. 3661 */ 3662 private static String getActionSymbolicName(int action) { 3663 switch (action) { 3664 case ACTION_FOCUS: 3665 return "ACTION_FOCUS"; 3666 case ACTION_CLEAR_FOCUS: 3667 return "ACTION_CLEAR_FOCUS"; 3668 case ACTION_SELECT: 3669 return "ACTION_SELECT"; 3670 case ACTION_CLEAR_SELECTION: 3671 return "ACTION_CLEAR_SELECTION"; 3672 case ACTION_CLICK: 3673 return "ACTION_CLICK"; 3674 case ACTION_LONG_CLICK: 3675 return "ACTION_LONG_CLICK"; 3676 case ACTION_ACCESSIBILITY_FOCUS: 3677 return "ACTION_ACCESSIBILITY_FOCUS"; 3678 case ACTION_CLEAR_ACCESSIBILITY_FOCUS: 3679 return "ACTION_CLEAR_ACCESSIBILITY_FOCUS"; 3680 case ACTION_NEXT_AT_MOVEMENT_GRANULARITY: 3681 return "ACTION_NEXT_AT_MOVEMENT_GRANULARITY"; 3682 case ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: 3683 return "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY"; 3684 case ACTION_NEXT_HTML_ELEMENT: 3685 return "ACTION_NEXT_HTML_ELEMENT"; 3686 case ACTION_PREVIOUS_HTML_ELEMENT: 3687 return "ACTION_PREVIOUS_HTML_ELEMENT"; 3688 case ACTION_SCROLL_FORWARD: 3689 return "ACTION_SCROLL_FORWARD"; 3690 case ACTION_SCROLL_BACKWARD: 3691 return "ACTION_SCROLL_BACKWARD"; 3692 case ACTION_CUT: 3693 return "ACTION_CUT"; 3694 case ACTION_COPY: 3695 return "ACTION_COPY"; 3696 case ACTION_PASTE: 3697 return "ACTION_PASTE"; 3698 case ACTION_SET_SELECTION: 3699 return "ACTION_SET_SELECTION"; 3700 case ACTION_EXPAND: 3701 return "ACTION_EXPAND"; 3702 case ACTION_COLLAPSE: 3703 return "ACTION_COLLAPSE"; 3704 case ACTION_DISMISS: 3705 return "ACTION_DISMISS"; 3706 case ACTION_SET_TEXT: 3707 return "ACTION_SET_TEXT"; 3708 case R.id.accessibilityActionShowOnScreen: 3709 return "ACTION_SHOW_ON_SCREEN"; 3710 case R.id.accessibilityActionScrollToPosition: 3711 return "ACTION_SCROLL_TO_POSITION"; 3712 case R.id.accessibilityActionScrollUp: 3713 return "ACTION_SCROLL_UP"; 3714 case R.id.accessibilityActionScrollLeft: 3715 return "ACTION_SCROLL_LEFT"; 3716 case R.id.accessibilityActionScrollDown: 3717 return "ACTION_SCROLL_DOWN"; 3718 case R.id.accessibilityActionScrollRight: 3719 return "ACTION_SCROLL_RIGHT"; 3720 case R.id.accessibilityActionSetProgress: 3721 return "ACTION_SET_PROGRESS"; 3722 case R.id.accessibilityActionContextClick: 3723 return "ACTION_CONTEXT_CLICK"; 3724 case R.id.accessibilityActionShowTooltip: 3725 return "ACTION_SHOW_TOOLTIP"; 3726 case R.id.accessibilityActionHideTooltip: 3727 return "ACTION_HIDE_TOOLTIP"; 3728 default: 3729 return "ACTION_UNKNOWN"; 3730 } 3731 } 3732 3733 /** 3734 * Gets the human readable movement granularity symbolic name. 3735 * 3736 * @param granularity The granularity. 3737 * @return The symbolic name. 3738 */ 3739 private static String getMovementGranularitySymbolicName(int granularity) { 3740 switch (granularity) { 3741 case MOVEMENT_GRANULARITY_CHARACTER: 3742 return "MOVEMENT_GRANULARITY_CHARACTER"; 3743 case MOVEMENT_GRANULARITY_WORD: 3744 return "MOVEMENT_GRANULARITY_WORD"; 3745 case MOVEMENT_GRANULARITY_LINE: 3746 return "MOVEMENT_GRANULARITY_LINE"; 3747 case MOVEMENT_GRANULARITY_PARAGRAPH: 3748 return "MOVEMENT_GRANULARITY_PARAGRAPH"; 3749 case MOVEMENT_GRANULARITY_PAGE: 3750 return "MOVEMENT_GRANULARITY_PAGE"; 3751 default: 3752 throw new IllegalArgumentException("Unknown movement granularity: " + granularity); 3753 } 3754 } 3755 3756 private boolean canPerformRequestOverConnection(long accessibilityNodeId) { 3757 return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) 3758 && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID) 3759 && (mConnectionId != UNDEFINED_CONNECTION_ID)); 3760 } 3761 3762 @Override 3763 public boolean equals(Object object) { 3764 if (this == object) { 3765 return true; 3766 } 3767 if (object == null) { 3768 return false; 3769 } 3770 if (getClass() != object.getClass()) { 3771 return false; 3772 } 3773 AccessibilityNodeInfo other = (AccessibilityNodeInfo) object; 3774 if (mSourceNodeId != other.mSourceNodeId) { 3775 return false; 3776 } 3777 if (mWindowId != other.mWindowId) { 3778 return false; 3779 } 3780 return true; 3781 } 3782 3783 @Override 3784 public int hashCode() { 3785 final int prime = 31; 3786 int result = 1; 3787 result = prime * result + getAccessibilityViewId(mSourceNodeId); 3788 result = prime * result + getVirtualDescendantId(mSourceNodeId); 3789 result = prime * result + mWindowId; 3790 return result; 3791 } 3792 3793 @Override 3794 public String toString() { 3795 StringBuilder builder = new StringBuilder(); 3796 builder.append(super.toString()); 3797 3798 if (DEBUG) { 3799 builder.append("; sourceNodeId: " + mSourceNodeId); 3800 builder.append("; windowId: " + mWindowId); 3801 builder.append("; accessibilityViewId: ").append(getAccessibilityViewId(mSourceNodeId)); 3802 builder.append("; virtualDescendantId: ").append(getVirtualDescendantId(mSourceNodeId)); 3803 builder.append("; mParentNodeId: " + mParentNodeId); 3804 builder.append("; traversalBefore: ").append(mTraversalBefore); 3805 builder.append("; traversalAfter: ").append(mTraversalAfter); 3806 3807 int granularities = mMovementGranularities; 3808 builder.append("; MovementGranularities: ["); 3809 while (granularities != 0) { 3810 final int granularity = 1 << Integer.numberOfTrailingZeros(granularities); 3811 granularities &= ~granularity; 3812 builder.append(getMovementGranularitySymbolicName(granularity)); 3813 if (granularities != 0) { 3814 builder.append(", "); 3815 } 3816 } 3817 builder.append("]"); 3818 3819 builder.append("; childAccessibilityIds: ["); 3820 final LongArray childIds = mChildNodeIds; 3821 if (childIds != null) { 3822 for (int i = 0, count = childIds.size(); i < count; i++) { 3823 builder.append(childIds.get(i)); 3824 if (i < count - 1) { 3825 builder.append(", "); 3826 } 3827 } 3828 } 3829 builder.append("]"); 3830 } 3831 3832 builder.append("; boundsInParent: ").append(mBoundsInParent); 3833 builder.append("; boundsInScreen: ").append(mBoundsInScreen); 3834 3835 builder.append("; packageName: ").append(mPackageName); 3836 builder.append("; className: ").append(mClassName); 3837 builder.append("; text: ").append(mText); 3838 builder.append("; error: ").append(mError); 3839 builder.append("; maxTextLength: ").append(mMaxTextLength); 3840 builder.append("; contentDescription: ").append(mContentDescription); 3841 builder.append("; tooltipText: ").append(mTooltipText); 3842 builder.append("; viewIdResName: ").append(mViewIdResourceName); 3843 3844 builder.append("; checkable: ").append(isCheckable()); 3845 builder.append("; checked: ").append(isChecked()); 3846 builder.append("; focusable: ").append(isFocusable()); 3847 builder.append("; focused: ").append(isFocused()); 3848 builder.append("; selected: ").append(isSelected()); 3849 builder.append("; clickable: ").append(isClickable()); 3850 builder.append("; longClickable: ").append(isLongClickable()); 3851 builder.append("; contextClickable: ").append(isContextClickable()); 3852 builder.append("; enabled: ").append(isEnabled()); 3853 builder.append("; password: ").append(isPassword()); 3854 builder.append("; scrollable: ").append(isScrollable()); 3855 builder.append("; importantForAccessibility: ").append(isImportantForAccessibility()); 3856 builder.append("; actions: ").append(mActions); 3857 3858 return builder.toString(); 3859 } 3860 3861 private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) { 3862 if (!canPerformRequestOverConnection(accessibilityId)) { 3863 return null; 3864 } 3865 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 3866 return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, 3867 mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS 3868 | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null); 3869 } 3870 3871 /** 3872 * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}. 3873 * Each action has a unique id that is mandatory and optional data. 3874 * <p> 3875 * There are three categories of actions: 3876 * <ul> 3877 * <li><strong>Standard actions</strong> - These are actions that are reported and 3878 * handled by the standard UI widgets in the platform. For each standard action 3879 * there is a static constant defined in this class, e.g. {@link #ACTION_FOCUS}. 3880 * These actions will have {@code null} labels. 3881 * </li> 3882 * <li><strong>Custom actions action</strong> - These are actions that are reported 3883 * and handled by custom widgets. i.e. ones that are not part of the UI toolkit. For 3884 * example, an application may define a custom action for clearing the user history. 3885 * </li> 3886 * <li><strong>Overriden standard actions</strong> - These are actions that override 3887 * standard actions to customize them. For example, an app may add a label to the 3888 * standard {@link #ACTION_CLICK} action to announce that this action clears browsing history. 3889 * </ul> 3890 * </p> 3891 * <p> 3892 * Actions are typically added to an {@link AccessibilityNodeInfo} by using 3893 * {@link AccessibilityNodeInfo#addAction(AccessibilityAction)} within 3894 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} and are performed 3895 * within {@link View#performAccessibilityAction(int, Bundle)}. 3896 * </p> 3897 * <p class="note"> 3898 * <strong>Note:</strong> Views which support these actions should invoke 3899 * {@link View#setImportantForAccessibility(int)} with 3900 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_YES} to ensure an {@link AccessibilityService} 3901 * can discover the set of supported actions. 3902 * </p> 3903 */ 3904 public static final class AccessibilityAction { 3905 3906 /** @hide */ 3907 public static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>(); 3908 3909 /** 3910 * Action that gives input focus to the node. 3911 */ 3912 public static final AccessibilityAction ACTION_FOCUS = 3913 new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS); 3914 3915 /** 3916 * Action that clears input focus of the node. 3917 */ 3918 public static final AccessibilityAction ACTION_CLEAR_FOCUS = 3919 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 3920 3921 /** 3922 * Action that selects the node. 3923 */ 3924 public static final AccessibilityAction ACTION_SELECT = 3925 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SELECT); 3926 3927 /** 3928 * Action that deselects the node. 3929 */ 3930 public static final AccessibilityAction ACTION_CLEAR_SELECTION = 3931 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 3932 3933 /** 3934 * Action that clicks on the node info. 3935 */ 3936 public static final AccessibilityAction ACTION_CLICK = 3937 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK); 3938 3939 /** 3940 * Action that long clicks on the node. 3941 */ 3942 public static final AccessibilityAction ACTION_LONG_CLICK = 3943 new AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 3944 3945 /** 3946 * Action that gives accessibility focus to the node. 3947 */ 3948 public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS = 3949 new AccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 3950 3951 /** 3952 * Action that clears accessibility focus of the node. 3953 */ 3954 public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS = 3955 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 3956 3957 /** 3958 * Action that requests to go to the next entity in this node's text 3959 * at a given movement granularity. For example, move to the next character, 3960 * word, etc. 3961 * <p> 3962 * <strong>Arguments:</strong> 3963 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 3964 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, 3965 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 3966 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 3967 * <strong>Example:</strong> Move to the previous character and do not extend selection. 3968 * <code><pre><p> 3969 * Bundle arguments = new Bundle(); 3970 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 3971 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 3972 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 3973 * false); 3974 * info.performAction(AccessibilityAction.ACTION_NEXT_AT_MOVEMENT_GRANULARITY.getId(), 3975 * arguments); 3976 * </code></pre></p> 3977 * </p> 3978 * 3979 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 3980 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 3981 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 3982 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 3983 * 3984 * @see AccessibilityNodeInfo#setMovementGranularities(int) 3985 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 3986 * @see AccessibilityNodeInfo#getMovementGranularities() 3987 * AccessibilityNodeInfo.getMovementGranularities() 3988 * 3989 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER 3990 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 3991 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD 3992 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 3993 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE 3994 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE 3995 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH 3996 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH 3997 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE 3998 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE 3999 */ 4000 public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 4001 new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 4002 4003 /** 4004 * Action that requests to go to the previous entity in this node's text 4005 * at a given movement granularity. For example, move to the next character, 4006 * word, etc. 4007 * <p> 4008 * <strong>Arguments:</strong> 4009 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 4010 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}, 4011 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 4012 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}<br> 4013 * <strong>Example:</strong> Move to the next character and do not extend selection. 4014 * <code><pre><p> 4015 * Bundle arguments = new Bundle(); 4016 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, 4017 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER); 4018 * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, 4019 * false); 4020 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY.getId(), 4021 * arguments); 4022 * </code></pre></p> 4023 * </p> 4024 * 4025 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 4026 * AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT 4027 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 4028 * AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN 4029 * 4030 * @see AccessibilityNodeInfo#setMovementGranularities(int) 4031 * AccessibilityNodeInfo.setMovementGranularities(int) 4032 * @see AccessibilityNodeInfo#getMovementGranularities() 4033 * AccessibilityNodeInfo.getMovementGranularities() 4034 * 4035 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_CHARACTER 4036 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 4037 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_WORD 4038 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 4039 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_LINE 4040 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_LINE 4041 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PARAGRAPH 4042 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH 4043 * @see AccessibilityNodeInfo#MOVEMENT_GRANULARITY_PAGE 4044 * AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE 4045 */ 4046 public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 4047 new AccessibilityAction( 4048 AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 4049 4050 /** 4051 * Action to move to the next HTML element of a given type. For example, move 4052 * to the BUTTON, INPUT, TABLE, etc. 4053 * <p> 4054 * <strong>Arguments:</strong> 4055 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING 4056 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 4057 * <strong>Example:</strong> 4058 * <code><pre><p> 4059 * Bundle arguments = new Bundle(); 4060 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 4061 * info.performAction(AccessibilityAction.ACTION_NEXT_HTML_ELEMENT.getId(), arguments); 4062 * </code></pre></p> 4063 * </p> 4064 */ 4065 public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT = 4066 new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT); 4067 4068 /** 4069 * Action to move to the previous HTML element of a given type. For example, move 4070 * to the BUTTON, INPUT, TABLE, etc. 4071 * <p> 4072 * <strong>Arguments:</strong> 4073 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_HTML_ELEMENT_STRING 4074 * AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING}<br> 4075 * <strong>Example:</strong> 4076 * <code><pre><p> 4077 * Bundle arguments = new Bundle(); 4078 * arguments.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_HTML_ELEMENT_STRING, "BUTTON"); 4079 * info.performAction(AccessibilityAction.ACTION_PREVIOUS_HTML_ELEMENT.getId(), arguments); 4080 * </code></pre></p> 4081 * </p> 4082 */ 4083 public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT = 4084 new AccessibilityAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT); 4085 4086 /** 4087 * Action to scroll the node content forward. 4088 */ 4089 public static final AccessibilityAction ACTION_SCROLL_FORWARD = 4090 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); 4091 4092 /** 4093 * Action to scroll the node content backward. 4094 */ 4095 public static final AccessibilityAction ACTION_SCROLL_BACKWARD = 4096 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); 4097 4098 /** 4099 * Action to copy the current selection to the clipboard. 4100 */ 4101 public static final AccessibilityAction ACTION_COPY = 4102 new AccessibilityAction(AccessibilityNodeInfo.ACTION_COPY); 4103 4104 /** 4105 * Action to paste the current clipboard content. 4106 */ 4107 public static final AccessibilityAction ACTION_PASTE = 4108 new AccessibilityAction(AccessibilityNodeInfo.ACTION_PASTE); 4109 4110 /** 4111 * Action to cut the current selection and place it to the clipboard. 4112 */ 4113 public static final AccessibilityAction ACTION_CUT = 4114 new AccessibilityAction(AccessibilityNodeInfo.ACTION_CUT); 4115 4116 /** 4117 * Action to set the selection. Performing this action with no arguments 4118 * clears the selection. 4119 * <p> 4120 * <strong>Arguments:</strong> 4121 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT 4122 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT}, 4123 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT 4124 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT}<br> 4125 * <strong>Example:</strong> 4126 * <code><pre><p> 4127 * Bundle arguments = new Bundle(); 4128 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1); 4129 * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2); 4130 * info.performAction(AccessibilityAction.ACTION_SET_SELECTION.getId(), arguments); 4131 * </code></pre></p> 4132 * </p> 4133 * 4134 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_START_INT 4135 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT 4136 * @see AccessibilityNodeInfo#ACTION_ARGUMENT_SELECTION_END_INT 4137 * AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT 4138 */ 4139 public static final AccessibilityAction ACTION_SET_SELECTION = 4140 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 4141 4142 /** 4143 * Action to expand an expandable node. 4144 */ 4145 public static final AccessibilityAction ACTION_EXPAND = 4146 new AccessibilityAction(AccessibilityNodeInfo.ACTION_EXPAND); 4147 4148 /** 4149 * Action to collapse an expandable node. 4150 */ 4151 public static final AccessibilityAction ACTION_COLLAPSE = 4152 new AccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE); 4153 4154 /** 4155 * Action to dismiss a dismissable node. 4156 */ 4157 public static final AccessibilityAction ACTION_DISMISS = 4158 new AccessibilityAction(AccessibilityNodeInfo.ACTION_DISMISS); 4159 4160 /** 4161 * Action that sets the text of the node. Performing the action without argument, 4162 * using <code> null</code> or empty {@link CharSequence} will clear the text. This 4163 * action will also put the cursor at the end of text. 4164 * <p> 4165 * <strong>Arguments:</strong> 4166 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE 4167 * AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br> 4168 * <strong>Example:</strong> 4169 * <code><pre><p> 4170 * Bundle arguments = new Bundle(); 4171 * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, 4172 * "android"); 4173 * info.performAction(AccessibilityAction.ACTION_SET_TEXT.getId(), arguments); 4174 * </code></pre></p> 4175 */ 4176 public static final AccessibilityAction ACTION_SET_TEXT = 4177 new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT); 4178 4179 /** 4180 * Action that requests the node make its bounding rectangle visible 4181 * on the screen, scrolling if necessary just enough. 4182 * 4183 * @see View#requestRectangleOnScreen(Rect) 4184 */ 4185 public static final AccessibilityAction ACTION_SHOW_ON_SCREEN = 4186 new AccessibilityAction(R.id.accessibilityActionShowOnScreen); 4187 4188 /** 4189 * Action that scrolls the node to make the specified collection 4190 * position visible on screen. 4191 * <p> 4192 * <strong>Arguments:</strong> 4193 * <ul> 4194 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li> 4195 * <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li> 4196 * <ul> 4197 * 4198 * @see AccessibilityNodeInfo#getCollectionInfo() 4199 */ 4200 public static final AccessibilityAction ACTION_SCROLL_TO_POSITION = 4201 new AccessibilityAction(R.id.accessibilityActionScrollToPosition); 4202 4203 /** 4204 * Action to scroll the node content up. 4205 */ 4206 public static final AccessibilityAction ACTION_SCROLL_UP = 4207 new AccessibilityAction(R.id.accessibilityActionScrollUp); 4208 4209 /** 4210 * Action to scroll the node content left. 4211 */ 4212 public static final AccessibilityAction ACTION_SCROLL_LEFT = 4213 new AccessibilityAction(R.id.accessibilityActionScrollLeft); 4214 4215 /** 4216 * Action to scroll the node content down. 4217 */ 4218 public static final AccessibilityAction ACTION_SCROLL_DOWN = 4219 new AccessibilityAction(R.id.accessibilityActionScrollDown); 4220 4221 /** 4222 * Action to scroll the node content right. 4223 */ 4224 public static final AccessibilityAction ACTION_SCROLL_RIGHT = 4225 new AccessibilityAction(R.id.accessibilityActionScrollRight); 4226 4227 /** 4228 * Action that context clicks the node. 4229 */ 4230 public static final AccessibilityAction ACTION_CONTEXT_CLICK = 4231 new AccessibilityAction(R.id.accessibilityActionContextClick); 4232 4233 /** 4234 * Action that sets progress between {@link RangeInfo#getMin() RangeInfo.getMin()} and 4235 * {@link RangeInfo#getMax() RangeInfo.getMax()}. It should use the same value type as 4236 * {@link RangeInfo#getType() RangeInfo.getType()} 4237 * <p> 4238 * <strong>Arguments:</strong> 4239 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_PROGRESS_VALUE} 4240 * 4241 * @see RangeInfo 4242 */ 4243 public static final AccessibilityAction ACTION_SET_PROGRESS = 4244 new AccessibilityAction(R.id.accessibilityActionSetProgress); 4245 4246 /** 4247 * Action to move a window to a new location. 4248 * <p> 4249 * <strong>Arguments:</strong> 4250 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_X} 4251 * {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y} 4252 */ 4253 public static final AccessibilityAction ACTION_MOVE_WINDOW = 4254 new AccessibilityAction(R.id.accessibilityActionMoveWindow); 4255 4256 /** 4257 * Action to show a tooltip. A node should expose this action only for views with tooltip 4258 * text that but are not currently showing a tooltip. 4259 */ 4260 public static final AccessibilityAction ACTION_SHOW_TOOLTIP = 4261 new AccessibilityAction(R.id.accessibilityActionShowTooltip); 4262 4263 /** 4264 * Action to hide a tooltip. A node should expose this action only for views that are 4265 * currently showing a tooltip. 4266 */ 4267 public static final AccessibilityAction ACTION_HIDE_TOOLTIP = 4268 new AccessibilityAction(R.id.accessibilityActionHideTooltip); 4269 4270 private final int mActionId; 4271 private final CharSequence mLabel; 4272 4273 /** @hide */ 4274 public int mSerializationFlag = -1; 4275 4276 /** 4277 * Creates a new AccessibilityAction. For adding a standard action without a specific label, 4278 * use the static constants. 4279 * 4280 * You can also override the description for one the standard actions. Below is an example 4281 * how to override the standard click action by adding a custom label: 4282 * <pre> 4283 * AccessibilityAction action = new AccessibilityAction( 4284 * AccessibilityAction.ACTION_CLICK.getId(), getLocalizedLabel()); 4285 * node.addAction(action); 4286 * </pre> 4287 * 4288 * @param actionId The id for this action. This should either be one of the 4289 * standard actions or a specific action for your app. In that case it is 4290 * required to use a resource identifier. 4291 * @param label The label for the new AccessibilityAction. 4292 */ 4293 public AccessibilityAction(int actionId, @Nullable CharSequence label) { 4294 if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) { 4295 throw new IllegalArgumentException("Invalid standard action id"); 4296 } 4297 4298 mActionId = actionId; 4299 mLabel = label; 4300 } 4301 4302 /** 4303 * Constructor for a {@link #sStandardActions standard} action 4304 */ 4305 private AccessibilityAction(int standardActionId) { 4306 this(standardActionId, null); 4307 4308 mSerializationFlag = (int) bitAt(sStandardActions.size()); 4309 sStandardActions.add(this); 4310 } 4311 4312 /** 4313 * Gets the id for this action. 4314 * 4315 * @return The action id. 4316 */ 4317 public int getId() { 4318 return mActionId; 4319 } 4320 4321 /** 4322 * Gets the label for this action. Its purpose is to describe the 4323 * action to user. 4324 * 4325 * @return The label. 4326 */ 4327 public CharSequence getLabel() { 4328 return mLabel; 4329 } 4330 4331 @Override 4332 public int hashCode() { 4333 return mActionId; 4334 } 4335 4336 @Override 4337 public boolean equals(Object other) { 4338 if (other == null) { 4339 return false; 4340 } 4341 4342 if (other == this) { 4343 return true; 4344 } 4345 4346 if (getClass() != other.getClass()) { 4347 return false; 4348 } 4349 4350 return mActionId == ((AccessibilityAction)other).mActionId; 4351 } 4352 4353 @Override 4354 public String toString() { 4355 return "AccessibilityAction: " + getActionSymbolicName(mActionId) + " - " + mLabel; 4356 } 4357 } 4358 4359 /** 4360 * Class with information if a node is a range. Use 4361 * {@link RangeInfo#obtain(int, float, float, float)} to get an instance. Recycling is 4362 * handled by the {@link AccessibilityNodeInfo} to which this object is attached. 4363 */ 4364 public static final class RangeInfo { 4365 private static final int MAX_POOL_SIZE = 10; 4366 4367 /** Range type: integer. */ 4368 public static final int RANGE_TYPE_INT = 0; 4369 /** Range type: float. */ 4370 public static final int RANGE_TYPE_FLOAT = 1; 4371 /** Range type: percent with values from zero to one.*/ 4372 public static final int RANGE_TYPE_PERCENT = 2; 4373 4374 private static final SynchronizedPool<RangeInfo> sPool = 4375 new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE); 4376 4377 private int mType; 4378 private float mMin; 4379 private float mMax; 4380 private float mCurrent; 4381 4382 /** 4383 * Obtains a pooled instance that is a clone of another one. 4384 * 4385 * @param other The instance to clone. 4386 * 4387 * @hide 4388 */ 4389 public static RangeInfo obtain(RangeInfo other) { 4390 return obtain(other.mType, other.mMin, other.mMax, other.mCurrent); 4391 } 4392 4393 /** 4394 * Obtains a pooled instance. 4395 * 4396 * @param type The type of the range. 4397 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no 4398 * minimum. 4399 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no 4400 * maximum. 4401 * @param current The current value. 4402 */ 4403 public static RangeInfo obtain(int type, float min, float max, float current) { 4404 RangeInfo info = sPool.acquire(); 4405 if (info == null) { 4406 return new RangeInfo(type, min, max, current); 4407 } 4408 4409 info.mType = type; 4410 info.mMin = min; 4411 info.mMax = max; 4412 info.mCurrent = current; 4413 return info; 4414 } 4415 4416 /** 4417 * Creates a new range. 4418 * 4419 * @param type The type of the range. 4420 * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no 4421 * minimum. 4422 * @param max The maximum value. Use {@code Float.POSITIVE_INFINITY} if the range has no 4423 * maximum. 4424 * @param current The current value. 4425 */ 4426 private RangeInfo(int type, float min, float max, float current) { 4427 mType = type; 4428 mMin = min; 4429 mMax = max; 4430 mCurrent = current; 4431 } 4432 4433 /** 4434 * Gets the range type. 4435 * 4436 * @return The range type. 4437 * 4438 * @see #RANGE_TYPE_INT 4439 * @see #RANGE_TYPE_FLOAT 4440 * @see #RANGE_TYPE_PERCENT 4441 */ 4442 public int getType() { 4443 return mType; 4444 } 4445 4446 /** 4447 * Gets the minimum value. 4448 * 4449 * @return The minimum value, or {@code Float.NEGATIVE_INFINITY} if no minimum exists. 4450 */ 4451 public float getMin() { 4452 return mMin; 4453 } 4454 4455 /** 4456 * Gets the maximum value. 4457 * 4458 * @return The maximum value, or {@code Float.POSITIVE_INFINITY} if no maximum exists. 4459 */ 4460 public float getMax() { 4461 return mMax; 4462 } 4463 4464 /** 4465 * Gets the current value. 4466 * 4467 * @return The current value. 4468 */ 4469 public float getCurrent() { 4470 return mCurrent; 4471 } 4472 4473 /** 4474 * Recycles this instance. 4475 */ 4476 void recycle() { 4477 clear(); 4478 sPool.release(this); 4479 } 4480 4481 private void clear() { 4482 mType = 0; 4483 mMin = 0; 4484 mMax = 0; 4485 mCurrent = 0; 4486 } 4487 } 4488 4489 /** 4490 * Class with information if a node is a collection. Use 4491 * {@link CollectionInfo#obtain(int, int, boolean)} to get an instance. Recycling is 4492 * handled by the {@link AccessibilityNodeInfo} to which this object is attached. 4493 * <p> 4494 * A collection of items has rows and columns and may be hierarchical. 4495 * For example, a horizontal list is a collection with one column, as 4496 * many rows as the list items, and is not hierarchical; A table is a 4497 * collection with several rows, several columns, and is not hierarchical; 4498 * A vertical tree is a hierarchical collection with one column and 4499 * as many rows as the first level children. 4500 * </p> 4501 */ 4502 public static final class CollectionInfo { 4503 /** Selection mode where items are not selectable. */ 4504 public static final int SELECTION_MODE_NONE = 0; 4505 4506 /** Selection mode where a single item may be selected. */ 4507 public static final int SELECTION_MODE_SINGLE = 1; 4508 4509 /** Selection mode where multiple items may be selected. */ 4510 public static final int SELECTION_MODE_MULTIPLE = 2; 4511 4512 private static final int MAX_POOL_SIZE = 20; 4513 4514 private static final SynchronizedPool<CollectionInfo> sPool = 4515 new SynchronizedPool<>(MAX_POOL_SIZE); 4516 4517 private int mRowCount; 4518 private int mColumnCount; 4519 private boolean mHierarchical; 4520 private int mSelectionMode; 4521 4522 /** 4523 * Obtains a pooled instance that is a clone of another one. 4524 * 4525 * @param other The instance to clone. 4526 * @hide 4527 */ 4528 public static CollectionInfo obtain(CollectionInfo other) { 4529 return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical, 4530 other.mSelectionMode); 4531 } 4532 4533 /** 4534 * Obtains a pooled instance. 4535 * 4536 * @param rowCount The number of rows. 4537 * @param columnCount The number of columns. 4538 * @param hierarchical Whether the collection is hierarchical. 4539 */ 4540 public static CollectionInfo obtain(int rowCount, int columnCount, 4541 boolean hierarchical) { 4542 return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE); 4543 } 4544 4545 /** 4546 * Obtains a pooled instance. 4547 * 4548 * @param rowCount The number of rows. 4549 * @param columnCount The number of columns. 4550 * @param hierarchical Whether the collection is hierarchical. 4551 * @param selectionMode The collection's selection mode, one of: 4552 * <ul> 4553 * <li>{@link #SELECTION_MODE_NONE} 4554 * <li>{@link #SELECTION_MODE_SINGLE} 4555 * <li>{@link #SELECTION_MODE_MULTIPLE} 4556 * </ul> 4557 */ 4558 public static CollectionInfo obtain(int rowCount, int columnCount, 4559 boolean hierarchical, int selectionMode) { 4560 final CollectionInfo info = sPool.acquire(); 4561 if (info == null) { 4562 return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode); 4563 } 4564 4565 info.mRowCount = rowCount; 4566 info.mColumnCount = columnCount; 4567 info.mHierarchical = hierarchical; 4568 info.mSelectionMode = selectionMode; 4569 return info; 4570 } 4571 4572 /** 4573 * Creates a new instance. 4574 * 4575 * @param rowCount The number of rows. 4576 * @param columnCount The number of columns. 4577 * @param hierarchical Whether the collection is hierarchical. 4578 * @param selectionMode The collection's selection mode. 4579 */ 4580 private CollectionInfo(int rowCount, int columnCount, boolean hierarchical, 4581 int selectionMode) { 4582 mRowCount = rowCount; 4583 mColumnCount = columnCount; 4584 mHierarchical = hierarchical; 4585 mSelectionMode = selectionMode; 4586 } 4587 4588 /** 4589 * Gets the number of rows. 4590 * 4591 * @return The row count. 4592 */ 4593 public int getRowCount() { 4594 return mRowCount; 4595 } 4596 4597 /** 4598 * Gets the number of columns. 4599 * 4600 * @return The column count. 4601 */ 4602 public int getColumnCount() { 4603 return mColumnCount; 4604 } 4605 4606 /** 4607 * Gets if the collection is a hierarchically ordered. 4608 * 4609 * @return Whether the collection is hierarchical. 4610 */ 4611 public boolean isHierarchical() { 4612 return mHierarchical; 4613 } 4614 4615 /** 4616 * Gets the collection's selection mode. 4617 * 4618 * @return The collection's selection mode, one of: 4619 * <ul> 4620 * <li>{@link #SELECTION_MODE_NONE} 4621 * <li>{@link #SELECTION_MODE_SINGLE} 4622 * <li>{@link #SELECTION_MODE_MULTIPLE} 4623 * </ul> 4624 */ 4625 public int getSelectionMode() { 4626 return mSelectionMode; 4627 } 4628 4629 /** 4630 * Recycles this instance. 4631 */ 4632 void recycle() { 4633 clear(); 4634 sPool.release(this); 4635 } 4636 4637 private void clear() { 4638 mRowCount = 0; 4639 mColumnCount = 0; 4640 mHierarchical = false; 4641 mSelectionMode = SELECTION_MODE_NONE; 4642 } 4643 } 4644 4645 /** 4646 * Class with information if a node is a collection item. Use 4647 * {@link CollectionItemInfo#obtain(int, int, int, int, boolean)} 4648 * to get an instance. Recycling is handled by the {@link AccessibilityNodeInfo} to which this 4649 * object is attached. 4650 * <p> 4651 * A collection item is contained in a collection, it starts at 4652 * a given row and column in the collection, and spans one or 4653 * more rows and columns. For example, a header of two related 4654 * table columns starts at the first row and the first column, 4655 * spans one row and two columns. 4656 * </p> 4657 */ 4658 public static final class CollectionItemInfo { 4659 private static final int MAX_POOL_SIZE = 20; 4660 4661 private static final SynchronizedPool<CollectionItemInfo> sPool = 4662 new SynchronizedPool<>(MAX_POOL_SIZE); 4663 4664 /** 4665 * Obtains a pooled instance that is a clone of another one. 4666 * 4667 * @param other The instance to clone. 4668 * @hide 4669 */ 4670 public static CollectionItemInfo obtain(CollectionItemInfo other) { 4671 return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex, 4672 other.mColumnSpan, other.mHeading, other.mSelected); 4673 } 4674 4675 /** 4676 * Obtains a pooled instance. 4677 * 4678 * @param rowIndex The row index at which the item is located. 4679 * @param rowSpan The number of rows the item spans. 4680 * @param columnIndex The column index at which the item is located. 4681 * @param columnSpan The number of columns the item spans. 4682 * @param heading Whether the item is a heading. (Prefer 4683 * {@link AccessibilityNodeInfo#setHeading(boolean)}). 4684 */ 4685 public static CollectionItemInfo obtain(int rowIndex, int rowSpan, 4686 int columnIndex, int columnSpan, boolean heading) { 4687 return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false); 4688 } 4689 4690 /** 4691 * Obtains a pooled instance. 4692 * 4693 * @param rowIndex The row index at which the item is located. 4694 * @param rowSpan The number of rows the item spans. 4695 * @param columnIndex The column index at which the item is located. 4696 * @param columnSpan The number of columns the item spans. 4697 * @param heading Whether the item is a heading. (Prefer 4698 * {@link AccessibilityNodeInfo#setHeading(boolean)}) 4699 * @param selected Whether the item is selected. 4700 */ 4701 public static CollectionItemInfo obtain(int rowIndex, int rowSpan, 4702 int columnIndex, int columnSpan, boolean heading, boolean selected) { 4703 final CollectionItemInfo info = sPool.acquire(); 4704 if (info == null) { 4705 return new CollectionItemInfo( 4706 rowIndex, rowSpan, columnIndex, columnSpan, heading, selected); 4707 } 4708 4709 info.mRowIndex = rowIndex; 4710 info.mRowSpan = rowSpan; 4711 info.mColumnIndex = columnIndex; 4712 info.mColumnSpan = columnSpan; 4713 info.mHeading = heading; 4714 info.mSelected = selected; 4715 return info; 4716 } 4717 4718 private boolean mHeading; 4719 private int mColumnIndex; 4720 private int mRowIndex; 4721 private int mColumnSpan; 4722 private int mRowSpan; 4723 private boolean mSelected; 4724 4725 /** 4726 * Creates a new instance. 4727 * 4728 * @param rowIndex The row index at which the item is located. 4729 * @param rowSpan The number of rows the item spans. 4730 * @param columnIndex The column index at which the item is located. 4731 * @param columnSpan The number of columns the item spans. 4732 * @param heading Whether the item is a heading. 4733 */ 4734 private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan, 4735 boolean heading, boolean selected) { 4736 mRowIndex = rowIndex; 4737 mRowSpan = rowSpan; 4738 mColumnIndex = columnIndex; 4739 mColumnSpan = columnSpan; 4740 mHeading = heading; 4741 mSelected = selected; 4742 } 4743 4744 /** 4745 * Gets the column index at which the item is located. 4746 * 4747 * @return The column index. 4748 */ 4749 public int getColumnIndex() { 4750 return mColumnIndex; 4751 } 4752 4753 /** 4754 * Gets the row index at which the item is located. 4755 * 4756 * @return The row index. 4757 */ 4758 public int getRowIndex() { 4759 return mRowIndex; 4760 } 4761 4762 /** 4763 * Gets the number of columns the item spans. 4764 * 4765 * @return The column span. 4766 */ 4767 public int getColumnSpan() { 4768 return mColumnSpan; 4769 } 4770 4771 /** 4772 * Gets the number of rows the item spans. 4773 * 4774 * @return The row span. 4775 */ 4776 public int getRowSpan() { 4777 return mRowSpan; 4778 } 4779 4780 /** 4781 * Gets if the collection item is a heading. For example, section 4782 * heading, table header, etc. 4783 * 4784 * @return If the item is a heading. 4785 * @deprecated Use {@link AccessibilityNodeInfo#isHeading()} 4786 */ 4787 public boolean isHeading() { 4788 return mHeading; 4789 } 4790 4791 /** 4792 * Gets if the collection item is selected. 4793 * 4794 * @return If the item is selected. 4795 */ 4796 public boolean isSelected() { 4797 return mSelected; 4798 } 4799 4800 /** 4801 * Recycles this instance. 4802 */ 4803 void recycle() { 4804 clear(); 4805 sPool.release(this); 4806 } 4807 4808 private void clear() { 4809 mColumnIndex = 0; 4810 mColumnSpan = 0; 4811 mRowIndex = 0; 4812 mRowSpan = 0; 4813 mHeading = false; 4814 mSelected = false; 4815 } 4816 } 4817 4818 /** 4819 * @see android.os.Parcelable.Creator 4820 */ 4821 public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR = 4822 new Parcelable.Creator<AccessibilityNodeInfo>() { 4823 @Override 4824 public AccessibilityNodeInfo createFromParcel(Parcel parcel) { 4825 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 4826 info.initFromParcel(parcel); 4827 return info; 4828 } 4829 4830 @Override 4831 public AccessibilityNodeInfo[] newArray(int size) { 4832 return new AccessibilityNodeInfo[size]; 4833 } 4834 }; 4835} 4836