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