1 /* 2 * Copyright (C) 2009 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.accessibilityservice; 18 19 import static android.accessibilityservice.MagnificationConfig.MAGNIFICATION_MODE_FULLSCREEN; 20 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; 21 22 import android.accessibilityservice.GestureDescription.MotionEventGenerator; 23 import android.annotation.CallbackExecutor; 24 import android.annotation.CheckResult; 25 import android.annotation.ColorInt; 26 import android.annotation.FlaggedApi; 27 import android.annotation.IntDef; 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.annotation.RequiresPermission; 31 import android.annotation.TestApi; 32 import android.app.Service; 33 import android.compat.annotation.UnsupportedAppUsage; 34 import android.content.Context; 35 import android.content.ContextWrapper; 36 import android.content.Intent; 37 import android.content.pm.ParceledListSlice; 38 import android.graphics.Bitmap; 39 import android.graphics.ColorSpace; 40 import android.graphics.ParcelableColorSpace; 41 import android.graphics.Region; 42 import android.hardware.HardwareBuffer; 43 import android.hardware.display.DisplayManager; 44 import android.os.Build; 45 import android.os.Bundle; 46 import android.os.Handler; 47 import android.os.HandlerExecutor; 48 import android.os.IBinder; 49 import android.os.Looper; 50 import android.os.RemoteCallback; 51 import android.os.RemoteException; 52 import android.os.SystemClock; 53 import android.util.ArrayMap; 54 import android.util.Log; 55 import android.util.Slog; 56 import android.util.SparseArray; 57 import android.view.Display; 58 import android.view.InputDevice; 59 import android.view.KeyEvent; 60 import android.view.MotionEvent; 61 import android.view.SurfaceControl; 62 import android.view.WindowManager; 63 import android.view.WindowManagerImpl; 64 import android.view.accessibility.AccessibilityCache; 65 import android.view.accessibility.AccessibilityEvent; 66 import android.view.accessibility.AccessibilityInteractionClient; 67 import android.view.accessibility.AccessibilityNodeInfo; 68 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 69 import android.view.accessibility.AccessibilityWindowInfo; 70 import android.view.accessibility.Flags; 71 import android.view.inputmethod.EditorInfo; 72 73 import com.android.internal.annotations.VisibleForTesting; 74 import com.android.internal.inputmethod.CancellationGroup; 75 import com.android.internal.inputmethod.IAccessibilityInputMethodSession; 76 import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback; 77 import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; 78 import com.android.internal.inputmethod.RemoteAccessibilityInputConnection; 79 import com.android.internal.util.Preconditions; 80 81 import java.lang.annotation.Retention; 82 import java.lang.annotation.RetentionPolicy; 83 import java.util.Collections; 84 import java.util.List; 85 import java.util.concurrent.Executor; 86 import java.util.function.Consumer; 87 import java.util.function.IntConsumer; 88 89 /** 90 * Accessibility services should only be used to assist users with disabilities in using 91 * Android devices and apps. They run in the background and receive callbacks by the system 92 * when {@link AccessibilityEvent}s are fired. Such events denote some state transition 93 * in the user interface, for example, the focus has changed, a button has been clicked, 94 * etc. Such a service can optionally request the capability for querying the content 95 * of the active window. Development of an accessibility service requires extending this 96 * class and implementing its abstract methods. 97 * 98 * <div class="special reference"> 99 * <h3>Developer Guides</h3> 100 * <p>For more information about creating AccessibilityServices, read the 101 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 102 * developer guide.</p> 103 * </div> 104 * 105 * <h3>Lifecycle</h3> 106 * <p> 107 * The lifecycle of an accessibility service is managed exclusively by the system and 108 * follows the established service life cycle. Starting an accessibility service is triggered 109 * exclusively by the user explicitly turning the service on in device settings. After the system 110 * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can 111 * be overridden by clients that want to perform post binding setup. 112 * </p> 113 * <p> 114 * An accessibility service stops either when the user turns it off in device settings or when 115 * it calls {@link AccessibilityService#disableSelf()}. 116 * </p> 117 * <h3>Declaration</h3> 118 * <p> 119 * An accessibility is declared as any other service in an AndroidManifest.xml, but it 120 * must do two things: 121 * <ul> 122 * <li> 123 * Specify that it handles the "android.accessibilityservice.AccessibilityService" 124 * {@link android.content.Intent}. 125 * </li> 126 * <li> 127 * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to 128 * ensure that only the system can bind to it. 129 * </li> 130 * </ul> 131 * If either of these items is missing, the system will ignore the accessibility service. 132 * Following is an example declaration: 133 * </p> 134 * <pre> <service android:name=".MyAccessibilityService" 135 * android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> 136 * <intent-filter> 137 * <action android:name="android.accessibilityservice.AccessibilityService" /> 138 * </intent-filter> 139 * . . . 140 * </service></pre> 141 * <h3>Configuration</h3> 142 * <p> 143 * An accessibility service can be configured to receive specific types of accessibility events, 144 * listen only to specific packages, get events from each type only once in a given time frame, 145 * retrieve window content, specify a settings activity, etc. 146 * </p> 147 * <p> 148 * There are two approaches for configuring an accessibility service: 149 * </p> 150 * <ul> 151 * <li> 152 * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring 153 * the service. A service declaration with a meta-data tag is presented below: 154 * <pre> <service android:name=".MyAccessibilityService"> 155 * <intent-filter> 156 * <action android:name="android.accessibilityservice.AccessibilityService" /> 157 * </intent-filter> 158 * <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /> 159 * </service></pre> 160 * <p class="note"> 161 * <strong>Note:</strong> This approach enables setting all properties. 162 * </p> 163 * <p> 164 * For more details refer to {@link #SERVICE_META_DATA} and 165 * <code><{@link android.R.styleable#AccessibilityService accessibility-service}></code>. 166 * </p> 167 * </li> 168 * <li> 169 * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note 170 * that this method can be called any time to dynamically change the service configuration. 171 * <p class="note"> 172 * <strong>Note:</strong> This approach enables setting only dynamically configurable properties: 173 * {@link AccessibilityServiceInfo#eventTypes}, 174 * {@link AccessibilityServiceInfo#feedbackType}, 175 * {@link AccessibilityServiceInfo#flags}, 176 * {@link AccessibilityServiceInfo#notificationTimeout}, 177 * {@link AccessibilityServiceInfo#packageNames} 178 * </p> 179 * <p> 180 * For more details refer to {@link AccessibilityServiceInfo}. 181 * </p> 182 * </li> 183 * </ul> 184 * <h3>Retrieving window content</h3> 185 * <p> 186 * A service can specify in its declaration that it can retrieve window 187 * content which is represented as a tree of {@link AccessibilityWindowInfo} and 188 * {@link AccessibilityNodeInfo} objects. Note that 189 * declaring this capability requires that the service declares its configuration via 190 * an XML resource referenced by {@link #SERVICE_META_DATA}. 191 * </p> 192 * <p> 193 * Window content may be retrieved with 194 * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()}, 195 * {@link AccessibilityService#findFocus(int)}, 196 * {@link AccessibilityService#getWindows()}, or 197 * {@link AccessibilityService#getRootInActiveWindow()}. 198 * </p> 199 * <p class="note"> 200 * <strong>Note</strong> An accessibility service may have requested to be notified for 201 * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also 202 * possible for a node to contain outdated information because the window content may change at any 203 * time. 204 * </p> 205 * <h3>Drawing Accessibility Overlays</h3> 206 * <p>Accessibility services can draw overlays on top of existing screen contents. 207 * Accessibility overlays can be used to visually highlight items on the screen 208 * e.g. indicate the current item with accessibility focus. 209 * Overlays can also offer the user a way to interact with the service directly and quickly 210 * customize the service's behavior.</p> 211 * <p>Accessibility overlays can be attached to a particular window or to the display itself. 212 * Attaching an overlay to a window allows the overly to move, grow and shrink as the window does. 213 * The overlay will maintain the same relative position within the window bounds as the window 214 * moves. The overlay will also maintain the same relative position within the window bounds if 215 * the window is resized. 216 * To attach an overlay to a window, use {@link #attachAccessibilityOverlayToWindow}. 217 * Attaching an overlay to the display means that the overlay is independent of the active 218 * windows on that display. 219 * To attach an overlay to a display, use {@link #attachAccessibilityOverlayToDisplay}. </p> 220 * <p> When positioning an overlay that is attached to a window, the service must use window 221 * coordinates. In order to position an overlay on top of an existing UI element it is necessary 222 * to know the bounds of that element in window coordinates. To find the bounds in window 223 * coordinates of an element, find the corresponding {@link AccessibilityNodeInfo} as discussed 224 * above and call {@link AccessibilityNodeInfo#getBoundsInWindow}. </p> 225 * <h3>Notification strategy</h3> 226 * <p> 227 * All accessibility services are notified of all events they have requested, regardless of their 228 * feedback type. 229 * </p> 230 * <p class="note"> 231 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 232 * events to the client too frequently since this is accomplished via an expensive 233 * interprocess call. One can think of the timeout as a criteria to determine when 234 * event generation has settled down.</p> 235 * <h3>Event types</h3> 236 * <ul> 237 * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li> 238 * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li> 239 * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li> 240 * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li> 241 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li> 242 * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li> 243 * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li> 244 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li> 245 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li> 246 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li> 247 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li> 248 * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li> 249 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li> 250 * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li> 251 * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li> 252 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li> 253 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li> 254 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li> 255 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li> 256 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li> 257 * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li> 258 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li> 259 * </ul> 260 * <h3>Feedback types</h3> 261 * <ul> 262 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li> 263 * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li> 264 * <li>{@link AccessibilityServiceInfo#FEEDBACK_SPOKEN}</li> 265 * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li> 266 * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li> 267 * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li> 268 * </ul> 269 * @see AccessibilityEvent 270 * @see AccessibilityServiceInfo 271 * @see android.view.accessibility.AccessibilityManager 272 */ 273 public abstract class AccessibilityService extends Service { 274 275 /** 276 * The user has performed a touch-exploration gesture on the touch screen without ever 277 * triggering gesture detection. This gesture is only dispatched when {@link 278 * AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set. 279 * 280 * @hide 281 */ 282 public static final int GESTURE_TOUCH_EXPLORATION = -2; 283 284 /** 285 * The user has performed a passthrough gesture on the touch screen without ever triggering 286 * gesture detection. This gesture is only dispatched when {@link 287 * AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set. 288 * @hide 289 */ 290 public static final int GESTURE_PASSTHROUGH = -1; 291 292 /** 293 * The user has performed an unrecognized gesture on the touch screen. This gesture is only 294 * dispatched when {@link AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set. 295 */ 296 public static final int GESTURE_UNKNOWN = 0; 297 298 /** 299 * The user has performed a swipe up gesture on the touch screen. 300 */ 301 public static final int GESTURE_SWIPE_UP = 1; 302 303 /** 304 * The user has performed a swipe down gesture on the touch screen. 305 */ 306 public static final int GESTURE_SWIPE_DOWN = 2; 307 308 /** 309 * The user has performed a swipe left gesture on the touch screen. 310 */ 311 public static final int GESTURE_SWIPE_LEFT = 3; 312 313 /** 314 * The user has performed a swipe right gesture on the touch screen. 315 */ 316 public static final int GESTURE_SWIPE_RIGHT = 4; 317 318 /** 319 * The user has performed a swipe left and right gesture on the touch screen. 320 */ 321 public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5; 322 323 /** 324 * The user has performed a swipe right and left gesture on the touch screen. 325 */ 326 public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6; 327 328 /** 329 * The user has performed a swipe up and down gesture on the touch screen. 330 */ 331 public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; 332 333 /** 334 * The user has performed a swipe down and up gesture on the touch screen. 335 */ 336 public static final int GESTURE_SWIPE_DOWN_AND_UP = 8; 337 338 /** 339 * The user has performed a left and up gesture on the touch screen. 340 */ 341 public static final int GESTURE_SWIPE_LEFT_AND_UP = 9; 342 343 /** 344 * The user has performed a left and down gesture on the touch screen. 345 */ 346 public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10; 347 348 /** 349 * The user has performed a right and up gesture on the touch screen. 350 */ 351 public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11; 352 353 /** 354 * The user has performed a right and down gesture on the touch screen. 355 */ 356 public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12; 357 358 /** 359 * The user has performed an up and left gesture on the touch screen. 360 */ 361 public static final int GESTURE_SWIPE_UP_AND_LEFT = 13; 362 363 /** 364 * The user has performed an up and right gesture on the touch screen. 365 */ 366 public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14; 367 368 /** 369 * The user has performed a down and left gesture on the touch screen. 370 */ 371 public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15; 372 373 /** 374 * The user has performed a down and right gesture on the touch screen. 375 */ 376 public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16; 377 378 /** 379 * The user has performed a double tap gesture on the touch screen. 380 */ 381 public static final int GESTURE_DOUBLE_TAP = 17; 382 383 /** 384 * The user has performed a double tap and hold gesture on the touch screen. 385 */ 386 public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; 387 388 /** 389 * The user has performed a two-finger single tap gesture on the touch screen. 390 */ 391 public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; 392 393 /** 394 * The user has performed a two-finger double tap gesture on the touch screen. 395 */ 396 public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; 397 398 /** 399 * The user has performed a two-finger triple tap gesture on the touch screen. 400 */ 401 public static final int GESTURE_2_FINGER_TRIPLE_TAP = 21; 402 403 /** 404 * The user has performed a three-finger single tap gesture on the touch screen. 405 */ 406 public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; 407 408 /** 409 * The user has performed a three-finger double tap gesture on the touch screen. 410 */ 411 public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; 412 413 /** 414 * The user has performed a three-finger triple tap gesture on the touch screen. 415 */ 416 public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; 417 418 /** 419 * The user has performed a two-finger swipe up gesture on the touch screen. 420 */ 421 public static final int GESTURE_2_FINGER_SWIPE_UP = 25; 422 423 /** 424 * The user has performed a two-finger swipe down gesture on the touch screen. 425 */ 426 public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; 427 428 /** 429 * The user has performed a two-finger swipe left gesture on the touch screen. 430 */ 431 public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; 432 433 /** 434 * The user has performed a two-finger swipe right gesture on the touch screen. 435 */ 436 public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; 437 438 /** 439 * The user has performed a three-finger swipe up gesture on the touch screen. 440 */ 441 public static final int GESTURE_3_FINGER_SWIPE_UP = 29; 442 443 /** 444 * The user has performed a three-finger swipe down gesture on the touch screen. 445 */ 446 public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; 447 448 /** 449 * The user has performed a three-finger swipe left gesture on the touch screen. 450 */ 451 public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; 452 453 /** 454 * The user has performed a three-finger swipe right gesture on the touch screen. 455 */ 456 public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; 457 458 /** The user has performed a four-finger swipe up gesture on the touch screen. */ 459 public static final int GESTURE_4_FINGER_SWIPE_UP = 33; 460 461 /** The user has performed a four-finger swipe down gesture on the touch screen. */ 462 public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34; 463 464 /** The user has performed a four-finger swipe left gesture on the touch screen. */ 465 public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35; 466 467 /** The user has performed a four-finger swipe right gesture on the touch screen. */ 468 public static final int GESTURE_4_FINGER_SWIPE_RIGHT = 36; 469 470 /** The user has performed a four-finger single tap gesture on the touch screen. */ 471 public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; 472 473 /** The user has performed a four-finger double tap gesture on the touch screen. */ 474 public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; 475 476 /** The user has performed a four-finger triple tap gesture on the touch screen. */ 477 public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39; 478 479 /** The user has performed a two-finger double tap and hold gesture on the touch screen. */ 480 public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; 481 482 /** The user has performed a three-finger double tap and hold gesture on the touch screen. */ 483 public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; 484 485 /** The user has performed a two-finger triple-tap and hold gesture on the touch screen. */ 486 public static final int GESTURE_2_FINGER_TRIPLE_TAP_AND_HOLD = 43; 487 488 /** The user has performed a three-finger single-tap and hold gesture on the touch screen. */ 489 public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44; 490 491 /** The user has performed a three-finger triple-tap and hold gesture on the touch screen. */ 492 public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45; 493 494 /** The user has performed a two-finger double tap and hold gesture on the touch screen. */ 495 public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; 496 497 /** 498 * The {@link Intent} that must be declared as handled by the service. 499 */ 500 public static final String SERVICE_INTERFACE = 501 "android.accessibilityservice.AccessibilityService"; 502 503 /** 504 * Name under which an AccessibilityService component publishes information 505 * about itself. This meta-data must reference an XML resource containing an 506 * <code><{@link android.R.styleable#AccessibilityService accessibility-service}></code> 507 * tag. This is a sample XML file configuring an accessibility service: 508 * <pre> <accessibility-service 509 * android:accessibilityEventTypes="typeViewClicked|typeViewFocused" 510 * android:packageNames="foo.bar, foo.baz" 511 * android:accessibilityFeedbackType="feedbackSpoken" 512 * android:notificationTimeout="100" 513 * android:accessibilityFlags="flagDefault" 514 * android:settingsActivity="foo.bar.TestBackActivity" 515 * android:canRetrieveWindowContent="true" 516 * android:canRequestTouchExplorationMode="true" 517 * . . . 518 * /></pre> 519 */ 520 public static final String SERVICE_META_DATA = "android.accessibilityservice"; 521 522 /** 523 * Action to go back. 524 */ 525 public static final int GLOBAL_ACTION_BACK = 1; 526 527 /** 528 * Action to go home. 529 */ 530 public static final int GLOBAL_ACTION_HOME = 2; 531 532 /** 533 * Action to toggle showing the overview of recent apps. Will fail on platforms that don't 534 * show recent apps. 535 */ 536 public static final int GLOBAL_ACTION_RECENTS = 3; 537 538 /** 539 * Action to open the notifications. 540 */ 541 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; 542 543 /** 544 * Action to open the quick settings. 545 */ 546 public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; 547 548 /** 549 * Action to open the power long-press dialog. 550 */ 551 public static final int GLOBAL_ACTION_POWER_DIALOG = 6; 552 553 /** 554 * Action to toggle docking the current app's window. 555 * <p> 556 * <strong>Note:</strong> It is effective only if it appears in {@link #getSystemActions()}. 557 */ 558 public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; 559 560 /** 561 * Action to lock the screen 562 */ 563 public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; 564 565 /** 566 * Action to take a screenshot 567 */ 568 public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9; 569 570 /** 571 * Action to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer and hang up calls 572 * and play and stop media. Calling takes priority. If there is an incoming call, 573 * this action can be used to answer that call, and if there is an ongoing call, to hang up on 574 * that call. 575 */ 576 public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; 577 578 /** 579 * Action to trigger the Accessibility Button 580 */ 581 public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON = 11; 582 583 /** 584 * Action to bring up the Accessibility Button's chooser menu 585 */ 586 public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 12; 587 588 /** 589 * Action to trigger the Accessibility Shortcut. This shortcut has a hardware trigger and can 590 * be activated by holding down the two volume keys. 591 */ 592 public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13; 593 594 /** 595 * Action to show Launcher's all apps. 596 */ 597 public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14; 598 599 /** 600 * Action to dismiss the notification shade 601 */ 602 public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15; 603 604 /** 605 * Action to trigger dpad up keyevent. 606 */ 607 public static final int GLOBAL_ACTION_DPAD_UP = 16; 608 609 /** 610 * Action to trigger dpad down keyevent. 611 */ 612 public static final int GLOBAL_ACTION_DPAD_DOWN = 17; 613 614 /** 615 * Action to trigger dpad left keyevent. 616 */ 617 public static final int GLOBAL_ACTION_DPAD_LEFT = 18; 618 619 /** 620 * Action to trigger dpad right keyevent. 621 */ 622 public static final int GLOBAL_ACTION_DPAD_RIGHT = 19; 623 624 /** 625 * Action to trigger dpad center keyevent. 626 */ 627 public static final int GLOBAL_ACTION_DPAD_CENTER = 20; 628 629 /** 630 * Action to trigger menu key event. 631 */ 632 @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MENU) 633 public static final int GLOBAL_ACTION_MENU = 21; 634 635 /** 636 * Action to trigger media play/pause key event. 637 */ 638 @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE) 639 public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22; 640 641 private static final String LOG_TAG = "AccessibilityService"; 642 643 /** 644 * Interface used by IAccessibilityServiceClientWrapper to call the service from its main 645 * thread. 646 * @hide 647 */ 648 public interface Callbacks { onAccessibilityEvent(AccessibilityEvent event)649 void onAccessibilityEvent(AccessibilityEvent event); onInterrupt()650 void onInterrupt(); onServiceConnected()651 void onServiceConnected(); init(int connectionId, IBinder windowToken)652 void init(int connectionId, IBinder windowToken); 653 /** The detected gesture information for different displays */ onGesture(AccessibilityGestureEvent gestureInfo)654 boolean onGesture(AccessibilityGestureEvent gestureInfo); onKeyEvent(KeyEvent event)655 boolean onKeyEvent(KeyEvent event); 656 /** Magnification changed callbacks for different displays */ onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config)657 void onMagnificationChanged(int displayId, @NonNull Region region, 658 MagnificationConfig config); 659 /** Callbacks for receiving motion events. */ onMotionEvent(MotionEvent event)660 void onMotionEvent(MotionEvent event); 661 /** Callback for tuch state changes. */ onTouchStateChanged(int displayId, int state)662 void onTouchStateChanged(int displayId, int state); onSoftKeyboardShowModeChanged(int showMode)663 void onSoftKeyboardShowModeChanged(int showMode); onPerformGestureResult(int sequence, boolean completedSuccessfully)664 void onPerformGestureResult(int sequence, boolean completedSuccessfully); onFingerprintCapturingGesturesChanged(boolean active)665 void onFingerprintCapturingGesturesChanged(boolean active); onFingerprintGesture(int gesture)666 void onFingerprintGesture(int gesture); 667 /** Accessbility button clicked callbacks for different displays */ onAccessibilityButtonClicked(int displayId)668 void onAccessibilityButtonClicked(int displayId); onAccessibilityButtonAvailabilityChanged(boolean available)669 void onAccessibilityButtonAvailabilityChanged(boolean available); 670 /** This is called when the system action list is changed. */ onSystemActionsChanged()671 void onSystemActionsChanged(); 672 /** This is called when an app requests ime sessions or when the service is enabled. */ createImeSession(IAccessibilityInputMethodSessionCallback callback)673 void createImeSession(IAccessibilityInputMethodSessionCallback callback); 674 /** This is called when an app starts input or when the service is enabled. */ startInput(@ullable RemoteAccessibilityInputConnection inputConnection, @NonNull EditorInfo editorInfo, boolean restarting)675 void startInput(@Nullable RemoteAccessibilityInputConnection inputConnection, 676 @NonNull EditorInfo editorInfo, boolean restarting); 677 } 678 679 /** 680 * Annotations for Soft Keyboard show modes so tools can catch invalid show modes. 681 * @hide 682 */ 683 @Retention(RetentionPolicy.SOURCE) 684 @IntDef(prefix = { "SHOW_MODE_" }, value = { 685 SHOW_MODE_AUTO, 686 SHOW_MODE_HIDDEN, 687 SHOW_MODE_IGNORE_HARD_KEYBOARD 688 }) 689 public @interface SoftKeyboardShowMode {} 690 691 /** 692 * Allow the system to control when the soft keyboard is shown. 693 * @see SoftKeyboardController 694 */ 695 public static final int SHOW_MODE_AUTO = 0; 696 697 /** 698 * Never show the soft keyboard. 699 * @see SoftKeyboardController 700 */ 701 public static final int SHOW_MODE_HIDDEN = 1; 702 703 /** 704 * Allow the soft keyboard to be shown, even if a hard keyboard is connected 705 * @see SoftKeyboardController 706 */ 707 public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2; 708 709 /** 710 * Mask used to cover the show modes supported in public API 711 * @hide 712 */ 713 public static final int SHOW_MODE_MASK = 0x03; 714 715 /** 716 * Bit used to hold the old value of the hard IME setting to restore when a service is shut 717 * down. 718 * @hide 719 */ 720 public static final int SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE = 0x20000000; 721 722 /** 723 * Bit for show mode setting to indicate that the user has overridden the hard keyboard 724 * behavior. 725 * @hide 726 */ 727 public static final int SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN = 0x40000000; 728 729 /** 730 * Annotations for error codes of taking screenshot. 731 * @hide 732 */ 733 @Retention(RetentionPolicy.SOURCE) 734 @IntDef(prefix = { "TAKE_SCREENSHOT_" }, value = { 735 ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, 736 ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS, 737 ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT, 738 ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, 739 ERROR_TAKE_SCREENSHOT_INVALID_WINDOW 740 }) 741 public @interface ScreenshotErrorCode {} 742 743 /** 744 * The status of taking screenshot is success. 745 * @hide 746 */ 747 public static final int TAKE_SCREENSHOT_SUCCESS = 0; 748 749 /** 750 * The status of taking screenshot is failure and the reason is internal error. 751 */ 752 public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 1; 753 754 /** 755 * The status of taking screenshot is failure and the reason is no accessibility access. 756 */ 757 public static final int ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS = 2; 758 759 /** 760 * The status of taking screenshot is failure and the reason is that too little time has 761 * elapsed since the last screenshot. 762 */ 763 public static final int ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT = 3; 764 765 /** 766 * The status of taking screenshot is failure and the reason is invalid display Id. 767 */ 768 public static final int ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY = 4; 769 770 /** 771 * The status of taking screenshot is failure and the reason is invalid accessibility window Id. 772 */ 773 public static final int ERROR_TAKE_SCREENSHOT_INVALID_WINDOW = 5; 774 775 /** 776 * The status of taking screenshot is failure and the reason is the window contains secure 777 * content. 778 * @see WindowManager.LayoutParams#FLAG_SECURE 779 */ 780 public static final int ERROR_TAKE_SCREENSHOT_SECURE_WINDOW = 6; 781 782 /** 783 * The interval time of calling 784 * {@link AccessibilityService#takeScreenshot(int, Executor, Consumer)} API. 785 * @hide 786 */ 787 @TestApi 788 public static final int ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS = 333; 789 790 /** @hide */ 791 public static final String KEY_ACCESSIBILITY_SCREENSHOT_STATUS = 792 "screenshot_status"; 793 794 /** @hide */ 795 public static final String KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER = 796 "screenshot_hardwareBuffer"; 797 798 /** @hide */ 799 public static final String KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE = 800 "screenshot_colorSpace"; 801 802 /** @hide */ 803 public static final String KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP = 804 "screenshot_timestamp"; 805 806 807 /** 808 * Annotations for result codes of attaching accessibility overlays. 809 * 810 * @hide 811 */ 812 @Retention(RetentionPolicy.SOURCE) 813 @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") 814 @IntDef( 815 prefix = {"OVERLAY_RESULT_"}, 816 value = { 817 OVERLAY_RESULT_SUCCESS, 818 OVERLAY_RESULT_INTERNAL_ERROR, 819 OVERLAY_RESULT_INVALID, 820 }) 821 public @interface AttachOverlayResult {} 822 823 /** Result code indicating the overlay was successfully attached. */ 824 @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") 825 public static final int OVERLAY_RESULT_SUCCESS = 0; 826 827 /** 828 * Result code indicating the overlay could not be attached due to an internal 829 * error and not 830 * because of problems with the input. 831 */ 832 @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") 833 public static final int OVERLAY_RESULT_INTERNAL_ERROR = 1; 834 835 /** 836 * Result code indicating the overlay could not be attached because the 837 * specified display or 838 * window id was invalid. 839 */ 840 @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") 841 public static final int OVERLAY_RESULT_INVALID = 2; 842 843 private int mConnectionId = AccessibilityInteractionClient.NO_ID; 844 845 @UnsupportedAppUsage 846 private AccessibilityServiceInfo mInfo; 847 848 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 849 private IBinder mWindowToken; 850 851 private WindowManager mWindowManager; 852 853 /** List of magnification controllers, mapping from displayId -> MagnificationController. */ 854 private final SparseArray<MagnificationController> mMagnificationControllers = 855 new SparseArray<>(0); 856 /** 857 * List of touch interaction controllers, mapping from displayId -> TouchInteractionController. 858 */ 859 private final SparseArray<TouchInteractionController> mTouchInteractionControllers = 860 new SparseArray<>(0); 861 862 private SoftKeyboardController mSoftKeyboardController; 863 private InputMethod mInputMethod; 864 private boolean mInputMethodInitialized = false; 865 private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers = 866 new SparseArray<>(0); 867 private BrailleDisplayController mBrailleDisplayController; 868 869 private int mGestureStatusCallbackSequence; 870 871 private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos; 872 873 private final Object mLock = new Object(); 874 875 private FingerprintGestureController mFingerprintGestureController; 876 877 private int mMotionEventSources; 878 879 /** 880 * Callback for {@link android.view.accessibility.AccessibilityEvent}s. 881 * 882 * @param event The new event. This event is owned by the caller and cannot be used after 883 * this method returns. Services wishing to use the event after this method returns should 884 * make a copy. 885 */ onAccessibilityEvent(AccessibilityEvent event)886 public abstract void onAccessibilityEvent(AccessibilityEvent event); 887 888 /** 889 * Callback for interrupting the accessibility feedback. 890 */ onInterrupt()891 public abstract void onInterrupt(); 892 893 /** 894 * Dispatches service connection to internal components first, then the 895 * client code. 896 */ dispatchServiceConnected()897 private void dispatchServiceConnected() { 898 synchronized (mLock) { 899 for (int i = 0; i < mMagnificationControllers.size(); i++) { 900 mMagnificationControllers.valueAt(i).onServiceConnectedLocked(); 901 } 902 final AccessibilityServiceInfo info = getServiceInfo(); 903 if (info != null) { 904 updateInputMethod(info); 905 mMotionEventSources = info.getMotionEventSources(); 906 } 907 } 908 if (mSoftKeyboardController != null) { 909 mSoftKeyboardController.onServiceConnected(); 910 } 911 912 // The client gets to handle service connection last, after we've set 913 // up any state upon which their code may rely. 914 onServiceConnected(); 915 } 916 updateInputMethod(AccessibilityServiceInfo info)917 private void updateInputMethod(AccessibilityServiceInfo info) { 918 if (info != null) { 919 boolean requestIme = (info.flags 920 & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0; 921 if (requestIme && !mInputMethodInitialized) { 922 mInputMethod = onCreateInputMethod(); 923 mInputMethodInitialized = true; 924 } else if (!requestIme & mInputMethodInitialized) { 925 mInputMethod = null; 926 mInputMethodInitialized = false; 927 } 928 } 929 } 930 931 /** 932 * This method is a part of the {@link AccessibilityService} lifecycle and is 933 * called after the system has successfully bound to the service. If is 934 * convenient to use this method for setting the {@link AccessibilityServiceInfo}. 935 * 936 * @see AccessibilityServiceInfo 937 * @see #setServiceInfo(AccessibilityServiceInfo) 938 */ onServiceConnected()939 protected void onServiceConnected() { 940 941 } 942 943 /** 944 * Called by {@link #onGesture(AccessibilityGestureEvent)} when the user performs a specific 945 * gesture on the default display. 946 * 947 * <strong>Note:</strong> To receive gestures an accessibility service must 948 * request that the device is in touch exploration mode by setting the 949 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} 950 * flag. 951 * 952 * @param gestureId The unique id of the performed gesture. 953 * 954 * @return Whether the gesture was handled. 955 * @deprecated Override {@link #onGesture(AccessibilityGestureEvent)} instead. 956 * 957 * @see #GESTURE_SWIPE_UP 958 * @see #GESTURE_SWIPE_UP_AND_LEFT 959 * @see #GESTURE_SWIPE_UP_AND_DOWN 960 * @see #GESTURE_SWIPE_UP_AND_RIGHT 961 * @see #GESTURE_SWIPE_DOWN 962 * @see #GESTURE_SWIPE_DOWN_AND_LEFT 963 * @see #GESTURE_SWIPE_DOWN_AND_UP 964 * @see #GESTURE_SWIPE_DOWN_AND_RIGHT 965 * @see #GESTURE_SWIPE_LEFT 966 * @see #GESTURE_SWIPE_LEFT_AND_UP 967 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT 968 * @see #GESTURE_SWIPE_LEFT_AND_DOWN 969 * @see #GESTURE_SWIPE_RIGHT 970 * @see #GESTURE_SWIPE_RIGHT_AND_UP 971 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT 972 * @see #GESTURE_SWIPE_RIGHT_AND_DOWN 973 */ 974 @Deprecated onGesture(int gestureId)975 protected boolean onGesture(int gestureId) { 976 return false; 977 } 978 979 /** 980 * Called by the system when the user performs a specific gesture on the 981 * specific touch screen. 982 *<p> 983 * <strong>Note:</strong> To receive gestures an accessibility service must 984 * request that the device is in touch exploration mode by setting the 985 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} 986 * flag. 987 *<p> 988 * <strong>Note:</strong> The default implementation calls {@link #onGesture(int)} when the 989 * touch screen is default display. 990 * 991 * @param gestureEvent The information of gesture. 992 * 993 * @return Whether the gesture was handled. 994 * 995 */ onGesture(@onNull AccessibilityGestureEvent gestureEvent)996 public boolean onGesture(@NonNull AccessibilityGestureEvent gestureEvent) { 997 if (gestureEvent.getDisplayId() == Display.DEFAULT_DISPLAY) { 998 onGesture(gestureEvent.getGestureId()); 999 } 1000 return false; 1001 } 1002 1003 /** 1004 * Callback that allows an accessibility service to observe the key events 1005 * before they are passed to the rest of the system. This means that the events 1006 * are first delivered here before they are passed to the device policy, the 1007 * input method, or applications. 1008 * <p> 1009 * <strong>Note:</strong> It is important that key events are handled in such 1010 * a way that the event stream that would be passed to the rest of the system 1011 * is well-formed. For example, handling the down event but not the up event 1012 * and vice versa would generate an inconsistent event stream. 1013 * </p> 1014 * <p> 1015 * <strong>Note:</strong> The key events delivered in this method are copies 1016 * and modifying them will have no effect on the events that will be passed 1017 * to the system. This method is intended to perform purely filtering 1018 * functionality. 1019 * <p> 1020 * 1021 * @param event The event to be processed. This event is owned by the caller and cannot be used 1022 * after this method returns. Services wishing to use the event after this method returns should 1023 * make a copy. 1024 * @return If true then the event will be consumed and not delivered to 1025 * applications, otherwise it will be delivered as usual. 1026 */ onKeyEvent(KeyEvent event)1027 protected boolean onKeyEvent(KeyEvent event) { 1028 return false; 1029 } 1030 1031 /** 1032 * Callback that allows an accessibility service to observe generic {@link MotionEvent}s. 1033 * <p> 1034 * Prefer {@link TouchInteractionController} to observe and control touchscreen events, 1035 * including touch gestures. If this or any enabled service is using 1036 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} then 1037 * {@link #onMotionEvent} will not receive touchscreen events. 1038 * </p> 1039 * <p> 1040 * <strong>Note:</strong> The service must first request to listen to events using 1041 * {@link AccessibilityServiceInfo#setMotionEventSources}. 1042 * {@link MotionEvent}s from sources in {@link AccessibilityServiceInfo#getMotionEventSources()} 1043 * are not sent to the rest of the system. To stop listening to events from a given source, call 1044 * {@link AccessibilityServiceInfo#setMotionEventSources} with that source removed. 1045 * </p> 1046 * @param event The event to be processed. 1047 */ onMotionEvent(@onNull MotionEvent event)1048 public void onMotionEvent(@NonNull MotionEvent event) { } 1049 1050 /** 1051 * Gets the windows on the screen of the default display. This method returns only the windows 1052 * that a sighted user can interact with, as opposed to all windows. 1053 * For example, if there is a modal dialog shown and the user cannot touch 1054 * anything behind it, then only the modal window will be reported 1055 * (assuming it is the top one). For convenience the returned windows 1056 * are ordered in a descending layer order, which is the windows that 1057 * are on top are reported first. Since the user can always 1058 * interact with the window that has input focus by typing, the focused 1059 * window is always returned (even if covered by a modal window). 1060 * <p> 1061 * <strong>Note:</strong> In order to access the windows your service has 1062 * to declare the capability to retrieve window content by setting the 1063 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 1064 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 1065 * Also the service has to opt-in to retrieve the interactive windows by 1066 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} 1067 * flag. 1068 * </p> 1069 * 1070 * @return The windows if there are windows and the service is can retrieve 1071 * them, otherwise an empty list. 1072 */ getWindows()1073 public List<AccessibilityWindowInfo> getWindows() { 1074 return AccessibilityInteractionClient.getInstance(this).getWindows(mConnectionId); 1075 } 1076 1077 /** 1078 * Gets the windows on the screen of all displays. This method returns only the windows 1079 * that a sighted user can interact with, as opposed to all windows. 1080 * For example, if there is a modal dialog shown and the user cannot touch 1081 * anything behind it, then only the modal window will be reported 1082 * (assuming it is the top one). For convenience the returned windows 1083 * are ordered in a descending layer order, which is the windows that 1084 * are on top are reported first. Since the user can always 1085 * interact with the window that has input focus by typing, the focused 1086 * window is always returned (even if covered by a modal window). 1087 * <p> 1088 * <strong>Note:</strong> In order to access the windows your service has 1089 * to declare the capability to retrieve window content by setting the 1090 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 1091 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 1092 * Also the service has to opt-in to retrieve the interactive windows by 1093 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} 1094 * flag. 1095 * </p> 1096 * 1097 * @return The windows of all displays if there are windows and the service is can retrieve 1098 * them, otherwise an empty list. The key of SparseArray is display ID. 1099 */ 1100 @NonNull getWindowsOnAllDisplays()1101 public final SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { 1102 return AccessibilityInteractionClient.getInstance(this).getWindowsOnAllDisplays( 1103 mConnectionId); 1104 } 1105 1106 /** 1107 * Gets the root node in the currently active window if this service 1108 * can retrieve window content. The active window is the one that the user 1109 * is currently touching or the window with input focus, if the user is not 1110 * touching any window. It could be from any logical display. 1111 * <p> 1112 * <strong>Note:</strong> In order to access the root node your service has 1113 * to declare the capability to retrieve window content by setting the 1114 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 1115 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 1116 * </p> 1117 * 1118 * @return The root node if this service can retrieve window content. 1119 * @see AccessibilityWindowInfo#isActive() for more explanation about the active window. 1120 */ getRootInActiveWindow()1121 public AccessibilityNodeInfo getRootInActiveWindow() { 1122 return getRootInActiveWindow(AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS_HYBRID); 1123 } 1124 1125 /** 1126 * Gets the root node in the currently active window if this service 1127 * can retrieve window content. The active window is the one that the user 1128 * is currently touching or the window with input focus, if the user is not 1129 * touching any window. It could be from any logical display. 1130 * 1131 * @param prefetchingStrategy the prefetching strategy. 1132 * @return The root node if this service can retrieve window content. 1133 * 1134 * @see #getRootInActiveWindow() 1135 * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching. 1136 */ 1137 @Nullable getRootInActiveWindow( @ccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy)1138 public AccessibilityNodeInfo getRootInActiveWindow( 1139 @AccessibilityNodeInfo.PrefetchingStrategy int prefetchingStrategy) { 1140 return AccessibilityInteractionClient.getInstance(this).getRootInActiveWindow( 1141 mConnectionId, prefetchingStrategy); 1142 } 1143 1144 /** 1145 * Disables the service. After calling this method, the service will be disabled and settings 1146 * will show that it is turned off. 1147 */ disableSelf()1148 public final void disableSelf() { 1149 final IAccessibilityServiceConnection connection = 1150 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 1151 if (connection != null) { 1152 try { 1153 connection.disableSelf(); 1154 } catch (RemoteException re) { 1155 throw new RuntimeException(re); 1156 } 1157 } 1158 } 1159 1160 @NonNull 1161 @Override createDisplayContext(Display display)1162 public Context createDisplayContext(Display display) { 1163 return new AccessibilityContext(super.createDisplayContext(display), mConnectionId); 1164 } 1165 1166 @NonNull 1167 @Override createWindowContext(int type, @Nullable Bundle options)1168 public Context createWindowContext(int type, @Nullable Bundle options) { 1169 final Context context = super.createWindowContext(type, options); 1170 if (type != TYPE_ACCESSIBILITY_OVERLAY) { 1171 return context; 1172 } 1173 return new AccessibilityContext(context, mConnectionId); 1174 } 1175 1176 @NonNull 1177 @Override createWindowContext(@onNull Display display, int type, @Nullable Bundle options)1178 public Context createWindowContext(@NonNull Display display, int type, 1179 @Nullable Bundle options) { 1180 final Context context = super.createWindowContext(display, type, options); 1181 if (type != TYPE_ACCESSIBILITY_OVERLAY) { 1182 return context; 1183 } 1184 return new AccessibilityContext(context, mConnectionId); 1185 } 1186 1187 /** 1188 * Returns the magnification controller, which may be used to query and 1189 * modify the state of display magnification. 1190 * <p> 1191 * <strong>Note:</strong> In order to control magnification, your service 1192 * must declare the capability by setting the 1193 * {@link android.R.styleable#AccessibilityService_canControlMagnification} 1194 * property in its meta-data. For more information, see 1195 * {@link #SERVICE_META_DATA}. 1196 * 1197 * @return the magnification controller 1198 */ 1199 @NonNull getMagnificationController()1200 public final MagnificationController getMagnificationController() { 1201 return getMagnificationController(Display.DEFAULT_DISPLAY); 1202 } 1203 1204 /** 1205 * Returns the magnification controller of specified logical display, which may be used to 1206 * query and modify the state of display magnification. 1207 * <p> 1208 * <strong>Note:</strong> In order to control magnification, your service 1209 * must declare the capability by setting the 1210 * {@link android.R.styleable#AccessibilityService_canControlMagnification} 1211 * property in its meta-data. For more information, see 1212 * {@link #SERVICE_META_DATA}. 1213 * 1214 * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for 1215 * default display. 1216 * @return the magnification controller 1217 * 1218 * @hide 1219 */ 1220 @NonNull getMagnificationController(int displayId)1221 public final MagnificationController getMagnificationController(int displayId) { 1222 synchronized (mLock) { 1223 MagnificationController controller = mMagnificationControllers.get(displayId); 1224 if (controller == null) { 1225 controller = new MagnificationController(this, mLock, displayId); 1226 mMagnificationControllers.put(displayId, controller); 1227 } 1228 return controller; 1229 } 1230 } 1231 1232 /** 1233 * Get the controller for fingerprint gestures. This feature requires {@link 1234 * AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}. 1235 * 1236 *<strong>Note: </strong> The service must be connected before this method is called. 1237 * 1238 * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable. 1239 */ 1240 @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) getFingerprintGestureController()1241 public final @NonNull FingerprintGestureController getFingerprintGestureController() { 1242 if (mFingerprintGestureController == null) { 1243 mFingerprintGestureController = new FingerprintGestureController( 1244 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId)); 1245 } 1246 return mFingerprintGestureController; 1247 } 1248 1249 /** 1250 * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from 1251 * the user, this service, or another service, will be cancelled. 1252 * <p> 1253 * The gesture will be dispatched as if it were performed directly on the screen by a user, so 1254 * the events may be affected by features such as magnification and explore by touch. 1255 * </p> 1256 * <p> 1257 * <strong>Note:</strong> In order to dispatch gestures, your service 1258 * must declare the capability by setting the 1259 * {@link android.R.styleable#AccessibilityService_canPerformGestures} 1260 * property in its meta-data. For more information, see 1261 * {@link #SERVICE_META_DATA}. 1262 * </p> 1263 * <p>Since many apps do not appropriately support {@link AccessibilityAction#ACTION_CLICK}, 1264 * if this action fails on an element that should be clickable, a service that is not a screen 1265 * reader may send a tap directly to the element as a fallback. The example below 1266 * demonstrates this fallback using the gesture dispatch APIs: 1267 * 1268 * <pre class="prettyprint"><code> 1269 * private void tap(PointF point) { 1270 * StrokeDescription tap = new StrokeDescription(path(point), 0, 1271 * ViewConfiguration.getTapTimeout()); 1272 * GestureDescription.Builder builder = new GestureDescription.Builder(); 1273 * builder.addStroke(tap); 1274 * dispatchGesture(builder.build(), null, null); 1275 * } 1276 *</code> 1277 * </pre> 1278 * @param gesture The gesture to dispatch 1279 * @param callback The object to call back when the status of the gesture is known. If 1280 * {@code null}, no status is reported. 1281 * @param handler The handler on which to call back the {@code callback} object. If 1282 * {@code null}, the object is called back on the service's main thread. 1283 * 1284 * @return {@code true} if the gesture is dispatched, {@code false} if not. 1285 */ dispatchGesture(@onNull GestureDescription gesture, @Nullable GestureResultCallback callback, @Nullable Handler handler)1286 public final boolean dispatchGesture(@NonNull GestureDescription gesture, 1287 @Nullable GestureResultCallback callback, 1288 @Nullable Handler handler) { 1289 final IAccessibilityServiceConnection connection = 1290 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 1291 if (connection == null) { 1292 return false; 1293 } 1294 int sampleTimeMs = calculateGestureSampleTimeMs(gesture.getDisplayId()); 1295 List<GestureDescription.GestureStep> steps = 1296 MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, sampleTimeMs); 1297 try { 1298 synchronized (mLock) { 1299 mGestureStatusCallbackSequence++; 1300 if (callback != null) { 1301 if (mGestureStatusCallbackInfos == null) { 1302 mGestureStatusCallbackInfos = new SparseArray<>(); 1303 } 1304 GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture, 1305 callback, handler); 1306 mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo); 1307 } 1308 connection.dispatchGesture(mGestureStatusCallbackSequence, 1309 new ParceledListSlice<>(steps), gesture.getDisplayId()); 1310 } 1311 } catch (RemoteException re) { 1312 throw new RuntimeException(re); 1313 } 1314 return true; 1315 } 1316 1317 /** 1318 * Returns the sample time in millis of gesture steps for the current display. 1319 * 1320 * <p>For gestures to be smooth they should line up with the refresh rate of the display. 1321 * On versions of Android before R, the sample time was fixed to 100ms. 1322 */ calculateGestureSampleTimeMs(int displayId)1323 private int calculateGestureSampleTimeMs(int displayId) { 1324 if (getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.Q) { 1325 return 100; 1326 } 1327 Display display = getSystemService(DisplayManager.class).getDisplay( 1328 displayId); 1329 if (display == null) { 1330 return 100; 1331 } 1332 int msPerSecond = 1000; 1333 int sampleTimeMs = (int) (msPerSecond / display.getRefreshRate()); 1334 if (sampleTimeMs < 1) { 1335 // Should be impossible, but do not return 0. 1336 return 100; 1337 } 1338 return sampleTimeMs; 1339 } 1340 onPerformGestureResult(int sequence, final boolean completedSuccessfully)1341 void onPerformGestureResult(int sequence, final boolean completedSuccessfully) { 1342 if (mGestureStatusCallbackInfos == null) { 1343 return; 1344 } 1345 GestureResultCallbackInfo callbackInfo; 1346 synchronized (mLock) { 1347 callbackInfo = mGestureStatusCallbackInfos.get(sequence); 1348 mGestureStatusCallbackInfos.remove(sequence); 1349 } 1350 final GestureResultCallbackInfo finalCallbackInfo = callbackInfo; 1351 if ((callbackInfo != null) && (callbackInfo.gestureDescription != null) 1352 && (callbackInfo.callback != null)) { 1353 if (callbackInfo.handler != null) { 1354 callbackInfo.handler.post(new Runnable() { 1355 @Override 1356 public void run() { 1357 if (completedSuccessfully) { 1358 finalCallbackInfo.callback 1359 .onCompleted(finalCallbackInfo.gestureDescription); 1360 } else { 1361 finalCallbackInfo.callback 1362 .onCancelled(finalCallbackInfo.gestureDescription); 1363 } 1364 } 1365 }); 1366 return; 1367 } 1368 if (completedSuccessfully) { 1369 callbackInfo.callback.onCompleted(callbackInfo.gestureDescription); 1370 } else { 1371 callbackInfo.callback.onCancelled(callbackInfo.gestureDescription); 1372 } 1373 } 1374 } 1375 onMagnificationChanged(int displayId, @NonNull Region region, MagnificationConfig config)1376 private void onMagnificationChanged(int displayId, @NonNull Region region, 1377 MagnificationConfig config) { 1378 MagnificationController controller; 1379 synchronized (mLock) { 1380 controller = mMagnificationControllers.get(displayId); 1381 } 1382 if (controller != null) { 1383 controller.dispatchMagnificationChanged(region, config); 1384 } 1385 } 1386 1387 /** 1388 * Callback for fingerprint gesture handling 1389 * @param active If gesture detection is active 1390 */ onFingerprintCapturingGesturesChanged(boolean active)1391 private void onFingerprintCapturingGesturesChanged(boolean active) { 1392 getFingerprintGestureController().onGestureDetectionActiveChanged(active); 1393 } 1394 1395 /** 1396 * Callback for fingerprint gesture handling 1397 * @param gesture The identifier for the gesture performed 1398 */ onFingerprintGesture(int gesture)1399 private void onFingerprintGesture(int gesture) { 1400 getFingerprintGestureController().onGesture(gesture); 1401 } 1402 1403 /** @hide */ 1404 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) getConnectionId()1405 public int getConnectionId() { 1406 return mConnectionId; 1407 } 1408 1409 /** 1410 * Used to control and query the state of display magnification. 1411 */ 1412 public static final class MagnificationController { 1413 private final AccessibilityService mService; 1414 private final int mDisplayId; 1415 1416 /** 1417 * Map of listeners to their handlers. Lazily created when adding the 1418 * first magnification listener. 1419 */ 1420 private ArrayMap<OnMagnificationChangedListener, Handler> mListeners; 1421 private final Object mLock; 1422 MagnificationController(@onNull AccessibilityService service, @NonNull Object lock, int displayId)1423 MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock, 1424 int displayId) { 1425 mService = service; 1426 mLock = lock; 1427 mDisplayId = displayId; 1428 } 1429 1430 /** 1431 * Called when the service is connected. 1432 */ onServiceConnectedLocked()1433 void onServiceConnectedLocked() { 1434 if (mListeners != null && !mListeners.isEmpty()) { 1435 setMagnificationCallbackEnabled(true); 1436 } 1437 } 1438 1439 /** 1440 * Adds the specified change listener to the list of magnification 1441 * change listeners. The callback will occur on the service's main 1442 * thread. 1443 * 1444 * @param listener the listener to add, must be non-{@code null} 1445 */ addListener(@onNull OnMagnificationChangedListener listener)1446 public void addListener(@NonNull OnMagnificationChangedListener listener) { 1447 addListener(listener, null); 1448 } 1449 1450 /** 1451 * Adds the specified change listener to the list of magnification 1452 * change listeners. The callback will occur on the specified 1453 * {@link Handler}'s thread, or on the service's main thread if the 1454 * handler is {@code null}. 1455 * 1456 * @param listener the listener to add, must be non-null 1457 * @param handler the handler on which the callback should execute, or 1458 * {@code null} to execute on the service's main thread 1459 */ addListener(@onNull OnMagnificationChangedListener listener, @Nullable Handler handler)1460 public void addListener(@NonNull OnMagnificationChangedListener listener, 1461 @Nullable Handler handler) { 1462 synchronized (mLock) { 1463 if (mListeners == null) { 1464 mListeners = new ArrayMap<>(); 1465 } 1466 1467 final boolean shouldEnableCallback = mListeners.isEmpty(); 1468 mListeners.put(listener, handler); 1469 1470 if (shouldEnableCallback) { 1471 // This may fail if the service is not connected yet, but if we 1472 // still have listeners when it connects then we can try again. 1473 setMagnificationCallbackEnabled(true); 1474 } 1475 } 1476 } 1477 1478 /** 1479 * Removes the specified change listener from the list of magnification change listeners. 1480 * 1481 * @param listener the listener to remove, must be non-null 1482 * @return {@code true} if the listener was removed, {@code false} otherwise 1483 */ removeListener(@onNull OnMagnificationChangedListener listener)1484 public boolean removeListener(@NonNull OnMagnificationChangedListener listener) { 1485 if (mListeners == null) { 1486 return false; 1487 } 1488 1489 synchronized (mLock) { 1490 final int keyIndex = mListeners.indexOfKey(listener); 1491 final boolean hasKey = keyIndex >= 0; 1492 if (hasKey) { 1493 mListeners.removeAt(keyIndex); 1494 } 1495 1496 if (hasKey && mListeners.isEmpty()) { 1497 // We just removed the last listener, so we don't need 1498 // callbacks from the service anymore. 1499 setMagnificationCallbackEnabled(false); 1500 } 1501 1502 return hasKey; 1503 } 1504 } 1505 setMagnificationCallbackEnabled(boolean enabled)1506 private void setMagnificationCallbackEnabled(boolean enabled) { 1507 final IAccessibilityServiceConnection connection = 1508 AccessibilityInteractionClient.getInstance(mService).getConnection( 1509 mService.mConnectionId); 1510 if (connection != null) { 1511 try { 1512 connection.setMagnificationCallbackEnabled(mDisplayId, enabled); 1513 } catch (RemoteException re) { 1514 throw new RuntimeException(re); 1515 } 1516 } 1517 } 1518 1519 /** 1520 * Dispatches magnification changes to any registered listeners. This 1521 * should be called on the service's main thread. 1522 */ dispatchMagnificationChanged(final @NonNull Region region, final MagnificationConfig config)1523 void dispatchMagnificationChanged(final @NonNull Region region, 1524 final MagnificationConfig config) { 1525 final ArrayMap<OnMagnificationChangedListener, Handler> entries; 1526 synchronized (mLock) { 1527 if (mListeners == null || mListeners.isEmpty()) { 1528 Slog.d(LOG_TAG, "Received magnification changed " 1529 + "callback with no listeners registered!"); 1530 setMagnificationCallbackEnabled(false); 1531 return; 1532 } 1533 1534 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent 1535 // modification. 1536 entries = new ArrayMap<>(mListeners); 1537 } 1538 1539 for (int i = 0, count = entries.size(); i < count; i++) { 1540 final OnMagnificationChangedListener listener = entries.keyAt(i); 1541 final Handler handler = entries.valueAt(i); 1542 if (handler != null) { 1543 handler.post(() -> { 1544 listener.onMagnificationChanged(MagnificationController.this, 1545 region, config); 1546 }); 1547 } else { 1548 // We're already on the main thread, just run the listener. 1549 listener.onMagnificationChanged(this, region, config); 1550 } 1551 } 1552 } 1553 1554 /** 1555 * Gets the {@link MagnificationConfig} of the controlling magnifier on the display. 1556 * <p> 1557 * <strong>Note:</strong> If the service is not yet connected (e.g. 1558 * {@link AccessibilityService#onServiceConnected()} has not yet been 1559 * called) or the service has been disconnected, this method will 1560 * return null. 1561 * </p> 1562 * 1563 * @return the magnification config that the service controls 1564 */ getMagnificationConfig()1565 public @Nullable MagnificationConfig getMagnificationConfig() { 1566 final IAccessibilityServiceConnection connection = 1567 AccessibilityInteractionClient.getInstance(mService).getConnection( 1568 mService.mConnectionId); 1569 if (connection != null) { 1570 try { 1571 return connection.getMagnificationConfig(mDisplayId); 1572 } catch (RemoteException re) { 1573 Log.w(LOG_TAG, "Failed to obtain magnification config", re); 1574 re.rethrowFromSystemServer(); 1575 } 1576 } 1577 return null; 1578 } 1579 1580 /** 1581 * Returns the current magnification scale. 1582 * <p> 1583 * <strong>Note:</strong> If the service is not yet connected (e.g. 1584 * {@link AccessibilityService#onServiceConnected()} has not yet been 1585 * called) or the service has been disconnected, this method will 1586 * return a default value of {@code 1.0f}. 1587 * </p> 1588 * <p> 1589 * <strong>Note:</strong> This legacy API gets the scale of full-screen 1590 * magnification. To get the scale of the current controlling magnifier, 1591 * use {@link #getMagnificationConfig} instead. 1592 * </p> 1593 * 1594 * @return the current magnification scale 1595 * @deprecated Use {@link #getMagnificationConfig()} instead 1596 */ 1597 @Deprecated getScale()1598 public float getScale() { 1599 final IAccessibilityServiceConnection connection = 1600 AccessibilityInteractionClient.getInstance(mService).getConnection( 1601 mService.mConnectionId); 1602 if (connection != null) { 1603 try { 1604 return connection.getMagnificationScale(mDisplayId); 1605 } catch (RemoteException re) { 1606 Log.w(LOG_TAG, "Failed to obtain scale", re); 1607 re.rethrowFromSystemServer(); 1608 } 1609 } 1610 return 1.0f; 1611 } 1612 1613 /** 1614 * Returns the unscaled screen-relative X coordinate of the focal 1615 * center of the magnified region. This is the point around which 1616 * zooming occurs and is guaranteed to lie within the magnified 1617 * region. 1618 * <p> 1619 * <strong>Note:</strong> If the service is not yet connected (e.g. 1620 * {@link AccessibilityService#onServiceConnected()} has not yet been 1621 * called) or the service has been disconnected, this method will 1622 * return a default value of {@code 0.0f}. 1623 * </p> 1624 * <p> 1625 * <strong>Note:</strong> This legacy API gets the center position of full-screen 1626 * magnification. To get the magnification center of the current controlling magnifier, 1627 * use {@link #getMagnificationConfig} instead. 1628 * </p> 1629 * 1630 * @return the unscaled screen-relative X coordinate of the center of 1631 * the magnified region 1632 * @deprecated Use {@link #getMagnificationConfig()} instead 1633 */ 1634 @Deprecated getCenterX()1635 public float getCenterX() { 1636 final IAccessibilityServiceConnection connection = 1637 AccessibilityInteractionClient.getInstance(mService).getConnection( 1638 mService.mConnectionId); 1639 if (connection != null) { 1640 try { 1641 return connection.getMagnificationCenterX(mDisplayId); 1642 } catch (RemoteException re) { 1643 Log.w(LOG_TAG, "Failed to obtain center X", re); 1644 re.rethrowFromSystemServer(); 1645 } 1646 } 1647 return 0.0f; 1648 } 1649 1650 /** 1651 * Returns the unscaled screen-relative Y coordinate of the focal 1652 * center of the magnified region. This is the point around which 1653 * zooming occurs and is guaranteed to lie within the magnified 1654 * region. 1655 * <p> 1656 * <strong>Note:</strong> If the service is not yet connected (e.g. 1657 * {@link AccessibilityService#onServiceConnected()} has not yet been 1658 * called) or the service has been disconnected, this method will 1659 * return a default value of {@code 0.0f}. 1660 * </p> 1661 * <p> 1662 * <strong>Note:</strong> This legacy API gets the center position of full-screen 1663 * magnification. To get the magnification center of the current controlling magnifier, 1664 * use {@link #getMagnificationConfig} instead. 1665 * </p> 1666 * 1667 * @return the unscaled screen-relative Y coordinate of the center of 1668 * the magnified region 1669 * @deprecated Use {@link #getMagnificationConfig()} instead 1670 */ 1671 @Deprecated getCenterY()1672 public float getCenterY() { 1673 final IAccessibilityServiceConnection connection = 1674 AccessibilityInteractionClient.getInstance(mService).getConnection( 1675 mService.mConnectionId); 1676 if (connection != null) { 1677 try { 1678 return connection.getMagnificationCenterY(mDisplayId); 1679 } catch (RemoteException re) { 1680 Log.w(LOG_TAG, "Failed to obtain center Y", re); 1681 re.rethrowFromSystemServer(); 1682 } 1683 } 1684 return 0.0f; 1685 } 1686 1687 /** 1688 * Returns the region of the screen currently active for magnification. Changes to 1689 * magnification scale and center only affect this portion of the screen. The rest of the 1690 * screen, for example input methods, cannot be magnified. This region is relative to the 1691 * unscaled screen and is independent of the scale and center point. 1692 * <p> 1693 * The returned region will be empty if magnification is not active. Magnification is active 1694 * if magnification gestures are enabled or if a service is running that can control 1695 * magnification. 1696 * <p> 1697 * <strong>Note:</strong> If the service is not yet connected (e.g. 1698 * {@link AccessibilityService#onServiceConnected()} has not yet been 1699 * called) or the service has been disconnected, this method will 1700 * return an empty region. 1701 * </p> 1702 * <p> 1703 * <strong>Note:</strong> This legacy API gets the magnification region of full-screen 1704 * magnification. To get the magnification region of the current controlling magnifier, 1705 * use {@link #getCurrentMagnificationRegion()} instead. 1706 * </p> 1707 * 1708 * @return the region of the screen currently active for magnification, or an empty region 1709 * if magnification is not active. 1710 * @deprecated Use {@link #getCurrentMagnificationRegion()} instead 1711 */ 1712 @Deprecated 1713 @NonNull getMagnificationRegion()1714 public Region getMagnificationRegion() { 1715 final IAccessibilityServiceConnection connection = 1716 AccessibilityInteractionClient.getInstance(mService).getConnection( 1717 mService.mConnectionId); 1718 if (connection != null) { 1719 try { 1720 return connection.getMagnificationRegion(mDisplayId); 1721 } catch (RemoteException re) { 1722 Log.w(LOG_TAG, "Failed to obtain magnified region", re); 1723 re.rethrowFromSystemServer(); 1724 } 1725 } 1726 return Region.obtain(); 1727 } 1728 1729 /** 1730 * Returns the region of the screen currently active for magnification if the 1731 * controlling magnification is {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}. 1732 * Returns the region of screen projected on the magnification window if the 1733 * controlling magnification is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}. 1734 * 1735 * <p> 1736 * If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}, 1737 * the returned region will be empty if the magnification is 1738 * not active. And the magnification is active if magnification gestures are enabled 1739 * or if a service is running that can control magnification. 1740 * </p><p> 1741 * If the controlling mode is {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, 1742 * the returned region will be empty if the magnification is not activated. 1743 * </p><p> 1744 * <strong>Note:</strong> If the service is not yet connected (e.g. 1745 * {@link AccessibilityService#onServiceConnected()} has not yet been 1746 * called) or the service has been disconnected, this method will 1747 * return an empty region. 1748 * </p> 1749 * 1750 * @return the magnification region of the currently controlling magnification 1751 */ 1752 @NonNull getCurrentMagnificationRegion()1753 public Region getCurrentMagnificationRegion() { 1754 final IAccessibilityServiceConnection connection = 1755 AccessibilityInteractionClient.getInstance(mService).getConnection( 1756 mService.mConnectionId); 1757 if (connection != null) { 1758 try { 1759 return connection.getCurrentMagnificationRegion(mDisplayId); 1760 } catch (RemoteException re) { 1761 Log.w(LOG_TAG, "Failed to obtain the current magnified region", re); 1762 re.rethrowFromSystemServer(); 1763 } 1764 } 1765 return Region.obtain(); 1766 } 1767 1768 /** 1769 * Resets magnification scale and center to their default (e.g. no 1770 * magnification) values. 1771 * <p> 1772 * <strong>Note:</strong> If the service is not yet connected (e.g. 1773 * {@link AccessibilityService#onServiceConnected()} has not yet been 1774 * called) or the service has been disconnected, this method will have 1775 * no effect and return {@code false}. 1776 * <p> 1777 * <strong>Note:</strong> This legacy API reset full-screen magnification. 1778 * To reset the current controlling magnifier, use 1779 * {@link #resetCurrentMagnification(boolean)} ()} instead. 1780 * </p> 1781 * 1782 * @param animate {@code true} to animate from the current scale and 1783 * center or {@code false} to reset the scale and center 1784 * immediately 1785 * @return {@code true} on success, {@code false} on failure 1786 */ reset(boolean animate)1787 public boolean reset(boolean animate) { 1788 final IAccessibilityServiceConnection connection = 1789 AccessibilityInteractionClient.getInstance(mService).getConnection( 1790 mService.mConnectionId); 1791 if (connection != null) { 1792 try { 1793 return connection.resetMagnification(mDisplayId, animate); 1794 } catch (RemoteException re) { 1795 Log.w(LOG_TAG, "Failed to reset", re); 1796 re.rethrowFromSystemServer(); 1797 } 1798 } 1799 return false; 1800 } 1801 1802 /** 1803 * Resets magnification scale and center of the controlling magnification 1804 * to their default (e.g. no magnification) values. 1805 * <p> 1806 * <strong>Note:</strong> If the service is not yet connected (e.g. 1807 * {@link AccessibilityService#onServiceConnected()} has not yet been 1808 * called) or the service has been disconnected, this method will have 1809 * no effect and return {@code false}. 1810 * </p> 1811 * 1812 * @param animate {@code true} to animate from the current scale and 1813 * center or {@code false} to reset the scale and center 1814 * immediately 1815 * @return {@code true} on success, {@code false} on failure 1816 */ resetCurrentMagnification(boolean animate)1817 public boolean resetCurrentMagnification(boolean animate) { 1818 final IAccessibilityServiceConnection connection = 1819 AccessibilityInteractionClient.getInstance(mService).getConnection( 1820 mService.mConnectionId); 1821 if (connection != null) { 1822 try { 1823 return connection.resetCurrentMagnification(mDisplayId, animate); 1824 } catch (RemoteException re) { 1825 Log.w(LOG_TAG, "Failed to reset", re); 1826 re.rethrowFromSystemServer(); 1827 } 1828 } 1829 return false; 1830 } 1831 1832 /** 1833 * Sets the {@link MagnificationConfig}. The service controls the magnification by 1834 * setting the config. 1835 * <p> 1836 * <strong>Note:</strong> If the service is not yet connected (e.g. 1837 * {@link AccessibilityService#onServiceConnected()} has not yet been 1838 * called) or the service has been disconnected, this method will have 1839 * no effect and return {@code false}. 1840 * </p> 1841 * 1842 * @param config the magnification config 1843 * @param animate {@code true} to animate from the current spec or 1844 * {@code false} to set the spec immediately 1845 * @return {@code true} on success, {@code false} on failure 1846 */ setMagnificationConfig(@onNull MagnificationConfig config, boolean animate)1847 public boolean setMagnificationConfig(@NonNull MagnificationConfig config, 1848 boolean animate) { 1849 final IAccessibilityServiceConnection connection = 1850 AccessibilityInteractionClient.getInstance(mService).getConnection( 1851 mService.mConnectionId); 1852 if (connection != null) { 1853 try { 1854 return connection.setMagnificationConfig(mDisplayId, config, animate); 1855 } catch (RemoteException re) { 1856 Log.w(LOG_TAG, "Failed to set magnification config", re); 1857 re.rethrowFromSystemServer(); 1858 } 1859 } 1860 return false; 1861 } 1862 1863 /** 1864 * Sets the magnification scale. 1865 * <p> 1866 * <strong>Note:</strong> If the service is not yet connected (e.g. 1867 * {@link AccessibilityService#onServiceConnected()} has not yet been 1868 * called) or the service has been disconnected, this method will have 1869 * no effect and return {@code false}. 1870 * <p> 1871 * <strong>Note:</strong> This legacy API sets the scale of full-screen 1872 * magnification. To set the scale of the specified magnifier, 1873 * use {@link #setMagnificationConfig} instead. 1874 * </p> 1875 * 1876 * @param scale the magnification scale to set, must be >= 1 and <= 8 1877 * @param animate {@code true} to animate from the current scale or 1878 * {@code false} to set the scale immediately 1879 * @return {@code true} on success, {@code false} on failure 1880 * @deprecated Use {@link #setMagnificationConfig(MagnificationConfig, boolean)} instead 1881 */ 1882 @Deprecated setScale(float scale, boolean animate)1883 public boolean setScale(float scale, boolean animate) { 1884 final IAccessibilityServiceConnection connection = 1885 AccessibilityInteractionClient.getInstance(mService).getConnection( 1886 mService.mConnectionId); 1887 if (connection != null) { 1888 try { 1889 final MagnificationConfig config = new MagnificationConfig.Builder() 1890 .setMode(MAGNIFICATION_MODE_FULLSCREEN) 1891 .setScale(scale).build(); 1892 return connection.setMagnificationConfig(mDisplayId, config, animate); 1893 } catch (RemoteException re) { 1894 Log.w(LOG_TAG, "Failed to set scale", re); 1895 re.rethrowFromSystemServer(); 1896 } 1897 } 1898 return false; 1899 } 1900 1901 /** 1902 * Sets the center of the magnified viewport. 1903 * <p> 1904 * <strong>Note:</strong> If the service is not yet connected (e.g. 1905 * {@link AccessibilityService#onServiceConnected()} has not yet been 1906 * called) or the service has been disconnected, this method will have 1907 * no effect and return {@code false}. 1908 * </p> 1909 * <p> 1910 * <strong>Note:</strong> This legacy API sets the center of full-screen 1911 * magnification. To set the center of the specified magnifier, 1912 * use {@link #setMagnificationConfig} instead. 1913 * </p> 1914 * 1915 * @param centerX the unscaled screen-relative X coordinate on which to 1916 * center the viewport 1917 * @param centerY the unscaled screen-relative Y coordinate on which to 1918 * center the viewport 1919 * @param animate {@code true} to animate from the current viewport 1920 * center or {@code false} to set the center immediately 1921 * @return {@code true} on success, {@code false} on failure 1922 * @deprecated Use {@link #setMagnificationConfig(MagnificationConfig, boolean)} instead 1923 */ 1924 @Deprecated setCenter(float centerX, float centerY, boolean animate)1925 public boolean setCenter(float centerX, float centerY, boolean animate) { 1926 final IAccessibilityServiceConnection connection = 1927 AccessibilityInteractionClient.getInstance(mService).getConnection( 1928 mService.mConnectionId); 1929 if (connection != null) { 1930 try { 1931 final MagnificationConfig config = new MagnificationConfig.Builder() 1932 .setMode(MAGNIFICATION_MODE_FULLSCREEN) 1933 .setCenterX(centerX).setCenterY(centerY).build(); 1934 return connection.setMagnificationConfig(mDisplayId, config, animate); 1935 } catch (RemoteException re) { 1936 Log.w(LOG_TAG, "Failed to set center", re); 1937 re.rethrowFromSystemServer(); 1938 } 1939 } 1940 return false; 1941 } 1942 1943 /** 1944 * Listener for changes in the state of magnification. 1945 */ 1946 public interface OnMagnificationChangedListener { 1947 /** 1948 * Called when the magnified region, scale, or center changes. 1949 * <p> 1950 * <strong>Note:</strong> This legacy callback notifies only full-screen 1951 * magnification change. 1952 * </p> 1953 * 1954 * @param controller the magnification controller 1955 * @param region the magnification region 1956 * @param scale the new scale 1957 * @param centerX the new X coordinate, in unscaled coordinates, around which 1958 * magnification is focused 1959 * @param centerY the new Y coordinate, in unscaled coordinates, around which 1960 * magnification is focused 1961 * @deprecated Override 1962 * {@link #onMagnificationChanged(MagnificationController, Region, MagnificationConfig)} 1963 * instead 1964 */ 1965 @Deprecated onMagnificationChanged(@onNull MagnificationController controller, @NonNull Region region, float scale, float centerX, float centerY)1966 void onMagnificationChanged(@NonNull MagnificationController controller, 1967 @NonNull Region region, float scale, float centerX, float centerY); 1968 1969 /** 1970 * Called when the magnified region, mode, scale, or center changes of 1971 * all magnification modes. 1972 * <p> 1973 * <strong>Note:</strong> This method can be overridden to listen to the 1974 * magnification changes of all magnification modes then the legacy callback 1975 * would not receive the notifications. 1976 * Skipping calling super when overriding this method results in 1977 * {@link #onMagnificationChanged(MagnificationController, Region, float, float, float)} 1978 * not getting called. 1979 * </p> 1980 * 1981 * @param controller the magnification controller 1982 * @param region the magnification region 1983 * If the config mode is 1984 * {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}, 1985 * it is the region of the screen currently active for magnification. 1986 * that is the same region as {@link #getMagnificationRegion()}. 1987 * If the config mode is 1988 * {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, 1989 * it is the region of screen projected on the magnification window. 1990 * @param config The magnification config. That has the controlling magnification 1991 * mode, the new scale and the new screen-relative center position 1992 */ onMagnificationChanged(@onNull MagnificationController controller, @NonNull Region region, @NonNull MagnificationConfig config)1993 default void onMagnificationChanged(@NonNull MagnificationController controller, 1994 @NonNull Region region, @NonNull MagnificationConfig config) { 1995 if (config.getMode() == MAGNIFICATION_MODE_FULLSCREEN) { 1996 onMagnificationChanged(controller, region, 1997 config.getScale(), config.getCenterX(), config.getCenterY()); 1998 } 1999 } 2000 } 2001 } 2002 2003 /** 2004 * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard 2005 * show mode. 2006 * 2007 * @return the soft keyboard controller 2008 */ 2009 @NonNull getSoftKeyboardController()2010 public final SoftKeyboardController getSoftKeyboardController() { 2011 synchronized (mLock) { 2012 if (mSoftKeyboardController == null) { 2013 mSoftKeyboardController = new SoftKeyboardController(this, mLock); 2014 } 2015 return mSoftKeyboardController; 2016 } 2017 } 2018 2019 /** 2020 * The default implementation returns our default {@link InputMethod}. Subclasses can override 2021 * it to provide their own customized version. Accessibility services need to set the 2022 * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag to use input method APIs. 2023 * 2024 * @return the InputMethod. 2025 */ 2026 @NonNull onCreateInputMethod()2027 public InputMethod onCreateInputMethod() { 2028 return new InputMethod(this); 2029 } 2030 2031 /** 2032 * Returns the InputMethod instance after the system calls {@link #onCreateInputMethod()}, 2033 * which may be used to input text or get editable text selection change notifications. It will 2034 * return null if the accessibility service doesn't set the 2035 * {@link AccessibilityServiceInfo#FLAG_INPUT_METHOD_EDITOR} flag or the system doesn't call 2036 * {@link #onCreateInputMethod()}. 2037 * 2038 * @return the InputMethod instance 2039 */ 2040 @Nullable getInputMethod()2041 public final InputMethod getInputMethod() { 2042 return mInputMethod; 2043 } 2044 onSoftKeyboardShowModeChanged(int showMode)2045 private void onSoftKeyboardShowModeChanged(int showMode) { 2046 if (mSoftKeyboardController != null) { 2047 mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode); 2048 } 2049 } 2050 2051 /** 2052 * Used to control, query, and listen for changes to the soft keyboard show mode. 2053 * <p> 2054 * Accessibility services may request to override the decisions normally made about whether or 2055 * not the soft keyboard is shown. 2056 * <p> 2057 * If multiple services make conflicting requests, the last request is honored. A service may 2058 * register a listener to find out if the mode has changed under it. 2059 * <p> 2060 * If the user takes action to override the behavior behavior requested by an accessibility 2061 * service, the user's request takes precendence, the show mode will be reset to 2062 * {@link AccessibilityService#SHOW_MODE_AUTO}, and services will no longer be able to control 2063 * that aspect of the soft keyboard's behavior. 2064 * <p> 2065 * Note: Because soft keyboards are independent apps, the framework does not have total control 2066 * over their behavior. They may choose to show themselves, or not, without regard to requests 2067 * made here. So the framework will make a best effort to deliver the behavior requested, but 2068 * cannot guarantee success. 2069 * 2070 * @see AccessibilityService#SHOW_MODE_AUTO 2071 * @see AccessibilityService#SHOW_MODE_HIDDEN 2072 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD 2073 */ 2074 public static final class SoftKeyboardController { 2075 private final AccessibilityService mService; 2076 2077 /** 2078 * Map of listeners to their handlers. Lazily created when adding the first 2079 * soft keyboard change listener. 2080 */ 2081 private ArrayMap<OnShowModeChangedListener, Handler> mListeners; 2082 private final Object mLock; 2083 2084 /** @hide */ 2085 @Retention(RetentionPolicy.SOURCE) 2086 @IntDef({ 2087 ENABLE_IME_SUCCESS, 2088 ENABLE_IME_FAIL_BY_ADMIN, 2089 ENABLE_IME_FAIL_UNKNOWN 2090 }) 2091 public @interface EnableImeResult {} 2092 /** 2093 * Return value for {@link #setInputMethodEnabled(String, boolean)}. The action succeeded. 2094 */ 2095 public static final int ENABLE_IME_SUCCESS = 0; 2096 /** 2097 * Return value for {@link #setInputMethodEnabled(String, boolean)}. The action failed 2098 * because the InputMethod is not permitted by device policy manager. 2099 */ 2100 public static final int ENABLE_IME_FAIL_BY_ADMIN = 1; 2101 /** 2102 * Return value for {@link #setInputMethodEnabled(String, boolean)}. The action failed 2103 * and the reason is unknown. 2104 */ 2105 public static final int ENABLE_IME_FAIL_UNKNOWN = 2; 2106 SoftKeyboardController(@onNull AccessibilityService service, @NonNull Object lock)2107 SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) { 2108 mService = service; 2109 mLock = lock; 2110 } 2111 2112 /** 2113 * Called when the service is connected. 2114 */ onServiceConnected()2115 void onServiceConnected() { 2116 synchronized(mLock) { 2117 if (mListeners != null && !mListeners.isEmpty()) { 2118 setSoftKeyboardCallbackEnabled(true); 2119 } 2120 } 2121 } 2122 2123 /** 2124 * Adds the specified change listener to the list of show mode change listeners. The 2125 * callback will occur on the service's main thread. Listener is not called on registration. 2126 */ addOnShowModeChangedListener(@onNull OnShowModeChangedListener listener)2127 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) { 2128 addOnShowModeChangedListener(listener, null); 2129 } 2130 2131 /** 2132 * Adds the specified change listener to the list of soft keyboard show mode change 2133 * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the 2134 * services's main thread if the handler is {@code null}. 2135 * 2136 * @param listener the listener to add, must be non-null 2137 * @param handler the handler on which to callback should execute, or {@code null} to 2138 * execute on the service's main thread 2139 */ addOnShowModeChangedListener(@onNull OnShowModeChangedListener listener, @Nullable Handler handler)2140 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener, 2141 @Nullable Handler handler) { 2142 synchronized (mLock) { 2143 if (mListeners == null) { 2144 mListeners = new ArrayMap<>(); 2145 } 2146 2147 final boolean shouldEnableCallback = mListeners.isEmpty(); 2148 mListeners.put(listener, handler); 2149 2150 if (shouldEnableCallback) { 2151 // This may fail if the service is not connected yet, but if we still have 2152 // listeners when it connects, we can try again. 2153 setSoftKeyboardCallbackEnabled(true); 2154 } 2155 } 2156 } 2157 2158 /** 2159 * Removes the specified change listener from the list of keyboard show mode change 2160 * listeners. 2161 * 2162 * @param listener the listener to remove, must be non-null 2163 * @return {@code true} if the listener was removed, {@code false} otherwise 2164 */ removeOnShowModeChangedListener( @onNull OnShowModeChangedListener listener)2165 public boolean removeOnShowModeChangedListener( 2166 @NonNull OnShowModeChangedListener listener) { 2167 if (mListeners == null) { 2168 return false; 2169 } 2170 2171 synchronized (mLock) { 2172 final int keyIndex = mListeners.indexOfKey(listener); 2173 final boolean hasKey = keyIndex >= 0; 2174 if (hasKey) { 2175 mListeners.removeAt(keyIndex); 2176 } 2177 2178 if (hasKey && mListeners.isEmpty()) { 2179 // We just removed the last listener, so we don't need callbacks from the 2180 // service anymore. 2181 setSoftKeyboardCallbackEnabled(false); 2182 } 2183 2184 return hasKey; 2185 } 2186 } 2187 setSoftKeyboardCallbackEnabled(boolean enabled)2188 private void setSoftKeyboardCallbackEnabled(boolean enabled) { 2189 final IAccessibilityServiceConnection connection = 2190 AccessibilityInteractionClient.getInstance(mService).getConnection( 2191 mService.mConnectionId); 2192 if (connection != null) { 2193 try { 2194 connection.setSoftKeyboardCallbackEnabled(enabled); 2195 } catch (RemoteException re) { 2196 throw new RuntimeException(re); 2197 } 2198 } 2199 } 2200 2201 /** 2202 * Dispatches the soft keyboard show mode change to any registered listeners. This should 2203 * be called on the service's main thread. 2204 */ dispatchSoftKeyboardShowModeChanged(final int showMode)2205 void dispatchSoftKeyboardShowModeChanged(final int showMode) { 2206 final ArrayMap<OnShowModeChangedListener, Handler> entries; 2207 synchronized (mLock) { 2208 if (mListeners == null || mListeners.isEmpty()) { 2209 Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback" 2210 + " with no listeners registered!"); 2211 setSoftKeyboardCallbackEnabled(false); 2212 return; 2213 } 2214 2215 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent 2216 // modification. 2217 entries = new ArrayMap<>(mListeners); 2218 } 2219 2220 for (int i = 0, count = entries.size(); i < count; i++) { 2221 final OnShowModeChangedListener listener = entries.keyAt(i); 2222 final Handler handler = entries.valueAt(i); 2223 if (handler != null) { 2224 handler.post(new Runnable() { 2225 @Override 2226 public void run() { 2227 listener.onShowModeChanged(SoftKeyboardController.this, showMode); 2228 } 2229 }); 2230 } else { 2231 // We're already on the main thread, just run the listener. 2232 listener.onShowModeChanged(this, showMode); 2233 } 2234 } 2235 } 2236 2237 /** 2238 * Returns the show mode of the soft keyboard. 2239 * 2240 * @return the current soft keyboard show mode 2241 * 2242 * @see AccessibilityService#SHOW_MODE_AUTO 2243 * @see AccessibilityService#SHOW_MODE_HIDDEN 2244 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD 2245 */ 2246 @SoftKeyboardShowMode getShowMode()2247 public int getShowMode() { 2248 final IAccessibilityServiceConnection connection = 2249 AccessibilityInteractionClient.getInstance(mService).getConnection( 2250 mService.mConnectionId); 2251 if (connection != null) { 2252 try { 2253 return connection.getSoftKeyboardShowMode(); 2254 } catch (RemoteException re) { 2255 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re); 2256 re.rethrowFromSystemServer(); 2257 } 2258 } 2259 return SHOW_MODE_AUTO; 2260 } 2261 2262 /** 2263 * Sets the soft keyboard show mode. 2264 * <p> 2265 * <strong>Note:</strong> If the service is not yet connected (e.g. 2266 * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the 2267 * service has been disconnected, this method will have no effect and return {@code false}. 2268 * 2269 * @param showMode the new show mode for the soft keyboard 2270 * @return {@code true} on success 2271 * 2272 * @see AccessibilityService#SHOW_MODE_AUTO 2273 * @see AccessibilityService#SHOW_MODE_HIDDEN 2274 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD 2275 */ setShowMode(@oftKeyboardShowMode int showMode)2276 public boolean setShowMode(@SoftKeyboardShowMode int showMode) { 2277 final IAccessibilityServiceConnection connection = 2278 AccessibilityInteractionClient.getInstance(mService).getConnection( 2279 mService.mConnectionId); 2280 if (connection != null) { 2281 try { 2282 return connection.setSoftKeyboardShowMode(showMode); 2283 } catch (RemoteException re) { 2284 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re); 2285 re.rethrowFromSystemServer(); 2286 } 2287 } 2288 return false; 2289 } 2290 2291 /** 2292 * Listener for changes in the soft keyboard show mode. 2293 */ 2294 public interface OnShowModeChangedListener { 2295 /** 2296 * Called when the soft keyboard behavior changes. The default show mode is 2297 * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is 2298 * focused. An AccessibilityService can also request the show mode 2299 * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. 2300 * 2301 * @param controller the soft keyboard controller 2302 * @param showMode the current soft keyboard show mode 2303 */ onShowModeChanged(@onNull SoftKeyboardController controller, @SoftKeyboardShowMode int showMode)2304 void onShowModeChanged(@NonNull SoftKeyboardController controller, 2305 @SoftKeyboardShowMode int showMode); 2306 } 2307 2308 /** 2309 * Switches the current IME for the user for whom the service is enabled. The change will 2310 * persist until the current IME is explicitly changed again, and may persist beyond the 2311 * life cycle of the requesting service. 2312 * 2313 * @param imeId The ID of the input method to make current. This IME must be installed and 2314 * enabled. 2315 * @return {@code true} if the current input method was successfully switched to the input 2316 * method by {@code imeId}, 2317 * {@code false} if the input method specified is not installed, not enabled, or 2318 * otherwise not available to become the current IME 2319 * 2320 * @see android.view.inputmethod.InputMethodInfo#getId() 2321 */ switchToInputMethod(@onNull String imeId)2322 public boolean switchToInputMethod(@NonNull String imeId) { 2323 final IAccessibilityServiceConnection connection = 2324 AccessibilityInteractionClient.getInstance(mService).getConnection( 2325 mService.mConnectionId); 2326 if (connection != null) { 2327 try { 2328 return connection.switchToInputMethod(imeId); 2329 } catch (RemoteException re) { 2330 throw new RuntimeException(re); 2331 } 2332 } 2333 return false; 2334 } 2335 2336 /** 2337 * Enable or disable the specified IME for the user for whom the service is activated. The 2338 * IME needs to be in the same package as the service and needs to be allowed by device 2339 * policy, if there is one. The change will persist until the specified IME is next 2340 * explicitly enabled or disabled by whatever means, such as user choice, and may persist 2341 * beyond the life cycle of the requesting service. 2342 * 2343 * @param imeId The ID of the input method to enable or disable. This IME must be installed. 2344 * @param enabled {@code true} if the input method associated with {@code imeId} should be 2345 * enabled. 2346 * @return status code for the result of enabling/disabling the input method associated 2347 * with {@code imeId}. 2348 * @throws SecurityException if the input method is not in the same package as the service. 2349 * 2350 * @see android.view.inputmethod.InputMethodInfo#getId() 2351 */ 2352 @CheckResult 2353 @EnableImeResult setInputMethodEnabled(@onNull String imeId, boolean enabled)2354 public int setInputMethodEnabled(@NonNull String imeId, boolean enabled) 2355 throws SecurityException { 2356 final IAccessibilityServiceConnection connection = 2357 AccessibilityInteractionClient.getInstance(mService).getConnection( 2358 mService.mConnectionId); 2359 if (connection != null) { 2360 try { 2361 return connection.setInputMethodEnabled(imeId, enabled); 2362 } catch (RemoteException re) { 2363 throw new RuntimeException(re); 2364 } 2365 } 2366 return ENABLE_IME_FAIL_UNKNOWN; 2367 } 2368 } 2369 2370 /** 2371 * Returns the controller for the accessibility button within the system's navigation area. 2372 * This instance may be used to query the accessibility button's state and register listeners 2373 * for interactions with and state changes for the accessibility button when 2374 * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set. 2375 * <p> 2376 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button 2377 * within a navigation area, and as such, use of this class should be considered only as an 2378 * optional feature or shortcut on supported device implementations. 2379 * </p> 2380 * 2381 * @return the accessibility button controller for this {@link AccessibilityService} 2382 */ 2383 @NonNull getAccessibilityButtonController()2384 public final AccessibilityButtonController getAccessibilityButtonController() { 2385 return getAccessibilityButtonController(Display.DEFAULT_DISPLAY); 2386 } 2387 2388 /** 2389 * Returns the controller of specified logical display for the accessibility button within the 2390 * system's navigation area. This instance may be used to query the accessibility button's 2391 * state and register listeners for interactions with and state changes for the accessibility 2392 * button when {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set. 2393 * <p> 2394 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button 2395 * within a navigation area, and as such, use of this class should be considered only as an 2396 * optional feature or shortcut on supported device implementations. 2397 * </p> 2398 * 2399 * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for default 2400 * display. 2401 * @return the accessibility button controller for this {@link AccessibilityService} 2402 */ 2403 @NonNull getAccessibilityButtonController(int displayId)2404 public final AccessibilityButtonController getAccessibilityButtonController(int displayId) { 2405 synchronized (mLock) { 2406 AccessibilityButtonController controller = mAccessibilityButtonControllers.get( 2407 displayId); 2408 if (controller == null) { 2409 controller = new AccessibilityButtonController( 2410 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId)); 2411 mAccessibilityButtonControllers.put(displayId, controller); 2412 } 2413 return controller; 2414 } 2415 } 2416 onAccessibilityButtonClicked(int displayId)2417 private void onAccessibilityButtonClicked(int displayId) { 2418 getAccessibilityButtonController(displayId).dispatchAccessibilityButtonClicked(); 2419 } 2420 onAccessibilityButtonAvailabilityChanged(boolean available)2421 private void onAccessibilityButtonAvailabilityChanged(boolean available) { 2422 getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged( 2423 available); 2424 } 2425 2426 /** Sets the cache status. 2427 * 2428 * <p>If {@code enabled}, enable the cache and prefetching. Otherwise, disable the cache 2429 * and prefetching. 2430 * Note: By default the cache is enabled. 2431 * @param enabled whether to enable or disable the cache. 2432 * @return {@code true} if the cache and connection are not null, so the cache status is set. 2433 */ setCacheEnabled(boolean enabled)2434 public boolean setCacheEnabled(boolean enabled) { 2435 AccessibilityCache cache = 2436 AccessibilityInteractionClient.getCache(mConnectionId); 2437 if (cache == null) { 2438 return false; 2439 } 2440 final IAccessibilityServiceConnection connection = 2441 AccessibilityInteractionClient.getConnection(mConnectionId); 2442 if (connection == null) { 2443 return false; 2444 } 2445 try { 2446 connection.setCacheEnabled(enabled); 2447 cache.setEnabled(enabled); 2448 return true; 2449 } catch (RemoteException re) { 2450 Log.w(LOG_TAG, "Error while setting status of cache", re); 2451 re.rethrowFromSystemServer(); 2452 } 2453 return false; 2454 } 2455 2456 /** Invalidates {@code node} and its subtree in the cache. 2457 * @param node the node to invalidate. 2458 * @return {@code true} if the subtree rooted at {@code node} was invalidated. 2459 */ clearCachedSubtree(@onNull AccessibilityNodeInfo node)2460 public boolean clearCachedSubtree(@NonNull AccessibilityNodeInfo node) { 2461 AccessibilityCache cache = 2462 AccessibilityInteractionClient.getCache(mConnectionId); 2463 if (cache == null) { 2464 return false; 2465 } 2466 return cache.clearSubTree(node); 2467 } 2468 2469 /** Clears the cache. 2470 * @return {@code true} if the cache was cleared 2471 */ clearCache()2472 public boolean clearCache() { 2473 AccessibilityCache cache = 2474 AccessibilityInteractionClient.getCache(mConnectionId); 2475 if (cache == null) { 2476 return false; 2477 } 2478 cache.clear(); 2479 return true; 2480 } 2481 2482 /** Checks if {@code node} is in the cache. 2483 * @param node the node to check. 2484 * @return {@code true} if {@code node} is in the cache. 2485 */ isNodeInCache(@onNull AccessibilityNodeInfo node)2486 public boolean isNodeInCache(@NonNull AccessibilityNodeInfo node) { 2487 AccessibilityCache cache = 2488 AccessibilityInteractionClient.getCache(mConnectionId); 2489 if (cache == null) { 2490 return false; 2491 } 2492 return cache.isNodeInCache(node); 2493 } 2494 2495 /** Returns {@code true} if the cache is enabled. */ isCacheEnabled()2496 public boolean isCacheEnabled() { 2497 AccessibilityCache cache = 2498 AccessibilityInteractionClient.getCache(mConnectionId); 2499 if (cache == null) { 2500 return false; 2501 } 2502 return cache.isEnabled(); 2503 } 2504 2505 /** This is called when the system action list is changed. */ onSystemActionsChanged()2506 public void onSystemActionsChanged() { 2507 } 2508 2509 /** 2510 * Returns a list of system actions available in the system right now. 2511 * <p> 2512 * System actions that correspond to the global action constants will have matching action IDs. 2513 * For example, an with id {@link #GLOBAL_ACTION_BACK} will perform the back action. 2514 * </p> 2515 * <p> 2516 * These actions should be called by {@link #performGlobalAction}. 2517 * </p> 2518 * 2519 * @return A list of available system actions. 2520 */ getSystemActions()2521 public final @NonNull List<AccessibilityAction> getSystemActions() { 2522 IAccessibilityServiceConnection connection = 2523 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2524 if (connection != null) { 2525 try { 2526 return connection.getSystemActions(); 2527 } catch (RemoteException re) { 2528 Log.w(LOG_TAG, "Error while calling getSystemActions", re); 2529 re.rethrowFromSystemServer(); 2530 } 2531 } 2532 return Collections.emptyList(); 2533 } 2534 2535 /** 2536 * Performs a global action. Such an action can be performed 2537 * at any moment regardless of the current application or user 2538 * location in that application. For example going back, going 2539 * home, opening recents, etc. 2540 * 2541 * <p> 2542 * Note: The global action ids themselves give no information about the current availability 2543 * of their corresponding actions. To determine if a global action is available, use 2544 * {@link #getSystemActions()} 2545 * 2546 * @param action The action to perform. 2547 * @return Whether the action was successfully performed. 2548 * 2549 * Perform actions using ids like the id constants referenced below: 2550 * @see #GLOBAL_ACTION_BACK 2551 * @see #GLOBAL_ACTION_HOME 2552 * @see #GLOBAL_ACTION_NOTIFICATIONS 2553 * @see #GLOBAL_ACTION_RECENTS 2554 * @see #GLOBAL_ACTION_DPAD_UP 2555 * @see #GLOBAL_ACTION_DPAD_DOWN 2556 * @see #GLOBAL_ACTION_DPAD_LEFT 2557 * @see #GLOBAL_ACTION_DPAD_RIGHT 2558 * @see #GLOBAL_ACTION_DPAD_CENTER 2559 */ performGlobalAction(int action)2560 public final boolean performGlobalAction(int action) { 2561 IAccessibilityServiceConnection connection = 2562 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2563 if (connection != null) { 2564 try { 2565 return connection.performGlobalAction(action); 2566 } catch (RemoteException re) { 2567 Log.w(LOG_TAG, "Error while calling performGlobalAction", re); 2568 re.rethrowFromSystemServer(); 2569 } 2570 } 2571 return false; 2572 } 2573 2574 /** 2575 * Find the view that has the specified focus type. The search is performed 2576 * across all windows. 2577 * <p> 2578 * <strong>Note:</strong> In order to access the windows your service has 2579 * to declare the capability to retrieve window content by setting the 2580 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 2581 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 2582 * Also the service has to opt-in to retrieve the interactive windows by 2583 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} 2584 * flag. Otherwise, the search will be performed only in the active window. 2585 * </p> 2586 * <p> 2587 * <strong>Note:</strong> If the view with {@link AccessibilityNodeInfo#FOCUS_INPUT} 2588 * is on an embedded view hierarchy which is embedded in a {@link android.view.SurfaceView} via 2589 * {@link android.view.SurfaceView#setChildSurfacePackage}, there is a limitation that this API 2590 * won't be able to find the node for the view. It's because views don't know about 2591 * the embedded hierarchies. Instead, you could traverse all the nodes to find the 2592 * focus. 2593 * </p> 2594 * 2595 * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or 2596 * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}. 2597 * @return The node info of the focused view or null. 2598 * 2599 * @see AccessibilityNodeInfo#FOCUS_INPUT 2600 * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY 2601 */ findFocus(int focus)2602 public AccessibilityNodeInfo findFocus(int focus) { 2603 return AccessibilityInteractionClient.getInstance(this).findFocus(mConnectionId, 2604 AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus); 2605 } 2606 2607 /** 2608 * Gets the an {@link AccessibilityServiceInfo} describing this 2609 * {@link AccessibilityService}. This method is useful if one wants 2610 * to change some of the dynamically configurable properties at 2611 * runtime. 2612 * 2613 * @return The accessibility service info. 2614 * 2615 * @see AccessibilityServiceInfo 2616 */ getServiceInfo()2617 public final AccessibilityServiceInfo getServiceInfo() { 2618 IAccessibilityServiceConnection connection = 2619 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2620 if (connection != null) { 2621 try { 2622 return connection.getServiceInfo(); 2623 } catch (RemoteException re) { 2624 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re); 2625 re.rethrowFromSystemServer(); 2626 } 2627 } 2628 return null; 2629 } 2630 2631 /** 2632 * Sets the {@link AccessibilityServiceInfo} that describes this service. 2633 * <p> 2634 * Note: You can call this method any time but the info will be picked up after 2635 * the system has bound to this service and when this method is called thereafter. 2636 * 2637 * @param info The info. 2638 */ setServiceInfo(AccessibilityServiceInfo info)2639 public final void setServiceInfo(AccessibilityServiceInfo info) { 2640 mInfo = info; 2641 updateInputMethod(info); 2642 mMotionEventSources = info.getMotionEventSources(); 2643 sendServiceInfo(); 2644 } 2645 2646 /** 2647 * Sets the {@link AccessibilityServiceInfo} for this service if the latter is 2648 * properly set and there is an {@link IAccessibilityServiceConnection} to the 2649 * AccessibilityManagerService. 2650 */ sendServiceInfo()2651 private void sendServiceInfo() { 2652 IAccessibilityServiceConnection connection = 2653 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2654 if (mInfo != null && connection != null) { 2655 try { 2656 connection.setServiceInfo(mInfo); 2657 mInfo = null; 2658 AccessibilityInteractionClient.getInstance(this).clearCache(mConnectionId); 2659 } catch (RemoteException re) { 2660 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re); 2661 re.rethrowFromSystemServer(); 2662 } 2663 } 2664 } 2665 2666 @Override getSystemService(@erviceName @onNull String name)2667 public Object getSystemService(@ServiceName @NonNull String name) { 2668 if (getBaseContext() == null) { 2669 throw new IllegalStateException( 2670 "System services not available to Activities before onCreate()"); 2671 } 2672 2673 // Guarantee that we always return the same window manager instance. 2674 if (WINDOW_SERVICE.equals(name)) { 2675 if (mWindowManager == null) { 2676 mWindowManager = (WindowManager) getBaseContext().getSystemService(name); 2677 final WindowManagerImpl wm = (WindowManagerImpl) mWindowManager; 2678 // Set e default token obtained from the connection to ensure client could use 2679 // accessibility overlay. 2680 wm.setDefaultToken(mWindowToken); 2681 } 2682 return mWindowManager; 2683 } 2684 return super.getSystemService(name); 2685 } 2686 2687 /** 2688 * Takes a screenshot of the specified display and returns it via an 2689 * {@link AccessibilityService.ScreenshotResult}. You can use {@link Bitmap#wrapHardwareBuffer} 2690 * to construct the bitmap from the ScreenshotResult's payload. 2691 * <p> 2692 * <strong>Note:</strong> In order to take screenshot your service has 2693 * to declare the capability to take screenshot by setting the 2694 * {@link android.R.styleable#AccessibilityService_canTakeScreenshot} 2695 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 2696 * </p> 2697 * 2698 * @param displayId The logic display id, must be {@link Display#DEFAULT_DISPLAY} for 2699 * default display. 2700 * @param executor Executor on which to run the callback. 2701 * @param callback The callback invoked when taking screenshot has succeeded or failed. 2702 * See {@link TakeScreenshotCallback} for details. 2703 * @see #takeScreenshotOfWindow 2704 */ takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor, @NonNull TakeScreenshotCallback callback)2705 public void takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor, 2706 @NonNull TakeScreenshotCallback callback) { 2707 Preconditions.checkNotNull(executor, "executor cannot be null"); 2708 Preconditions.checkNotNull(callback, "callback cannot be null"); 2709 final IAccessibilityServiceConnection connection = 2710 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2711 if (connection == null) { 2712 sendScreenshotFailure(ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, executor, callback); 2713 return; 2714 } 2715 try { 2716 connection.takeScreenshot(displayId, new RemoteCallback((result) -> { 2717 final int status = result.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS); 2718 if (status != TAKE_SCREENSHOT_SUCCESS) { 2719 sendScreenshotFailure(status, executor, callback); 2720 return; 2721 } 2722 final HardwareBuffer hardwareBuffer = 2723 result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER, android.hardware.HardwareBuffer.class); 2724 final ParcelableColorSpace colorSpace = 2725 result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, 2726 android.graphics.ParcelableColorSpace.class); 2727 final ScreenshotResult screenshot = new ScreenshotResult(hardwareBuffer, 2728 colorSpace.getColorSpace(), 2729 result.getLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP)); 2730 sendScreenshotSuccess(screenshot, executor, callback); 2731 })); 2732 } catch (RemoteException re) { 2733 throw new RuntimeException(re); 2734 } 2735 } 2736 2737 /** 2738 * Takes a screenshot of the specified window and returns it via an 2739 * {@link AccessibilityService.ScreenshotResult}. You can use {@link Bitmap#wrapHardwareBuffer} 2740 * to construct the bitmap from the ScreenshotResult's payload. 2741 * <p> 2742 * <strong>Note:</strong> In order to take screenshots your service has 2743 * to declare the capability to take screenshot by setting the 2744 * {@link android.R.styleable#AccessibilityService_canTakeScreenshot} 2745 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 2746 * </p> 2747 * <p> 2748 * Both this method and {@link #takeScreenshot} can be used for machine learning-based visual 2749 * screen understanding. Use <code>takeScreenshotOfWindow</code> if your target window might be 2750 * visually underneath an accessibility overlay (from your or another accessibility service) in 2751 * order to capture the window contents without the screenshot being covered by the overlay 2752 * contents drawn on the screen. 2753 * </p> 2754 * 2755 * @param accessibilityWindowId The window id, from {@link AccessibilityWindowInfo#getId()}. 2756 * @param executor Executor on which to run the callback. 2757 * @param callback The callback invoked when taking screenshot has succeeded or failed. 2758 * See {@link TakeScreenshotCallback} for details. 2759 * @see #takeScreenshot 2760 */ takeScreenshotOfWindow(int accessibilityWindowId, @NonNull @CallbackExecutor Executor executor, @NonNull TakeScreenshotCallback callback)2761 public void takeScreenshotOfWindow(int accessibilityWindowId, 2762 @NonNull @CallbackExecutor Executor executor, 2763 @NonNull TakeScreenshotCallback callback) { 2764 AccessibilityInteractionClient.getInstance(this).takeScreenshotOfWindow( 2765 mConnectionId, accessibilityWindowId, executor, callback); 2766 } 2767 2768 /** 2769 * Sets the strokeWidth and color of the accessibility focus rectangle. 2770 * <p> 2771 * <strong>Note:</strong> This setting persists until this or another active 2772 * AccessibilityService changes it or the device reboots. 2773 * </p> 2774 * 2775 * @param strokeWidth The stroke width of the rectangle in pixels. 2776 * Setting this value to zero results in no focus rectangle being drawn. 2777 * @param color The color of the rectangle. 2778 */ setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color)2779 public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) { 2780 IAccessibilityServiceConnection connection = 2781 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2782 if (connection != null) { 2783 try { 2784 connection.setFocusAppearance(strokeWidth, color); 2785 } catch (RemoteException re) { 2786 Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the " 2787 + "accessibility focus rectangle", re); 2788 re.rethrowFromSystemServer(); 2789 } 2790 } 2791 } 2792 2793 /** 2794 * Implement to return the implementation of the internal accessibility 2795 * service interface. 2796 */ 2797 @Override onBind(Intent intent)2798 public final IBinder onBind(Intent intent) { 2799 return new IAccessibilityServiceClientWrapper(this, getMainExecutor(), new Callbacks() { 2800 @Override 2801 public void onServiceConnected() { 2802 AccessibilityService.this.dispatchServiceConnected(); 2803 } 2804 2805 @Override 2806 public void onInterrupt() { 2807 AccessibilityService.this.onInterrupt(); 2808 } 2809 2810 @Override 2811 public void onAccessibilityEvent(AccessibilityEvent event) { 2812 AccessibilityService.this.onAccessibilityEvent(event); 2813 } 2814 2815 @Override 2816 public void init(int connectionId, IBinder windowToken) { 2817 mConnectionId = connectionId; 2818 mWindowToken = windowToken; 2819 2820 // The client may have already obtained the window manager, so 2821 // update the default token on whatever manager we gave them. 2822 if (mWindowManager != null) { 2823 final WindowManagerImpl wm = (WindowManagerImpl) mWindowManager; 2824 wm.setDefaultToken(mWindowToken); 2825 } 2826 } 2827 2828 @Override 2829 public boolean onGesture(AccessibilityGestureEvent gestureEvent) { 2830 return AccessibilityService.this.onGesture(gestureEvent); 2831 } 2832 2833 @Override 2834 public boolean onKeyEvent(KeyEvent event) { 2835 return AccessibilityService.this.onKeyEvent(event); 2836 } 2837 2838 @Override 2839 public void onMagnificationChanged(int displayId, @NonNull Region region, 2840 MagnificationConfig config) { 2841 AccessibilityService.this.onMagnificationChanged(displayId, region, config); 2842 } 2843 2844 @Override 2845 public void onMotionEvent(MotionEvent event) { 2846 AccessibilityService.this.sendMotionEventToCallback(event); 2847 } 2848 2849 @Override 2850 public void onTouchStateChanged(int displayId, int state) { 2851 AccessibilityService.this.onTouchStateChanged(displayId, state); 2852 } 2853 2854 @Override 2855 public void onSoftKeyboardShowModeChanged(int showMode) { 2856 AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode); 2857 } 2858 2859 @Override 2860 public void onPerformGestureResult(int sequence, boolean completedSuccessfully) { 2861 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully); 2862 } 2863 2864 @Override 2865 public void onFingerprintCapturingGesturesChanged(boolean active) { 2866 AccessibilityService.this.onFingerprintCapturingGesturesChanged(active); 2867 } 2868 2869 @Override 2870 public void onFingerprintGesture(int gesture) { 2871 AccessibilityService.this.onFingerprintGesture(gesture); 2872 } 2873 2874 @Override 2875 public void onAccessibilityButtonClicked(int displayId) { 2876 AccessibilityService.this.onAccessibilityButtonClicked(displayId); 2877 } 2878 2879 @Override 2880 public void onAccessibilityButtonAvailabilityChanged(boolean available) { 2881 AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available); 2882 } 2883 2884 @Override 2885 public void onSystemActionsChanged() { 2886 AccessibilityService.this.onSystemActionsChanged(); 2887 } 2888 2889 @Override 2890 public void createImeSession(IAccessibilityInputMethodSessionCallback callback) { 2891 if (mInputMethod != null) { 2892 mInputMethod.createImeSession(callback); 2893 } 2894 } 2895 2896 @Override 2897 public void startInput(@Nullable RemoteAccessibilityInputConnection connection, 2898 @NonNull EditorInfo editorInfo, boolean restarting) { 2899 if (mInputMethod != null) { 2900 if (restarting) { 2901 mInputMethod.restartInput(connection, editorInfo); 2902 } else { 2903 mInputMethod.startInput(connection, editorInfo); 2904 } 2905 } 2906 } 2907 }); 2908 } 2909 2910 /** 2911 * Implements the internal {@link IAccessibilityServiceClient} interface to convert 2912 * incoming calls to it back to calls on an {@link AccessibilityService}. 2913 * 2914 * @hide 2915 */ 2916 public static class IAccessibilityServiceClientWrapper extends 2917 IAccessibilityServiceClient.Stub { 2918 2919 private final Callbacks mCallback; 2920 private final Context mContext; 2921 private final Executor mExecutor; 2922 2923 private int mConnectionId = AccessibilityInteractionClient.NO_ID; 2924 2925 /** 2926 * This is not {@code null} only between {@link #bindInput()} and {@link #unbindInput()} so 2927 * that {@link RemoteAccessibilityInputConnection} can query if {@link #unbindInput()} has 2928 * already been called or not, mainly to avoid unnecessary blocking operations. 2929 * 2930 * <p>This field must be set and cleared only from the binder thread(s), where the system 2931 * guarantees that {@link #bindInput()}, 2932 * {@link #startInput(IRemoteAccessibilityInputConnection, EditorInfo, boolean)}, 2933 * and {@link #unbindInput()} are called with the same order as the original calls 2934 * in {@link com.android.server.inputmethod.InputMethodManagerService}. 2935 * See {@link IBinder#FLAG_ONEWAY} for detailed semantics.</p> 2936 */ 2937 @Nullable 2938 CancellationGroup mCancellationGroup = null; 2939 2940 public IAccessibilityServiceClientWrapper(Context context, Executor executor, 2941 Callbacks callback) { 2942 mCallback = callback; 2943 mContext = context; 2944 mExecutor = executor; 2945 } 2946 2947 public IAccessibilityServiceClientWrapper(Context context, Looper looper, 2948 Callbacks callback) { 2949 this(context, new HandlerExecutor(new Handler(looper)), callback); 2950 } 2951 2952 public void init(IAccessibilityServiceConnection connection, int connectionId, 2953 IBinder windowToken) { 2954 mExecutor.execute(() -> { 2955 mConnectionId = connectionId; 2956 if (connection != null) { 2957 AccessibilityInteractionClient.getInstance(mContext).addConnection( 2958 mConnectionId, connection, /*initializeCache=*/true); 2959 if (mContext != null) { 2960 try { 2961 connection.setAttributionTag(mContext.getAttributionTag()); 2962 } catch (RemoteException re) { 2963 Log.w(LOG_TAG, "Error while setting attributionTag", re); 2964 re.rethrowFromSystemServer(); 2965 } 2966 } 2967 mCallback.init(mConnectionId, windowToken); 2968 mCallback.onServiceConnected(); 2969 } else { 2970 AccessibilityInteractionClient.getInstance(mContext) 2971 .clearCache(mConnectionId); 2972 AccessibilityInteractionClient.getInstance(mContext).removeConnection( 2973 mConnectionId); 2974 mConnectionId = AccessibilityInteractionClient.NO_ID; 2975 mCallback.init(AccessibilityInteractionClient.NO_ID, null); 2976 } 2977 return; 2978 }); 2979 } 2980 2981 public void onInterrupt() { 2982 mExecutor.execute(() -> { 2983 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2984 mCallback.onInterrupt(); 2985 } 2986 }); 2987 } 2988 2989 public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) { 2990 mExecutor.execute(() -> { 2991 if (event != null) { 2992 // Send the event to AccessibilityCache via AccessibilityInteractionClient 2993 AccessibilityInteractionClient.getInstance(mContext).onAccessibilityEvent( 2994 event, mConnectionId); 2995 if (serviceWantsEvent 2996 && (mConnectionId != AccessibilityInteractionClient.NO_ID)) { 2997 // Send the event to AccessibilityService 2998 mCallback.onAccessibilityEvent(event); 2999 } 3000 } 3001 return; 3002 }); 3003 } 3004 3005 @Override 3006 public void onGesture(AccessibilityGestureEvent gestureInfo) { 3007 mExecutor.execute(() -> { 3008 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3009 mCallback.onGesture(gestureInfo); 3010 } 3011 return; 3012 }); 3013 } 3014 3015 public void clearAccessibilityCache() { 3016 mExecutor.execute(() -> { 3017 AccessibilityInteractionClient.getInstance(mContext).clearCache(mConnectionId); 3018 return; 3019 }); 3020 } 3021 3022 @Override 3023 public void onKeyEvent(KeyEvent event, int sequence) { 3024 mExecutor.execute(() -> { 3025 try { 3026 IAccessibilityServiceConnection connection = AccessibilityInteractionClient 3027 .getInstance(mContext).getConnection(mConnectionId); 3028 if (connection != null) { 3029 final boolean result = mCallback.onKeyEvent(event); 3030 try { 3031 connection.setOnKeyEventResult(result, sequence); 3032 } catch (RemoteException re) { 3033 /* ignore */ 3034 } 3035 } 3036 } finally { 3037 // Make sure the event is recycled. 3038 try { 3039 event.recycle(); 3040 } catch (IllegalStateException ise) { 3041 /* ignore - best effort */ 3042 } 3043 } 3044 return; 3045 }); 3046 } 3047 3048 /** Magnification changed callbacks for different displays */ 3049 public void onMagnificationChanged(int displayId, @NonNull Region region, 3050 MagnificationConfig config) { 3051 mExecutor.execute(() -> { 3052 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3053 mCallback.onMagnificationChanged(displayId, region, config); 3054 } 3055 return; 3056 }); 3057 } 3058 3059 public void onSoftKeyboardShowModeChanged(int showMode) { 3060 mExecutor.execute(() -> { 3061 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3062 mCallback.onSoftKeyboardShowModeChanged(showMode); 3063 } 3064 return; 3065 }); 3066 } 3067 3068 public void onPerformGestureResult(int sequence, boolean successfully) { 3069 mExecutor.execute(() -> { 3070 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3071 mCallback.onPerformGestureResult(sequence, successfully); 3072 } 3073 return; 3074 }); 3075 } 3076 3077 public void onFingerprintCapturingGesturesChanged(boolean active) { 3078 mExecutor.execute(() -> { 3079 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3080 mCallback.onFingerprintCapturingGesturesChanged(active); 3081 } 3082 return; 3083 }); 3084 } 3085 3086 public void onFingerprintGesture(int gesture) { 3087 mExecutor.execute(() -> { 3088 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3089 mCallback.onFingerprintGesture(gesture); 3090 } 3091 return; 3092 }); 3093 } 3094 3095 /** Accessibility button clicked callbacks for different displays */ 3096 public void onAccessibilityButtonClicked(int displayId) { 3097 mExecutor.execute(() -> { 3098 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3099 mCallback.onAccessibilityButtonClicked(displayId); 3100 } 3101 return; 3102 }); 3103 } 3104 3105 public void onAccessibilityButtonAvailabilityChanged(boolean available) { 3106 mExecutor.execute(() -> { 3107 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3108 mCallback.onAccessibilityButtonAvailabilityChanged(available); 3109 } 3110 return; 3111 }); 3112 } 3113 3114 /** This is called when the system action list is changed. */ 3115 public void onSystemActionsChanged() { 3116 mExecutor.execute(() -> { 3117 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3118 mCallback.onSystemActionsChanged(); 3119 } 3120 return; 3121 }); 3122 } 3123 3124 /** This is called when an app requests ime sessions or when the service is enabled. */ 3125 public void createImeSession(IAccessibilityInputMethodSessionCallback callback) { 3126 mExecutor.execute(() -> { 3127 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3128 mCallback.createImeSession(callback); 3129 } 3130 }); 3131 } 3132 3133 /** 3134 * This is called when InputMethodManagerService requests to set the session enabled or 3135 * disabled 3136 */ 3137 public void setImeSessionEnabled(IAccessibilityInputMethodSession session, 3138 boolean enabled) { 3139 try { 3140 AccessibilityInputMethodSession ls = 3141 ((AccessibilityInputMethodSessionWrapper) session).getSession(); 3142 if (ls == null) { 3143 Log.w(LOG_TAG, "Session is already finished: " + session); 3144 return; 3145 } 3146 mExecutor.execute(() -> { 3147 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3148 ls.setEnabled(enabled); 3149 } 3150 return; 3151 }); 3152 } catch (ClassCastException e) { 3153 Log.w(LOG_TAG, "Incoming session not of correct type: " + session, e); 3154 } 3155 } 3156 3157 /** This is called when an app binds input or when the service is enabled. */ 3158 public void bindInput() { 3159 if (mCancellationGroup != null) { 3160 Log.e(LOG_TAG, "bindInput must be paired with unbindInput."); 3161 } 3162 mCancellationGroup = new CancellationGroup(); 3163 } 3164 3165 /** This is called when an app unbinds input or when the service is disabled. */ 3166 public void unbindInput() { 3167 if (mCancellationGroup != null) { 3168 // Signal the flag then forget it. 3169 mCancellationGroup.cancelAll(); 3170 mCancellationGroup = null; 3171 } else { 3172 Log.e(LOG_TAG, "unbindInput must be paired with bindInput."); 3173 } 3174 } 3175 3176 /** This is called when an app starts input or when the service is enabled. */ 3177 public void startInput(IRemoteAccessibilityInputConnection connection, 3178 EditorInfo editorInfo, boolean restarting) { 3179 if (mCancellationGroup == null) { 3180 Log.e(LOG_TAG, "startInput must be called after bindInput."); 3181 mCancellationGroup = new CancellationGroup(); 3182 } 3183 mExecutor.execute(() -> { 3184 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 3185 final RemoteAccessibilityInputConnection ic = connection == null ? null 3186 : new RemoteAccessibilityInputConnection( 3187 connection, mCancellationGroup); 3188 editorInfo.makeCompatible(mContext.getApplicationInfo().targetSdkVersion); 3189 mCallback.startInput(ic, editorInfo, restarting); 3190 } 3191 }); 3192 } 3193 3194 @Override 3195 public void onMotionEvent(MotionEvent event) { 3196 mExecutor.execute(() -> { 3197 mCallback.onMotionEvent(event); 3198 }); 3199 } 3200 3201 @Override 3202 public void onTouchStateChanged(int displayId, int state) { 3203 mExecutor.execute(() -> { 3204 mCallback.onTouchStateChanged(displayId, state); 3205 }); 3206 } 3207 } 3208 3209 /** 3210 * Class used to report status of dispatched gestures 3211 */ 3212 public static abstract class GestureResultCallback { 3213 /** Called when the gesture has completed successfully 3214 * 3215 * @param gestureDescription The description of the gesture that completed. 3216 */ 3217 public void onCompleted(GestureDescription gestureDescription) { 3218 } 3219 3220 /** Called when the gesture was cancelled 3221 * 3222 * @param gestureDescription The description of the gesture that was cancelled. 3223 */ 3224 public void onCancelled(GestureDescription gestureDescription) { 3225 } 3226 } 3227 3228 /* Object to keep track of gesture result callbacks */ 3229 private static class GestureResultCallbackInfo { 3230 GestureDescription gestureDescription; 3231 GestureResultCallback callback; 3232 Handler handler; 3233 3234 GestureResultCallbackInfo(GestureDescription gestureDescription, 3235 GestureResultCallback callback, Handler handler) { 3236 this.gestureDescription = gestureDescription; 3237 this.callback = callback; 3238 this.handler = handler; 3239 } 3240 } 3241 3242 private void sendScreenshotSuccess(ScreenshotResult screenshot, Executor executor, 3243 TakeScreenshotCallback callback) { 3244 executor.execute(() -> callback.onSuccess(screenshot)); 3245 } 3246 3247 private void sendScreenshotFailure(@ScreenshotErrorCode int errorCode, Executor executor, 3248 TakeScreenshotCallback callback) { 3249 executor.execute(() -> callback.onFailure(errorCode)); 3250 } 3251 3252 /** 3253 * Interface used to report status of taking screenshot. 3254 */ 3255 public interface TakeScreenshotCallback { 3256 /** Called when taking screenshot has completed successfully. 3257 * 3258 * @param screenshot The content of screenshot. 3259 */ 3260 void onSuccess(@NonNull ScreenshotResult screenshot); 3261 3262 /** Called when taking screenshot has failed. {@code errorCode} will identify the 3263 * reason of failure. 3264 * 3265 * @param errorCode The error code of this operation. 3266 */ 3267 void onFailure(@ScreenshotErrorCode int errorCode); 3268 } 3269 3270 /** 3271 * Can be used to construct a bitmap of the screenshot or any other operations for 3272 * {@link AccessibilityService#takeScreenshot} API. 3273 */ 3274 public static final class ScreenshotResult { 3275 private final @NonNull HardwareBuffer mHardwareBuffer; 3276 private final @NonNull ColorSpace mColorSpace; 3277 private final long mTimestamp; 3278 3279 /** @hide */ 3280 public ScreenshotResult(@NonNull HardwareBuffer hardwareBuffer, 3281 @NonNull ColorSpace colorSpace, long timestamp) { 3282 Preconditions.checkNotNull(hardwareBuffer, "hardwareBuffer cannot be null"); 3283 Preconditions.checkNotNull(colorSpace, "colorSpace cannot be null"); 3284 mHardwareBuffer = hardwareBuffer; 3285 mColorSpace = colorSpace; 3286 mTimestamp = timestamp; 3287 } 3288 3289 /** 3290 * Gets the {@link ColorSpace} identifying a specific organization of colors of the 3291 * screenshot. 3292 * 3293 * @return the color space 3294 */ 3295 @NonNull 3296 public ColorSpace getColorSpace() { 3297 return mColorSpace; 3298 } 3299 3300 /** 3301 * Gets the {@link HardwareBuffer} representing a memory buffer of the screenshot. 3302 * <p> 3303 * <strong>Note:</strong> The application should call {@link HardwareBuffer#close()} when 3304 * the buffer is no longer needed to free the underlying resources. 3305 * </p> 3306 * 3307 * @return the hardware buffer 3308 */ 3309 @NonNull 3310 public HardwareBuffer getHardwareBuffer() { 3311 return mHardwareBuffer; 3312 } 3313 3314 /** 3315 * Gets the timestamp of taking the screenshot. 3316 * 3317 * @return milliseconds of non-sleep uptime before screenshot since boot and it's from 3318 * {@link SystemClock#uptimeMillis()} 3319 */ 3320 public long getTimestamp() { 3321 return mTimestamp; 3322 }; 3323 } 3324 3325 /** 3326 * When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this 3327 * function requests that touch interactions starting in the specified region of the screen 3328 * bypass the gesture detector. There can only be one gesture detection passthrough region per 3329 * display. Requesting a new gesture detection passthrough region clears the existing one. To 3330 * disable this passthrough and return to the original behavior, pass in an empty region. When 3331 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this 3332 * function has no effect. 3333 * 3334 * @param displayId The display on which to set this region. 3335 * @param region the region of the screen. 3336 */ 3337 public void setGestureDetectionPassthroughRegion(int displayId, @NonNull Region region) { 3338 Preconditions.checkNotNull(region, "region cannot be null"); 3339 final IAccessibilityServiceConnection connection = 3340 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 3341 if (connection != null) { 3342 try { 3343 connection.setGestureDetectionPassthroughRegion(displayId, region); 3344 } catch (RemoteException re) { 3345 throw new RuntimeException(re); 3346 } 3347 } 3348 } 3349 3350 /** 3351 * When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this 3352 * function requests that touch interactions starting in the specified region of the screen 3353 * bypass the touch explorer and go straight to the view hierarchy. There can only be one touch 3354 * exploration passthrough region per display. Requesting a new touch explorationpassthrough 3355 * region clears the existing one. To disable this passthrough and return to the original 3356 * behavior, pass in an empty region. When {@link 3357 * AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this function has 3358 * no effect. 3359 * 3360 * @param displayId The display on which to set this region. 3361 * @param region the region of the screen . 3362 */ 3363 public void setTouchExplorationPassthroughRegion(int displayId, @NonNull Region region) { 3364 Preconditions.checkNotNull(region, "region cannot be null"); 3365 final IAccessibilityServiceConnection connection = 3366 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 3367 if (connection != null) { 3368 try { 3369 connection.setTouchExplorationPassthroughRegion(displayId, region); 3370 } catch (RemoteException re) { 3371 throw new RuntimeException(re); 3372 } 3373 } 3374 } 3375 3376 /** 3377 * Sets the system settings values that control the scaling factor for animations. The scale 3378 * controls the animation playback speed for animations that respect these settings. Animations 3379 * that do not respect the settings values will not be affected by this function. A lower scale 3380 * value results in a faster speed. A value of <code>0</code> disables animations entirely. When 3381 * animations are disabled services receive window change events more quickly which can reduce 3382 * the potential by confusion by reducing the time during which windows are in transition. 3383 * 3384 * @see AccessibilityEvent#TYPE_WINDOWS_CHANGED 3385 * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 3386 * @see android.provider.Settings.Global#WINDOW_ANIMATION_SCALE 3387 * @see android.provider.Settings.Global#TRANSITION_ANIMATION_SCALE 3388 * @see android.provider.Settings.Global#ANIMATOR_DURATION_SCALE 3389 * @param scale The scaling factor for all animations. 3390 */ 3391 public void setAnimationScale(float scale) { 3392 final IAccessibilityServiceConnection connection = 3393 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 3394 if (connection != null) { 3395 try { 3396 connection.setAnimationScale(scale); 3397 } catch (RemoteException re) { 3398 throw new RuntimeException(re); 3399 } 3400 } 3401 } 3402 3403 private static class AccessibilityContext extends ContextWrapper { 3404 private final int mConnectionId; 3405 3406 private AccessibilityContext(Context base, int connectionId) { 3407 super(base); 3408 mConnectionId = connectionId; 3409 setDefaultTokenInternal(this, getDisplayId()); 3410 } 3411 3412 @NonNull 3413 @Override 3414 public Context createDisplayContext(Display display) { 3415 return new AccessibilityContext(super.createDisplayContext(display), mConnectionId); 3416 } 3417 3418 @NonNull 3419 @Override 3420 public Context createWindowContext(int type, @Nullable Bundle options) { 3421 final Context context = super.createWindowContext(type, options); 3422 if (type != TYPE_ACCESSIBILITY_OVERLAY) { 3423 return context; 3424 } 3425 return new AccessibilityContext(context, mConnectionId); 3426 } 3427 3428 @NonNull 3429 @Override 3430 public Context createWindowContext(@NonNull Display display, int type, 3431 @Nullable Bundle options) { 3432 final Context context = super.createWindowContext(display, type, options); 3433 if (type != TYPE_ACCESSIBILITY_OVERLAY) { 3434 return context; 3435 } 3436 return new AccessibilityContext(context, mConnectionId); 3437 } 3438 3439 private void setDefaultTokenInternal(Context context, int displayId) { 3440 final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService( 3441 WINDOW_SERVICE); 3442 final IAccessibilityServiceConnection connection = 3443 AccessibilityInteractionClient.getConnection(mConnectionId); 3444 IBinder token = null; 3445 if (connection != null) { 3446 try { 3447 token = connection.getOverlayWindowToken(displayId); 3448 } catch (RemoteException re) { 3449 Log.w(LOG_TAG, "Failed to get window token", re); 3450 re.rethrowFromSystemServer(); 3451 } 3452 wm.setDefaultToken(token); 3453 } 3454 } 3455 } 3456 3457 /** 3458 * Returns the touch interaction controller for the specified logical display, which may be used 3459 * to detect gestures and otherwise control touch interactions. If 3460 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled the 3461 * controller's methods will have no effect. 3462 * 3463 * @param displayId The logical display id, use {@link Display#DEFAULT_DISPLAY} for default 3464 * display. 3465 * @return the TouchExploration controller 3466 */ 3467 @NonNull 3468 public final TouchInteractionController getTouchInteractionController(int displayId) { 3469 synchronized (mLock) { 3470 TouchInteractionController controller = mTouchInteractionControllers.get(displayId); 3471 if (controller == null) { 3472 controller = new TouchInteractionController(this, mLock, displayId); 3473 mTouchInteractionControllers.put(displayId, controller); 3474 } 3475 return controller; 3476 } 3477 } 3478 3479 void sendMotionEventToCallback(MotionEvent event) { 3480 boolean sendingTouchEventToTouchInteractionController = false; 3481 if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) { 3482 TouchInteractionController controller; 3483 synchronized (mLock) { 3484 int displayId = event.getDisplayId(); 3485 controller = mTouchInteractionControllers.get(displayId); 3486 } 3487 if (controller != null) { 3488 sendingTouchEventToTouchInteractionController = true; 3489 controller.onMotionEvent(event); 3490 } 3491 } 3492 final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK; 3493 if ((mMotionEventSources & eventSourceWithoutClass) != 0 3494 && !sendingTouchEventToTouchInteractionController) { 3495 onMotionEvent(event); 3496 } 3497 } 3498 3499 void onTouchStateChanged(int displayId, int state) { 3500 TouchInteractionController controller; 3501 synchronized (mLock) { 3502 controller = mTouchInteractionControllers.get(displayId); 3503 } 3504 if (controller != null) { 3505 controller.onStateChanged(state); 3506 } 3507 } 3508 3509 /** 3510 * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the 3511 * specified display. This type of overlay should be used for content that does not need to 3512 * track the location and size of Views in the currently active app e.g. service configuration 3513 * or general service UI. 3514 * 3515 * <p>Generally speaking, an accessibility overlay will be a {@link android.view.View}. To embed 3516 * the View into a {@link android.view.SurfaceControl}, create a {@link 3517 * android.view.SurfaceControlViewHost} and attach the View using {@link 3518 * android.view.SurfaceControlViewHost#setView}. Then obtain the SurfaceControl by calling 3519 * <code> viewHost.getSurfacePackage().getSurfaceControl()</code>. 3520 * 3521 * <p>To remove this overlay and free the associated resources, use <code> 3522 * new SurfaceControl.Transaction().reparent(sc, null).apply();</code>. 3523 * 3524 * <p>If the specified overlay has already been attached to the specified display this method 3525 * does nothing. If the specified overlay has already been attached to a previous display this 3526 * function will transfer the overlay to the new display. Services can attach multiple overlays. 3527 * Use <code> new SurfaceControl.Transaction().setLayer(sc, layer).apply();</code>. to 3528 * coordinate the order of the overlays on screen. 3529 * 3530 * @param displayId the display to which the SurfaceControl should be attached. 3531 * @param sc the SurfaceControl containing the overlay content 3532 * 3533 */ 3534 public void attachAccessibilityOverlayToDisplay(int displayId, @NonNull SurfaceControl sc) { 3535 Preconditions.checkNotNull(sc, "SurfaceControl cannot be null"); 3536 AccessibilityInteractionClient.getInstance(this) 3537 .attachAccessibilityOverlayToDisplay(mConnectionId, displayId, sc, null, null); 3538 } 3539 3540 /** 3541 * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the 3542 * specified display. This type of overlay should be used for content that does not need to 3543 * track the location and size of Views in the currently active app e.g. service configuration 3544 * or general service UI. 3545 * 3546 * <p>Generally speaking, an accessibility overlay will be a {@link android.view.View}. To embed 3547 * the View into a {@link android.view.SurfaceControl}, create a {@link 3548 * android.view.SurfaceControlViewHost} and attach the View using {@link 3549 * android.view.SurfaceControlViewHost#setView}. Then obtain the SurfaceControl by calling 3550 * <code> viewHost.getSurfacePackage().getSurfaceControl()</code>. 3551 * 3552 * <p>To remove this overlay and free the associated resources, use <code> 3553 * new SurfaceControl.Transaction().reparent(sc, null).apply();</code>. 3554 * 3555 * <p>If the specified overlay has already been attached to the specified display this method 3556 * does nothing. If the specified overlay has already been attached to a previous display this 3557 * function will transfer the overlay to the new display. Services can attach multiple overlays. 3558 * Use <code> new SurfaceControl.Transaction().setLayer(sc, layer).apply();</code>. to 3559 * coordinate the order of the overlays on screen. 3560 * 3561 * @param displayId the display to which the SurfaceControl should be attached. 3562 * @param sc the SurfaceControl containing the overlay content 3563 * @param executor Executor on which to run the callback. 3564 * @param callback The callback invoked when attaching the overlay has succeeded or failed. The 3565 * callback is a {@link java.util.function.IntConsumer} of the result status code. 3566 * @see #OVERLAY_RESULT_SUCCESS 3567 * @see #OVERLAY_RESULT_INVALID 3568 * @see #OVERLAY_RESULT_INTERNAL_ERROR 3569 */ 3570 @FlaggedApi(android.view.accessibility.Flags.FLAG_A11Y_OVERLAY_CALLBACKS) 3571 public final void attachAccessibilityOverlayToDisplay( 3572 int displayId, 3573 @NonNull SurfaceControl sc, 3574 @NonNull @CallbackExecutor Executor executor, 3575 @NonNull IntConsumer callback) { 3576 Preconditions.checkNotNull(sc, "SurfaceControl cannot be null"); 3577 AccessibilityInteractionClient.getInstance(this) 3578 .attachAccessibilityOverlayToDisplay( 3579 mConnectionId, displayId, sc, executor, callback); 3580 } 3581 3582 /** 3583 * Attaches an accessibility overlay {@link android.view.SurfaceControl} to the specified 3584 * window. This method should be used when you want the overlay to move and resize as the parent 3585 * window moves and resizes. 3586 * 3587 * <p>Generally speaking, an accessibility overlay will be a {@link android.view.View}. To embed 3588 * the View into a {@link android.view.SurfaceControl}, create a {@link 3589 * android.view.SurfaceControlViewHost} and attach the View using {@link 3590 * android.view.SurfaceControlViewHost#setView}. Then obtain the SurfaceControl by calling 3591 * <code> viewHost.getSurfacePackage().getSurfaceControl()</code>. 3592 * 3593 * <p>To remove this overlay and free the associated resources, use <code> 3594 * new SurfaceControl.Transaction().reparent(sc, null).apply();</code>. 3595 * 3596 * <p>If the specified overlay has already been attached to the specified window this method 3597 * does nothing. If the specified overlay has already been attached to a previous window this 3598 * function will transfer the overlay to the new window. Services can attach multiple overlays. 3599 * Use <code> new SurfaceControl.Transaction().setLayer(sc, layer).apply();</code>. to 3600 * coordinate the order of the overlays on screen. 3601 * 3602 * @param accessibilityWindowId The window id, from {@link AccessibilityWindowInfo#getId()}. 3603 * @param sc the SurfaceControl containing the overlay content 3604 * 3605 */ 3606 public void attachAccessibilityOverlayToWindow( 3607 int accessibilityWindowId, @NonNull SurfaceControl sc) { 3608 Preconditions.checkNotNull(sc, "SurfaceControl cannot be null"); 3609 AccessibilityInteractionClient.getInstance(this) 3610 .attachAccessibilityOverlayToWindow( 3611 mConnectionId, accessibilityWindowId, sc, null, null); 3612 } 3613 3614 /** 3615 * Attaches an accessibility overlay {@link android.view.SurfaceControl} to the specified 3616 * window. This method should be used when you want the overlay to move and resize as the parent 3617 * window moves and resizes. 3618 * 3619 * <p>Generally speaking, an accessibility overlay will be a {@link android.view.View}. To embed 3620 * the View into a {@link android.view.SurfaceControl}, create a {@link 3621 * android.view.SurfaceControlViewHost} and attach the View using {@link 3622 * android.view.SurfaceControlViewHost#setView}. Then obtain the SurfaceControl by calling 3623 * <code> viewHost.getSurfacePackage().getSurfaceControl()</code>. 3624 * 3625 * <p>To remove this overlay and free the associated resources, use <code> 3626 * new SurfaceControl.Transaction().reparent(sc, null).apply();</code>. 3627 * 3628 * <p>If the specified overlay has already been attached to the specified window this method 3629 * does nothing. If the specified overlay has already been attached to a previous window this 3630 * function will transfer the overlay to the new window. Services can attach multiple overlays. 3631 * Use <code> new SurfaceControl.Transaction().setLayer(sc, layer).apply();</code>. to 3632 * coordinate the order of the overlays on screen. 3633 * 3634 * @param accessibilityWindowId The window id, from {@link AccessibilityWindowInfo#getId()}. 3635 * @param sc the SurfaceControl containing the overlay content 3636 * @param executor Executor on which to run the callback. 3637 * @param callback The callback invoked when attaching the overlay has succeeded or failed. The 3638 * callback is a {@link java.util.function.IntConsumer} of the result status code. 3639 * @see #OVERLAY_RESULT_SUCCESS 3640 * @see #OVERLAY_RESULT_INVALID 3641 * @see #OVERLAY_RESULT_INTERNAL_ERROR 3642 */ 3643 @FlaggedApi(android.view.accessibility.Flags.FLAG_A11Y_OVERLAY_CALLBACKS) 3644 public final void attachAccessibilityOverlayToWindow( 3645 int accessibilityWindowId, 3646 @NonNull SurfaceControl sc, 3647 @NonNull @CallbackExecutor Executor executor, 3648 @NonNull IntConsumer callback) { 3649 Preconditions.checkNotNull(sc, "SurfaceControl cannot be null"); 3650 AccessibilityInteractionClient.getInstance(this) 3651 .attachAccessibilityOverlayToWindow( 3652 mConnectionId, accessibilityWindowId, sc, executor, callback); 3653 } 3654 3655 /** 3656 * Returns the {@link BrailleDisplayController} which may be used to communicate with 3657 * refreshable Braille displays that provide USB or Bluetooth Braille display HID support. 3658 */ 3659 @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID) 3660 @NonNull 3661 public final BrailleDisplayController getBrailleDisplayController() { 3662 BrailleDisplayController.checkApiFlagIsEnabled(); 3663 synchronized (mLock) { 3664 if (mBrailleDisplayController == null) { 3665 mBrailleDisplayController = new BrailleDisplayControllerImpl(this, mLock); 3666 } 3667 return mBrailleDisplayController; 3668 } 3669 } 3670 } 3671