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