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