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