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