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