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