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