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 android.accessibilityservice.GestureDescription.MotionEventGenerator; 20 import android.annotation.CallbackExecutor; 21 import android.annotation.ColorInt; 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.RequiresPermission; 26 import android.annotation.TestApi; 27 import android.app.Service; 28 import android.compat.annotation.UnsupportedAppUsage; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.pm.ParceledListSlice; 32 import android.graphics.Bitmap; 33 import android.graphics.ColorSpace; 34 import android.graphics.ParcelableColorSpace; 35 import android.graphics.Region; 36 import android.hardware.HardwareBuffer; 37 import android.hardware.display.DisplayManager; 38 import android.os.Build; 39 import android.os.Handler; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.Message; 43 import android.os.RemoteCallback; 44 import android.os.RemoteException; 45 import android.os.SystemClock; 46 import android.util.ArrayMap; 47 import android.util.Log; 48 import android.util.Slog; 49 import android.util.SparseArray; 50 import android.view.Display; 51 import android.view.KeyEvent; 52 import android.view.SurfaceView; 53 import android.view.WindowManager; 54 import android.view.WindowManagerImpl; 55 import android.view.accessibility.AccessibilityEvent; 56 import android.view.accessibility.AccessibilityInteractionClient; 57 import android.view.accessibility.AccessibilityNodeInfo; 58 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 59 import android.view.accessibility.AccessibilityWindowInfo; 60 61 import com.android.internal.os.HandlerCaller; 62 import com.android.internal.os.SomeArgs; 63 import com.android.internal.util.Preconditions; 64 65 import java.lang.annotation.Retention; 66 import java.lang.annotation.RetentionPolicy; 67 import java.util.Collections; 68 import java.util.List; 69 import java.util.concurrent.Executor; 70 import java.util.function.Consumer; 71 72 /** 73 * Accessibility services should only be used to assist users with disabilities in using 74 * Android devices and apps. They run in the background and receive callbacks by the system 75 * when {@link AccessibilityEvent}s are fired. Such events denote some state transition 76 * in the user interface, for example, the focus has changed, a button has been clicked, 77 * etc. Such a service can optionally request the capability for querying the content 78 * of the active window. Development of an accessibility service requires extending this 79 * class and implementing its abstract methods. 80 * 81 * <div class="special reference"> 82 * <h3>Developer Guides</h3> 83 * <p>For more information about creating AccessibilityServices, read the 84 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 85 * developer guide.</p> 86 * </div> 87 * 88 * <h3>Lifecycle</h3> 89 * <p> 90 * The lifecycle of an accessibility service is managed exclusively by the system and 91 * follows the established service life cycle. Starting an accessibility service is triggered 92 * exclusively by the user explicitly turning the service on in device settings. After the system 93 * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can 94 * be overridden by clients that want to perform post binding setup. 95 * </p> 96 * <p> 97 * An accessibility service stops either when the user turns it off in device settings or when 98 * it calls {@link AccessibilityService#disableSelf()}. 99 * </p> 100 * <h3>Declaration</h3> 101 * <p> 102 * An accessibility is declared as any other service in an AndroidManifest.xml, but it 103 * must do two things: 104 * <ul> 105 * <ol> 106 * Specify that it handles the "android.accessibilityservice.AccessibilityService" 107 * {@link android.content.Intent}. 108 * </ol> 109 * <ol> 110 * Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to 111 * ensure that only the system can bind to it. 112 * </ol> 113 * </ul> 114 * If either of these items is missing, the system will ignore the accessibility service. 115 * Following is an example declaration: 116 * </p> 117 * <pre> <service android:name=".MyAccessibilityService" 118 * android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> 119 * <intent-filter> 120 * <action android:name="android.accessibilityservice.AccessibilityService" /> 121 * </intent-filter> 122 * . . . 123 * </service></pre> 124 * <h3>Configuration</h3> 125 * <p> 126 * An accessibility service can be configured to receive specific types of accessibility events, 127 * listen only to specific packages, get events from each type only once in a given time frame, 128 * retrieve window content, specify a settings activity, etc. 129 * </p> 130 * <p> 131 * There are two approaches for configuring an accessibility service: 132 * </p> 133 * <ul> 134 * <li> 135 * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring 136 * the service. A service declaration with a meta-data tag is presented below: 137 * <pre> <service android:name=".MyAccessibilityService"> 138 * <intent-filter> 139 * <action android:name="android.accessibilityservice.AccessibilityService" /> 140 * </intent-filter> 141 * <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /> 142 * </service></pre> 143 * <p class="note"> 144 * <strong>Note:</strong> This approach enables setting all properties. 145 * </p> 146 * <p> 147 * For more details refer to {@link #SERVICE_META_DATA} and 148 * <code><{@link android.R.styleable#AccessibilityService accessibility-service}></code>. 149 * </p> 150 * </li> 151 * <li> 152 * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note 153 * that this method can be called any time to dynamically change the service configuration. 154 * <p class="note"> 155 * <strong>Note:</strong> This approach enables setting only dynamically configurable properties: 156 * {@link AccessibilityServiceInfo#eventTypes}, 157 * {@link AccessibilityServiceInfo#feedbackType}, 158 * {@link AccessibilityServiceInfo#flags}, 159 * {@link AccessibilityServiceInfo#notificationTimeout}, 160 * {@link AccessibilityServiceInfo#packageNames} 161 * </p> 162 * <p> 163 * For more details refer to {@link AccessibilityServiceInfo}. 164 * </p> 165 * </li> 166 * </ul> 167 * <h3>Retrieving window content</h3> 168 * <p> 169 * A service can specify in its declaration that it can retrieve window 170 * content which is represented as a tree of {@link AccessibilityWindowInfo} and 171 * {@link AccessibilityNodeInfo} objects. Note that 172 * declaring this capability requires that the service declares its configuration via 173 * an XML resource referenced by {@link #SERVICE_META_DATA}. 174 * </p> 175 * <p> 176 * Window content may be retrieved with 177 * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()}, 178 * {@link AccessibilityService#findFocus(int)}, 179 * {@link AccessibilityService#getWindows()}, or 180 * {@link AccessibilityService#getRootInActiveWindow()}. 181 * </p> 182 * <p class="note"> 183 * <strong>Note</strong> An accessibility service may have requested to be notified for 184 * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also 185 * possible for a node to contain outdated information because the window content may change at any 186 * time. 187 * </p> 188 * <h3>Notification strategy</h3> 189 * <p> 190 * All accessibility services are notified of all events they have requested, regardless of their 191 * feedback type. 192 * </p> 193 * <p class="note"> 194 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 195 * events to the client too frequently since this is accomplished via an expensive 196 * interprocess call. One can think of the timeout as a criteria to determine when 197 * event generation has settled down.</p> 198 * <h3>Event types</h3> 199 * <ul> 200 * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li> 201 * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li> 202 * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li> 203 * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li> 204 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li> 205 * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li> 206 * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li> 207 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li> 208 * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li> 209 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li> 210 * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li> 211 * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li> 212 * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li> 213 * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li> 214 * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li> 215 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li> 216 * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li> 217 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li> 218 * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li> 219 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li> 220 * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li> 221 * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li> 222 * </ul> 223 * <h3>Feedback types</h3> 224 * <ul> 225 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li> 226 * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li> 227 * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li> 228 * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li> 229 * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li> 230 * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li> 231 * </ul> 232 * @see AccessibilityEvent 233 * @see AccessibilityServiceInfo 234 * @see android.view.accessibility.AccessibilityManager 235 */ 236 public abstract class AccessibilityService extends Service { 237 238 /** 239 * The user has performed a touch-exploration gesture on the touch screen without ever 240 * triggering gesture detection. This gesture is only dispatched when {@link 241 * AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set. 242 * 243 * @hide 244 */ 245 public static final int GESTURE_TOUCH_EXPLORATION = -2; 246 247 /** 248 * The user has performed a passthrough gesture on the touch screen without ever triggering 249 * gesture detection. This gesture is only dispatched when {@link 250 * AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set. 251 * @hide 252 */ 253 public static final int GESTURE_PASSTHROUGH = -1; 254 255 /** 256 * The user has performed an unrecognized gesture on the touch screen. This gesture is only 257 * dispatched when {@link AccessibilityServiceInfo#FLAG_SEND_MOTION_EVENTS} is set. 258 */ 259 public static final int GESTURE_UNKNOWN = 0; 260 261 /** 262 * The user has performed a swipe up gesture on the touch screen. 263 */ 264 public static final int GESTURE_SWIPE_UP = 1; 265 266 /** 267 * The user has performed a swipe down gesture on the touch screen. 268 */ 269 public static final int GESTURE_SWIPE_DOWN = 2; 270 271 /** 272 * The user has performed a swipe left gesture on the touch screen. 273 */ 274 public static final int GESTURE_SWIPE_LEFT = 3; 275 276 /** 277 * The user has performed a swipe right gesture on the touch screen. 278 */ 279 public static final int GESTURE_SWIPE_RIGHT = 4; 280 281 /** 282 * The user has performed a swipe left and right gesture on the touch screen. 283 */ 284 public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5; 285 286 /** 287 * The user has performed a swipe right and left gesture on the touch screen. 288 */ 289 public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6; 290 291 /** 292 * The user has performed a swipe up and down gesture on the touch screen. 293 */ 294 public static final int GESTURE_SWIPE_UP_AND_DOWN = 7; 295 296 /** 297 * The user has performed a swipe down and up gesture on the touch screen. 298 */ 299 public static final int GESTURE_SWIPE_DOWN_AND_UP = 8; 300 301 /** 302 * The user has performed a left and up gesture on the touch screen. 303 */ 304 public static final int GESTURE_SWIPE_LEFT_AND_UP = 9; 305 306 /** 307 * The user has performed a left and down gesture on the touch screen. 308 */ 309 public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10; 310 311 /** 312 * The user has performed a right and up gesture on the touch screen. 313 */ 314 public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11; 315 316 /** 317 * The user has performed a right and down gesture on the touch screen. 318 */ 319 public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12; 320 321 /** 322 * The user has performed an up and left gesture on the touch screen. 323 */ 324 public static final int GESTURE_SWIPE_UP_AND_LEFT = 13; 325 326 /** 327 * The user has performed an up and right gesture on the touch screen. 328 */ 329 public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14; 330 331 /** 332 * The user has performed an down and left gesture on the touch screen. 333 */ 334 public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15; 335 336 /** 337 * The user has performed an down and right gesture on the touch screen. 338 */ 339 public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16; 340 341 /** 342 * The user has performed a double tap gesture on the touch screen. 343 */ 344 public static final int GESTURE_DOUBLE_TAP = 17; 345 346 /** 347 * The user has performed a double tap and hold gesture on the touch screen. 348 */ 349 public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; 350 351 /** 352 * The user has performed a two-finger single tap gesture on the touch screen. 353 */ 354 public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; 355 356 /** 357 * The user has performed a two-finger double tap gesture on the touch screen. 358 */ 359 public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; 360 361 /** 362 * The user has performed a two-finger triple tap gesture on the touch screen. 363 */ 364 public static final int GESTURE_2_FINGER_TRIPLE_TAP = 21; 365 366 /** 367 * The user has performed a three-finger single tap gesture on the touch screen. 368 */ 369 public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; 370 371 /** 372 * The user has performed a three-finger double tap gesture on the touch screen. 373 */ 374 public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; 375 376 /** 377 * The user has performed a three-finger triple tap gesture on the touch screen. 378 */ 379 public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; 380 381 /** 382 * The user has performed a two-finger swipe up gesture on the touch screen. 383 */ 384 public static final int GESTURE_2_FINGER_SWIPE_UP = 25; 385 386 /** 387 * The user has performed a two-finger swipe down gesture on the touch screen. 388 */ 389 public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; 390 391 /** 392 * The user has performed a two-finger swipe left gesture on the touch screen. 393 */ 394 public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; 395 396 /** 397 * The user has performed a two-finger swipe right gesture on the touch screen. 398 */ 399 public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; 400 401 /** 402 * The user has performed a three-finger swipe up gesture on the touch screen. 403 */ 404 public static final int GESTURE_3_FINGER_SWIPE_UP = 29; 405 406 /** 407 * The user has performed a three-finger swipe down gesture on the touch screen. 408 */ 409 public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; 410 411 /** 412 * The user has performed a three-finger swipe left gesture on the touch screen. 413 */ 414 public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; 415 416 /** 417 * The user has performed a three-finger swipe right gesture on the touch screen. 418 */ 419 public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; 420 421 /** The user has performed a four-finger swipe up gesture on the touch screen. */ 422 public static final int GESTURE_4_FINGER_SWIPE_UP = 33; 423 424 /** The user has performed a four-finger swipe down gesture on the touch screen. */ 425 public static final int GESTURE_4_FINGER_SWIPE_DOWN = 34; 426 427 /** The user has performed a four-finger swipe left gesture on the touch screen. */ 428 public static final int GESTURE_4_FINGER_SWIPE_LEFT = 35; 429 430 /** The user has performed a four-finger swipe right gesture on the touch screen. */ 431 public static final int GESTURE_4_FINGER_SWIPE_RIGHT = 36; 432 433 /** The user has performed a four-finger single tap gesture on the touch screen. */ 434 public static final int GESTURE_4_FINGER_SINGLE_TAP = 37; 435 436 /** The user has performed a four-finger double tap gesture on the touch screen. */ 437 public static final int GESTURE_4_FINGER_DOUBLE_TAP = 38; 438 439 /** The user has performed a four-finger triple tap gesture on the touch screen. */ 440 public static final int GESTURE_4_FINGER_TRIPLE_TAP = 39; 441 442 /** The user has performed a two-finger double tap and hold gesture on the touch screen. */ 443 public static final int GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD = 40; 444 445 /** The user has performed a three-finger double tap and hold gesture on the touch screen. */ 446 public static final int GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD = 41; 447 448 /** The user has performed a two-finger triple-tap and hold gesture on the touch screen. */ 449 public static final int GESTURE_2_FINGER_TRIPLE_TAP_AND_HOLD = 43; 450 451 /** The user has performed a three-finger single-tap and hold gesture on the touch screen. */ 452 public static final int GESTURE_3_FINGER_SINGLE_TAP_AND_HOLD = 44; 453 454 /** The user has performed a three-finger triple-tap and hold gesture on the touch screen. */ 455 public static final int GESTURE_3_FINGER_TRIPLE_TAP_AND_HOLD = 45; 456 457 /** The user has performed a two-finger double tap and hold gesture on the touch screen. */ 458 public static final int GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD = 42; 459 460 /** 461 * The {@link Intent} that must be declared as handled by the service. 462 */ 463 public static final String SERVICE_INTERFACE = 464 "android.accessibilityservice.AccessibilityService"; 465 466 /** 467 * Name under which an AccessibilityService component publishes information 468 * about itself. This meta-data must reference an XML resource containing an 469 * <code><{@link android.R.styleable#AccessibilityService accessibility-service}></code> 470 * tag. This is a sample XML file configuring an accessibility service: 471 * <pre> <accessibility-service 472 * android:accessibilityEventTypes="typeViewClicked|typeViewFocused" 473 * android:packageNames="foo.bar, foo.baz" 474 * android:accessibilityFeedbackType="feedbackSpoken" 475 * android:notificationTimeout="100" 476 * android:accessibilityFlags="flagDefault" 477 * android:settingsActivity="foo.bar.TestBackActivity" 478 * android:canRetrieveWindowContent="true" 479 * android:canRequestTouchExplorationMode="true" 480 * . . . 481 * /></pre> 482 */ 483 public static final String SERVICE_META_DATA = "android.accessibilityservice"; 484 485 /** 486 * Action to go back. 487 */ 488 public static final int GLOBAL_ACTION_BACK = 1; 489 490 /** 491 * Action to go home. 492 */ 493 public static final int GLOBAL_ACTION_HOME = 2; 494 495 /** 496 * Action to toggle showing the overview of recent apps. Will fail on platforms that don't 497 * show recent apps. 498 */ 499 public static final int GLOBAL_ACTION_RECENTS = 3; 500 501 /** 502 * Action to open the notifications. 503 */ 504 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; 505 506 /** 507 * Action to open the quick settings. 508 */ 509 public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; 510 511 /** 512 * Action to open the power long-press dialog. 513 */ 514 public static final int GLOBAL_ACTION_POWER_DIALOG = 6; 515 516 /** 517 * Action to toggle docking the current app's window 518 */ 519 public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; 520 521 /** 522 * Action to lock the screen 523 */ 524 public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; 525 526 /** 527 * Action to take a screenshot 528 */ 529 public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9; 530 531 /** 532 * Action to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer/hang up calls and 533 * play/stop media 534 */ 535 public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; 536 537 /** 538 * Action to trigger the Accessibility Button 539 */ 540 public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON = 11; 541 542 /** 543 * Action to bring up the Accessibility Button's chooser menu 544 */ 545 public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 12; 546 547 /** 548 * Action to trigger the Accessibility Shortcut. This shortcut has a hardware trigger and can 549 * be activated by holding down the two volume keys. 550 */ 551 public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13; 552 553 /** 554 * Action to show Launcher's all apps. 555 */ 556 public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14; 557 558 /** 559 * Action to dismiss the notification shade 560 */ 561 public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15; 562 563 private static final String LOG_TAG = "AccessibilityService"; 564 565 /** 566 * Interface used by IAccessibilityServiceClientWrapper to call the service from its main 567 * thread. 568 * @hide 569 */ 570 public interface Callbacks { onAccessibilityEvent(AccessibilityEvent event)571 void onAccessibilityEvent(AccessibilityEvent event); onInterrupt()572 void onInterrupt(); onServiceConnected()573 void onServiceConnected(); init(int connectionId, IBinder windowToken)574 void init(int connectionId, IBinder windowToken); 575 /** The detected gesture information for different displays */ onGesture(AccessibilityGestureEvent gestureInfo)576 boolean onGesture(AccessibilityGestureEvent gestureInfo); onKeyEvent(KeyEvent event)577 boolean onKeyEvent(KeyEvent event); 578 /** Magnification changed callbacks for different displays */ onMagnificationChanged(int displayId, @NonNull Region region, float scale, float centerX, float centerY)579 void onMagnificationChanged(int displayId, @NonNull Region region, 580 float scale, float centerX, float centerY); onSoftKeyboardShowModeChanged(int showMode)581 void onSoftKeyboardShowModeChanged(int showMode); onPerformGestureResult(int sequence, boolean completedSuccessfully)582 void onPerformGestureResult(int sequence, boolean completedSuccessfully); onFingerprintCapturingGesturesChanged(boolean active)583 void onFingerprintCapturingGesturesChanged(boolean active); onFingerprintGesture(int gesture)584 void onFingerprintGesture(int gesture); 585 /** Accessbility button clicked callbacks for different displays */ onAccessibilityButtonClicked(int displayId)586 void onAccessibilityButtonClicked(int displayId); onAccessibilityButtonAvailabilityChanged(boolean available)587 void onAccessibilityButtonAvailabilityChanged(boolean available); 588 /** This is called when the system action list is changed. */ onSystemActionsChanged()589 void onSystemActionsChanged(); 590 } 591 592 /** 593 * Annotations for Soft Keyboard show modes so tools can catch invalid show modes. 594 * @hide 595 */ 596 @Retention(RetentionPolicy.SOURCE) 597 @IntDef(prefix = { "SHOW_MODE_" }, value = { 598 SHOW_MODE_AUTO, 599 SHOW_MODE_HIDDEN, 600 SHOW_MODE_IGNORE_HARD_KEYBOARD 601 }) 602 public @interface SoftKeyboardShowMode {} 603 604 /** 605 * Allow the system to control when the soft keyboard is shown. 606 * @see SoftKeyboardController 607 */ 608 public static final int SHOW_MODE_AUTO = 0; 609 610 /** 611 * Never show the soft keyboard. 612 * @see SoftKeyboardController 613 */ 614 public static final int SHOW_MODE_HIDDEN = 1; 615 616 /** 617 * Allow the soft keyboard to be shown, even if a hard keyboard is connected 618 * @see SoftKeyboardController 619 */ 620 public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2; 621 622 /** 623 * Mask used to cover the show modes supported in public API 624 * @hide 625 */ 626 public static final int SHOW_MODE_MASK = 0x03; 627 628 /** 629 * Bit used to hold the old value of the hard IME setting to restore when a service is shut 630 * down. 631 * @hide 632 */ 633 public static final int SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE = 0x20000000; 634 635 /** 636 * Bit for show mode setting to indicate that the user has overridden the hard keyboard 637 * behavior. 638 * @hide 639 */ 640 public static final int SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN = 0x40000000; 641 642 /** 643 * Annotations for error codes of taking screenshot. 644 * @hide 645 */ 646 @Retention(RetentionPolicy.SOURCE) 647 @IntDef(prefix = { "TAKE_SCREENSHOT_" }, value = { 648 ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, 649 ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS, 650 ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT, 651 ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY 652 }) 653 public @interface ScreenshotErrorCode {} 654 655 /** 656 * The status of taking screenshot is success. 657 * @hide 658 */ 659 public static final int TAKE_SCREENSHOT_SUCCESS = 0; 660 661 /** 662 * The status of taking screenshot is failure and the reason is internal error. 663 */ 664 public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 1; 665 666 /** 667 * The status of taking screenshot is failure and the reason is no accessibility access. 668 */ 669 public static final int ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS = 2; 670 671 /** 672 * The status of taking screenshot is failure and the reason is that too little time has 673 * elapsed since the last screenshot. 674 */ 675 public static final int ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT = 3; 676 677 /** 678 * The status of taking screenshot is failure and the reason is invalid display Id. 679 */ 680 public static final int ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY = 4; 681 682 /** 683 * The interval time of calling 684 * {@link AccessibilityService#takeScreenshot(int, Executor, Consumer)} API. 685 * @hide 686 */ 687 @TestApi 688 public static final int ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS = 333; 689 690 /** @hide */ 691 public static final String KEY_ACCESSIBILITY_SCREENSHOT_STATUS = 692 "screenshot_status"; 693 694 /** @hide */ 695 public static final String KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER = 696 "screenshot_hardwareBuffer"; 697 698 /** @hide */ 699 public static final String KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE = 700 "screenshot_colorSpace"; 701 702 /** @hide */ 703 public static final String KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP = 704 "screenshot_timestamp"; 705 706 private int mConnectionId = AccessibilityInteractionClient.NO_ID; 707 708 @UnsupportedAppUsage 709 private AccessibilityServiceInfo mInfo; 710 711 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 712 private IBinder mWindowToken; 713 714 private WindowManager mWindowManager; 715 716 /** List of magnification controllers, mapping from displayId -> MagnificationController. */ 717 private final SparseArray<MagnificationController> mMagnificationControllers = 718 new SparseArray<>(0); 719 private SoftKeyboardController mSoftKeyboardController; 720 private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers = 721 new SparseArray<>(0); 722 723 private int mGestureStatusCallbackSequence; 724 725 private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos; 726 727 private final Object mLock = new Object(); 728 729 private FingerprintGestureController mFingerprintGestureController; 730 731 732 /** 733 * Callback for {@link android.view.accessibility.AccessibilityEvent}s. 734 * 735 * @param event The new event. This event is owned by the caller and cannot be used after 736 * this method returns. Services wishing to use the event after this method returns should 737 * make a copy. 738 */ onAccessibilityEvent(AccessibilityEvent event)739 public abstract void onAccessibilityEvent(AccessibilityEvent event); 740 741 /** 742 * Callback for interrupting the accessibility feedback. 743 */ onInterrupt()744 public abstract void onInterrupt(); 745 746 /** 747 * Dispatches service connection to internal components first, then the 748 * client code. 749 */ dispatchServiceConnected()750 private void dispatchServiceConnected() { 751 synchronized (mLock) { 752 for (int i = 0; i < mMagnificationControllers.size(); i++) { 753 mMagnificationControllers.valueAt(i).onServiceConnectedLocked(); 754 } 755 } 756 if (mSoftKeyboardController != null) { 757 mSoftKeyboardController.onServiceConnected(); 758 } 759 760 // The client gets to handle service connection last, after we've set 761 // up any state upon which their code may rely. 762 onServiceConnected(); 763 } 764 765 /** 766 * This method is a part of the {@link AccessibilityService} lifecycle and is 767 * called after the system has successfully bound to the service. If is 768 * convenient to use this method for setting the {@link AccessibilityServiceInfo}. 769 * 770 * @see AccessibilityServiceInfo 771 * @see #setServiceInfo(AccessibilityServiceInfo) 772 */ onServiceConnected()773 protected void onServiceConnected() { 774 775 } 776 777 /** 778 * Called by {@link #onGesture(AccessibilityGestureEvent)} when the user performs a specific 779 * gesture on the default display. 780 * 781 * <strong>Note:</strong> To receive gestures an accessibility service must 782 * request that the device is in touch exploration mode by setting the 783 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} 784 * flag. 785 * 786 * @param gestureId The unique id of the performed gesture. 787 * 788 * @return Whether the gesture was handled. 789 * @deprecated Override {@link #onGesture(AccessibilityGestureEvent)} instead. 790 * 791 * @see #GESTURE_SWIPE_UP 792 * @see #GESTURE_SWIPE_UP_AND_LEFT 793 * @see #GESTURE_SWIPE_UP_AND_DOWN 794 * @see #GESTURE_SWIPE_UP_AND_RIGHT 795 * @see #GESTURE_SWIPE_DOWN 796 * @see #GESTURE_SWIPE_DOWN_AND_LEFT 797 * @see #GESTURE_SWIPE_DOWN_AND_UP 798 * @see #GESTURE_SWIPE_DOWN_AND_RIGHT 799 * @see #GESTURE_SWIPE_LEFT 800 * @see #GESTURE_SWIPE_LEFT_AND_UP 801 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT 802 * @see #GESTURE_SWIPE_LEFT_AND_DOWN 803 * @see #GESTURE_SWIPE_RIGHT 804 * @see #GESTURE_SWIPE_RIGHT_AND_UP 805 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT 806 * @see #GESTURE_SWIPE_RIGHT_AND_DOWN 807 */ 808 @Deprecated onGesture(int gestureId)809 protected boolean onGesture(int gestureId) { 810 return false; 811 } 812 813 /** 814 * Called by the system when the user performs a specific gesture on the 815 * specific touch screen. 816 *<p> 817 * <strong>Note:</strong> To receive gestures an accessibility service must 818 * request that the device is in touch exploration mode by setting the 819 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} 820 * flag. 821 *<p> 822 * <strong>Note:</strong> The default implementation calls {@link #onGesture(int)} when the 823 * touch screen is default display. 824 * 825 * @param gestureEvent The information of gesture. 826 * 827 * @return Whether the gesture was handled. 828 * 829 */ onGesture(@onNull AccessibilityGestureEvent gestureEvent)830 public boolean onGesture(@NonNull AccessibilityGestureEvent gestureEvent) { 831 if (gestureEvent.getDisplayId() == Display.DEFAULT_DISPLAY) { 832 onGesture(gestureEvent.getGestureId()); 833 } 834 return false; 835 } 836 837 /** 838 * Callback that allows an accessibility service to observe the key events 839 * before they are passed to the rest of the system. This means that the events 840 * are first delivered here before they are passed to the device policy, the 841 * input method, or applications. 842 * <p> 843 * <strong>Note:</strong> It is important that key events are handled in such 844 * a way that the event stream that would be passed to the rest of the system 845 * is well-formed. For example, handling the down event but not the up event 846 * and vice versa would generate an inconsistent event stream. 847 * </p> 848 * <p> 849 * <strong>Note:</strong> The key events delivered in this method are copies 850 * and modifying them will have no effect on the events that will be passed 851 * to the system. This method is intended to perform purely filtering 852 * functionality. 853 * <p> 854 * 855 * @param event The event to be processed. This event is owned by the caller and cannot be used 856 * after this method returns. Services wishing to use the event after this method returns should 857 * make a copy. 858 * @return If true then the event will be consumed and not delivered to 859 * applications, otherwise it will be delivered as usual. 860 */ onKeyEvent(KeyEvent event)861 protected boolean onKeyEvent(KeyEvent event) { 862 return false; 863 } 864 865 /** 866 * Gets the windows on the screen of the default display. This method returns only the windows 867 * that a sighted user can interact with, as opposed to all windows. 868 * For example, if there is a modal dialog shown and the user cannot touch 869 * anything behind it, then only the modal window will be reported 870 * (assuming it is the top one). For convenience the returned windows 871 * are ordered in a descending layer order, which is the windows that 872 * are on top are reported first. Since the user can always 873 * interact with the window that has input focus by typing, the focused 874 * window is always returned (even if covered by a modal window). 875 * <p> 876 * <strong>Note:</strong> In order to access the windows your service has 877 * to declare the capability to retrieve window content by setting the 878 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 879 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 880 * Also the service has to opt-in to retrieve the interactive windows by 881 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} 882 * flag. 883 * </p> 884 * 885 * @return The windows if there are windows and the service is can retrieve 886 * them, otherwise an empty list. 887 */ getWindows()888 public List<AccessibilityWindowInfo> getWindows() { 889 return AccessibilityInteractionClient.getInstance(this).getWindows(mConnectionId); 890 } 891 892 /** 893 * Gets the windows on the screen of all displays. This method returns only the windows 894 * that a sighted user can interact with, as opposed to all windows. 895 * For example, if there is a modal dialog shown and the user cannot touch 896 * anything behind it, then only the modal window will be reported 897 * (assuming it is the top one). For convenience the returned windows 898 * are ordered in a descending layer order, which is the windows that 899 * are on top are reported first. Since the user can always 900 * interact with the window that has input focus by typing, the focused 901 * window is always returned (even if covered by a modal window). 902 * <p> 903 * <strong>Note:</strong> In order to access the windows your service has 904 * to declare the capability to retrieve window content by setting the 905 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 906 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 907 * Also the service has to opt-in to retrieve the interactive windows by 908 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} 909 * flag. 910 * </p> 911 * 912 * @return The windows of all displays if there are windows and the service is can retrieve 913 * them, otherwise an empty list. The key of SparseArray is display ID. 914 */ 915 @NonNull getWindowsOnAllDisplays()916 public final SparseArray<List<AccessibilityWindowInfo>> getWindowsOnAllDisplays() { 917 return AccessibilityInteractionClient.getInstance(this).getWindowsOnAllDisplays( 918 mConnectionId); 919 } 920 921 /** 922 * Gets the root node in the currently active window if this service 923 * can retrieve window content. The active window is the one that the user 924 * is currently touching or the window with input focus, if the user is not 925 * touching any window. It could be from any logical display. 926 * <p> 927 * The currently active window is defined as the window that most recently fired one 928 * of the following events: 929 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}, 930 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}, 931 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}. 932 * In other words, the last window shown that also has input focus. 933 * </p> 934 * <p> 935 * <strong>Note:</strong> In order to access the root node your service has 936 * to declare the capability to retrieve window content by setting the 937 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 938 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 939 * </p> 940 * 941 * @return The root node if this service can retrieve window content. 942 */ getRootInActiveWindow()943 public AccessibilityNodeInfo getRootInActiveWindow() { 944 return AccessibilityInteractionClient.getInstance(this).getRootInActiveWindow( 945 mConnectionId); 946 } 947 948 /** 949 * Disables the service. After calling this method, the service will be disabled and settings 950 * will show that it is turned off. 951 */ disableSelf()952 public final void disableSelf() { 953 final IAccessibilityServiceConnection connection = 954 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 955 if (connection != null) { 956 try { 957 connection.disableSelf(); 958 } catch (RemoteException re) { 959 throw new RuntimeException(re); 960 } 961 } 962 } 963 964 @Override createDisplayContext(Display display)965 public Context createDisplayContext(Display display) { 966 final Context context = super.createDisplayContext(display); 967 final int displayId = display.getDisplayId(); 968 setDefaultTokenInternal(context, displayId); 969 return context; 970 } 971 setDefaultTokenInternal(Context context, int displayId)972 private void setDefaultTokenInternal(Context context, int displayId) { 973 final WindowManagerImpl wm = (WindowManagerImpl) context.getSystemService(WINDOW_SERVICE); 974 final IAccessibilityServiceConnection connection = 975 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 976 IBinder token = null; 977 if (connection != null) { 978 synchronized (mLock) { 979 try { 980 token = connection.getOverlayWindowToken(displayId); 981 } catch (RemoteException re) { 982 Log.w(LOG_TAG, "Failed to get window token", re); 983 re.rethrowFromSystemServer(); 984 } 985 } 986 wm.setDefaultToken(token); 987 } 988 } 989 990 /** 991 * Returns the magnification controller, which may be used to query and 992 * modify the state of display magnification. 993 * <p> 994 * <strong>Note:</strong> In order to control magnification, your service 995 * must declare the capability by setting the 996 * {@link android.R.styleable#AccessibilityService_canControlMagnification} 997 * property in its meta-data. For more information, see 998 * {@link #SERVICE_META_DATA}. 999 * 1000 * @return the magnification controller 1001 */ 1002 @NonNull getMagnificationController()1003 public final MagnificationController getMagnificationController() { 1004 return getMagnificationController(Display.DEFAULT_DISPLAY); 1005 } 1006 1007 /** 1008 * Returns the magnification controller of specified logical display, which may be used to 1009 * query and modify the state of display magnification. 1010 * <p> 1011 * <strong>Note:</strong> In order to control magnification, your service 1012 * must declare the capability by setting the 1013 * {@link android.R.styleable#AccessibilityService_canControlMagnification} 1014 * property in its meta-data. For more information, see 1015 * {@link #SERVICE_META_DATA}. 1016 * 1017 * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for 1018 * default display. 1019 * @return the magnification controller 1020 * 1021 * @hide 1022 */ 1023 @NonNull getMagnificationController(int displayId)1024 public final MagnificationController getMagnificationController(int displayId) { 1025 synchronized (mLock) { 1026 MagnificationController controller = mMagnificationControllers.get(displayId); 1027 if (controller == null) { 1028 controller = new MagnificationController(this, mLock, displayId); 1029 mMagnificationControllers.put(displayId, controller); 1030 } 1031 return controller; 1032 } 1033 } 1034 1035 /** 1036 * Get the controller for fingerprint gestures. This feature requires {@link 1037 * AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}. 1038 * 1039 *<strong>Note: </strong> The service must be connected before this method is called. 1040 * 1041 * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable. 1042 */ 1043 @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) getFingerprintGestureController()1044 public final @NonNull FingerprintGestureController getFingerprintGestureController() { 1045 if (mFingerprintGestureController == null) { 1046 mFingerprintGestureController = new FingerprintGestureController( 1047 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId)); 1048 } 1049 return mFingerprintGestureController; 1050 } 1051 1052 /** 1053 * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from 1054 * the user, this service, or another service, will be cancelled. 1055 * <p> 1056 * The gesture will be dispatched as if it were performed directly on the screen by a user, so 1057 * the events may be affected by features such as magnification and explore by touch. 1058 * </p> 1059 * <p> 1060 * <strong>Note:</strong> In order to dispatch gestures, your service 1061 * must declare the capability by setting the 1062 * {@link android.R.styleable#AccessibilityService_canPerformGestures} 1063 * property in its meta-data. For more information, see 1064 * {@link #SERVICE_META_DATA}. 1065 * </p> 1066 * 1067 * @param gesture The gesture to dispatch 1068 * @param callback The object to call back when the status of the gesture is known. If 1069 * {@code null}, no status is reported. 1070 * @param handler The handler on which to call back the {@code callback} object. If 1071 * {@code null}, the object is called back on the service's main thread. 1072 * 1073 * @return {@code true} if the gesture is dispatched, {@code false} if not. 1074 */ dispatchGesture(@onNull GestureDescription gesture, @Nullable GestureResultCallback callback, @Nullable Handler handler)1075 public final boolean dispatchGesture(@NonNull GestureDescription gesture, 1076 @Nullable GestureResultCallback callback, 1077 @Nullable Handler handler) { 1078 final IAccessibilityServiceConnection connection = 1079 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 1080 if (connection == null) { 1081 return false; 1082 } 1083 int sampleTimeMs = calculateGestureSampleTimeMs(gesture.getDisplayId()); 1084 List<GestureDescription.GestureStep> steps = 1085 MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, sampleTimeMs); 1086 try { 1087 synchronized (mLock) { 1088 mGestureStatusCallbackSequence++; 1089 if (callback != null) { 1090 if (mGestureStatusCallbackInfos == null) { 1091 mGestureStatusCallbackInfos = new SparseArray<>(); 1092 } 1093 GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture, 1094 callback, handler); 1095 mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo); 1096 } 1097 connection.dispatchGesture(mGestureStatusCallbackSequence, 1098 new ParceledListSlice<>(steps), gesture.getDisplayId()); 1099 } 1100 } catch (RemoteException re) { 1101 throw new RuntimeException(re); 1102 } 1103 return true; 1104 } 1105 1106 /** 1107 * Returns the sample time in millis of gesture steps for the current display. 1108 * 1109 * <p>For gestures to be smooth they should line up with the refresh rate of the display. 1110 * On versions of Android before R, the sample time was fixed to 100ms. 1111 */ calculateGestureSampleTimeMs(int displayId)1112 private int calculateGestureSampleTimeMs(int displayId) { 1113 if (getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.Q) { 1114 return 100; 1115 } 1116 Display display = getSystemService(DisplayManager.class).getDisplay( 1117 displayId); 1118 if (display == null) { 1119 return 100; 1120 } 1121 int msPerSecond = 1000; 1122 int sampleTimeMs = (int) (msPerSecond / display.getRefreshRate()); 1123 if (sampleTimeMs < 1) { 1124 // Should be impossible, but do not return 0. 1125 return 100; 1126 } 1127 return sampleTimeMs; 1128 } 1129 onPerformGestureResult(int sequence, final boolean completedSuccessfully)1130 void onPerformGestureResult(int sequence, final boolean completedSuccessfully) { 1131 if (mGestureStatusCallbackInfos == null) { 1132 return; 1133 } 1134 GestureResultCallbackInfo callbackInfo; 1135 synchronized (mLock) { 1136 callbackInfo = mGestureStatusCallbackInfos.get(sequence); 1137 mGestureStatusCallbackInfos.remove(sequence); 1138 } 1139 final GestureResultCallbackInfo finalCallbackInfo = callbackInfo; 1140 if ((callbackInfo != null) && (callbackInfo.gestureDescription != null) 1141 && (callbackInfo.callback != null)) { 1142 if (callbackInfo.handler != null) { 1143 callbackInfo.handler.post(new Runnable() { 1144 @Override 1145 public void run() { 1146 if (completedSuccessfully) { 1147 finalCallbackInfo.callback 1148 .onCompleted(finalCallbackInfo.gestureDescription); 1149 } else { 1150 finalCallbackInfo.callback 1151 .onCancelled(finalCallbackInfo.gestureDescription); 1152 } 1153 } 1154 }); 1155 return; 1156 } 1157 if (completedSuccessfully) { 1158 callbackInfo.callback.onCompleted(callbackInfo.gestureDescription); 1159 } else { 1160 callbackInfo.callback.onCancelled(callbackInfo.gestureDescription); 1161 } 1162 } 1163 } 1164 onMagnificationChanged(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1165 private void onMagnificationChanged(int displayId, @NonNull Region region, float scale, 1166 float centerX, float centerY) { 1167 MagnificationController controller; 1168 synchronized (mLock) { 1169 controller = mMagnificationControllers.get(displayId); 1170 } 1171 if (controller != null) { 1172 controller.dispatchMagnificationChanged(region, scale, centerX, centerY); 1173 } 1174 } 1175 1176 /** 1177 * Callback for fingerprint gesture handling 1178 * @param active If gesture detection is active 1179 */ onFingerprintCapturingGesturesChanged(boolean active)1180 private void onFingerprintCapturingGesturesChanged(boolean active) { 1181 getFingerprintGestureController().onGestureDetectionActiveChanged(active); 1182 } 1183 1184 /** 1185 * Callback for fingerprint gesture handling 1186 * @param gesture The identifier for the gesture performed 1187 */ onFingerprintGesture(int gesture)1188 private void onFingerprintGesture(int gesture) { 1189 getFingerprintGestureController().onGesture(gesture); 1190 } 1191 1192 /** 1193 * Used to control and query the state of display magnification. 1194 */ 1195 public static final class MagnificationController { 1196 private final AccessibilityService mService; 1197 private final int mDisplayId; 1198 1199 /** 1200 * Map of listeners to their handlers. Lazily created when adding the 1201 * first magnification listener. 1202 */ 1203 private ArrayMap<OnMagnificationChangedListener, Handler> mListeners; 1204 private final Object mLock; 1205 MagnificationController(@onNull AccessibilityService service, @NonNull Object lock, int displayId)1206 MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock, 1207 int displayId) { 1208 mService = service; 1209 mLock = lock; 1210 mDisplayId = displayId; 1211 } 1212 1213 /** 1214 * Called when the service is connected. 1215 */ onServiceConnectedLocked()1216 void onServiceConnectedLocked() { 1217 if (mListeners != null && !mListeners.isEmpty()) { 1218 setMagnificationCallbackEnabled(true); 1219 } 1220 } 1221 1222 /** 1223 * Adds the specified change listener to the list of magnification 1224 * change listeners. The callback will occur on the service's main 1225 * thread. 1226 * 1227 * @param listener the listener to add, must be non-{@code null} 1228 */ addListener(@onNull OnMagnificationChangedListener listener)1229 public void addListener(@NonNull OnMagnificationChangedListener listener) { 1230 addListener(listener, null); 1231 } 1232 1233 /** 1234 * Adds the specified change listener to the list of magnification 1235 * change listeners. The callback will occur on the specified 1236 * {@link Handler}'s thread, or on the service's main thread if the 1237 * handler is {@code null}. 1238 * 1239 * @param listener the listener to add, must be non-null 1240 * @param handler the handler on which the callback should execute, or 1241 * {@code null} to execute on the service's main thread 1242 */ addListener(@onNull OnMagnificationChangedListener listener, @Nullable Handler handler)1243 public void addListener(@NonNull OnMagnificationChangedListener listener, 1244 @Nullable Handler handler) { 1245 synchronized (mLock) { 1246 if (mListeners == null) { 1247 mListeners = new ArrayMap<>(); 1248 } 1249 1250 final boolean shouldEnableCallback = mListeners.isEmpty(); 1251 mListeners.put(listener, handler); 1252 1253 if (shouldEnableCallback) { 1254 // This may fail if the service is not connected yet, but if we 1255 // still have listeners when it connects then we can try again. 1256 setMagnificationCallbackEnabled(true); 1257 } 1258 } 1259 } 1260 1261 /** 1262 * Removes the specified change listener from the list of magnification change listeners. 1263 * 1264 * @param listener the listener to remove, must be non-null 1265 * @return {@code true} if the listener was removed, {@code false} otherwise 1266 */ removeListener(@onNull OnMagnificationChangedListener listener)1267 public boolean removeListener(@NonNull OnMagnificationChangedListener listener) { 1268 if (mListeners == null) { 1269 return false; 1270 } 1271 1272 synchronized (mLock) { 1273 final int keyIndex = mListeners.indexOfKey(listener); 1274 final boolean hasKey = keyIndex >= 0; 1275 if (hasKey) { 1276 mListeners.removeAt(keyIndex); 1277 } 1278 1279 if (hasKey && mListeners.isEmpty()) { 1280 // We just removed the last listener, so we don't need 1281 // callbacks from the service anymore. 1282 setMagnificationCallbackEnabled(false); 1283 } 1284 1285 return hasKey; 1286 } 1287 } 1288 setMagnificationCallbackEnabled(boolean enabled)1289 private void setMagnificationCallbackEnabled(boolean enabled) { 1290 final IAccessibilityServiceConnection connection = 1291 AccessibilityInteractionClient.getInstance(mService).getConnection( 1292 mService.mConnectionId); 1293 if (connection != null) { 1294 try { 1295 connection.setMagnificationCallbackEnabled(mDisplayId, enabled); 1296 } catch (RemoteException re) { 1297 throw new RuntimeException(re); 1298 } 1299 } 1300 } 1301 1302 /** 1303 * Dispatches magnification changes to any registered listeners. This 1304 * should be called on the service's main thread. 1305 */ dispatchMagnificationChanged(final @NonNull Region region, final float scale, final float centerX, final float centerY)1306 void dispatchMagnificationChanged(final @NonNull Region region, final float scale, 1307 final float centerX, final float centerY) { 1308 final ArrayMap<OnMagnificationChangedListener, Handler> entries; 1309 synchronized (mLock) { 1310 if (mListeners == null || mListeners.isEmpty()) { 1311 Slog.d(LOG_TAG, "Received magnification changed " 1312 + "callback with no listeners registered!"); 1313 setMagnificationCallbackEnabled(false); 1314 return; 1315 } 1316 1317 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent 1318 // modification. 1319 entries = new ArrayMap<>(mListeners); 1320 } 1321 1322 for (int i = 0, count = entries.size(); i < count; i++) { 1323 final OnMagnificationChangedListener listener = entries.keyAt(i); 1324 final Handler handler = entries.valueAt(i); 1325 if (handler != null) { 1326 handler.post(new Runnable() { 1327 @Override 1328 public void run() { 1329 listener.onMagnificationChanged(MagnificationController.this, 1330 region, scale, centerX, centerY); 1331 } 1332 }); 1333 } else { 1334 // We're already on the main thread, just run the listener. 1335 listener.onMagnificationChanged(this, region, scale, centerX, centerY); 1336 } 1337 } 1338 } 1339 1340 /** 1341 * Returns the current magnification scale. 1342 * <p> 1343 * <strong>Note:</strong> If the service is not yet connected (e.g. 1344 * {@link AccessibilityService#onServiceConnected()} has not yet been 1345 * called) or the service has been disconnected, this method will 1346 * return a default value of {@code 1.0f}. 1347 * 1348 * @return the current magnification scale 1349 */ getScale()1350 public float getScale() { 1351 final IAccessibilityServiceConnection connection = 1352 AccessibilityInteractionClient.getInstance(mService).getConnection( 1353 mService.mConnectionId); 1354 if (connection != null) { 1355 try { 1356 return connection.getMagnificationScale(mDisplayId); 1357 } catch (RemoteException re) { 1358 Log.w(LOG_TAG, "Failed to obtain scale", re); 1359 re.rethrowFromSystemServer(); 1360 } 1361 } 1362 return 1.0f; 1363 } 1364 1365 /** 1366 * Returns the unscaled screen-relative X coordinate of the focal 1367 * center of the magnified region. This is the point around which 1368 * zooming occurs and is guaranteed to lie within the magnified 1369 * region. 1370 * <p> 1371 * <strong>Note:</strong> If the service is not yet connected (e.g. 1372 * {@link AccessibilityService#onServiceConnected()} has not yet been 1373 * called) or the service has been disconnected, this method will 1374 * return a default value of {@code 0.0f}. 1375 * 1376 * @return the unscaled screen-relative X coordinate of the center of 1377 * the magnified region 1378 */ getCenterX()1379 public float getCenterX() { 1380 final IAccessibilityServiceConnection connection = 1381 AccessibilityInteractionClient.getInstance(mService).getConnection( 1382 mService.mConnectionId); 1383 if (connection != null) { 1384 try { 1385 return connection.getMagnificationCenterX(mDisplayId); 1386 } catch (RemoteException re) { 1387 Log.w(LOG_TAG, "Failed to obtain center X", re); 1388 re.rethrowFromSystemServer(); 1389 } 1390 } 1391 return 0.0f; 1392 } 1393 1394 /** 1395 * Returns the unscaled screen-relative Y coordinate of the focal 1396 * center of the magnified region. This is the point around which 1397 * zooming occurs and is guaranteed to lie within the magnified 1398 * region. 1399 * <p> 1400 * <strong>Note:</strong> If the service is not yet connected (e.g. 1401 * {@link AccessibilityService#onServiceConnected()} has not yet been 1402 * called) or the service has been disconnected, this method will 1403 * return a default value of {@code 0.0f}. 1404 * 1405 * @return the unscaled screen-relative Y coordinate of the center of 1406 * the magnified region 1407 */ getCenterY()1408 public float getCenterY() { 1409 final IAccessibilityServiceConnection connection = 1410 AccessibilityInteractionClient.getInstance(mService).getConnection( 1411 mService.mConnectionId); 1412 if (connection != null) { 1413 try { 1414 return connection.getMagnificationCenterY(mDisplayId); 1415 } catch (RemoteException re) { 1416 Log.w(LOG_TAG, "Failed to obtain center Y", re); 1417 re.rethrowFromSystemServer(); 1418 } 1419 } 1420 return 0.0f; 1421 } 1422 1423 /** 1424 * Returns the region of the screen currently active for magnification. Changes to 1425 * magnification scale and center only affect this portion of the screen. The rest of the 1426 * screen, for example input methods, cannot be magnified. This region is relative to the 1427 * unscaled screen and is independent of the scale and center point. 1428 * <p> 1429 * The returned region will be empty if magnification is not active. Magnification is active 1430 * if magnification gestures are enabled or if a service is running that can control 1431 * magnification. 1432 * <p> 1433 * <strong>Note:</strong> If the service is not yet connected (e.g. 1434 * {@link AccessibilityService#onServiceConnected()} has not yet been 1435 * called) or the service has been disconnected, this method will 1436 * return an empty region. 1437 * 1438 * @return the region of the screen currently active for magnification, or an empty region 1439 * if magnification is not active. 1440 */ 1441 @NonNull getMagnificationRegion()1442 public Region getMagnificationRegion() { 1443 final IAccessibilityServiceConnection connection = 1444 AccessibilityInteractionClient.getInstance(mService).getConnection( 1445 mService.mConnectionId); 1446 if (connection != null) { 1447 try { 1448 return connection.getMagnificationRegion(mDisplayId); 1449 } catch (RemoteException re) { 1450 Log.w(LOG_TAG, "Failed to obtain magnified region", re); 1451 re.rethrowFromSystemServer(); 1452 } 1453 } 1454 return Region.obtain(); 1455 } 1456 1457 /** 1458 * Resets magnification scale and center to their default (e.g. no 1459 * magnification) values. 1460 * <p> 1461 * <strong>Note:</strong> If the service is not yet connected (e.g. 1462 * {@link AccessibilityService#onServiceConnected()} has not yet been 1463 * called) or the service has been disconnected, this method will have 1464 * no effect and return {@code false}. 1465 * 1466 * @param animate {@code true} to animate from the current scale and 1467 * center or {@code false} to reset the scale and center 1468 * immediately 1469 * @return {@code true} on success, {@code false} on failure 1470 */ reset(boolean animate)1471 public boolean reset(boolean animate) { 1472 final IAccessibilityServiceConnection connection = 1473 AccessibilityInteractionClient.getInstance(mService).getConnection( 1474 mService.mConnectionId); 1475 if (connection != null) { 1476 try { 1477 return connection.resetMagnification(mDisplayId, animate); 1478 } catch (RemoteException re) { 1479 Log.w(LOG_TAG, "Failed to reset", re); 1480 re.rethrowFromSystemServer(); 1481 } 1482 } 1483 return false; 1484 } 1485 1486 /** 1487 * Sets the magnification scale. 1488 * <p> 1489 * <strong>Note:</strong> If the service is not yet connected (e.g. 1490 * {@link AccessibilityService#onServiceConnected()} has not yet been 1491 * called) or the service has been disconnected, this method will have 1492 * no effect and return {@code false}. 1493 * 1494 * @param scale the magnification scale to set, must be >= 1 and <= 8 1495 * @param animate {@code true} to animate from the current scale or 1496 * {@code false} to set the scale immediately 1497 * @return {@code true} on success, {@code false} on failure 1498 */ setScale(float scale, boolean animate)1499 public boolean setScale(float scale, boolean animate) { 1500 final IAccessibilityServiceConnection connection = 1501 AccessibilityInteractionClient.getInstance(mService).getConnection( 1502 mService.mConnectionId); 1503 if (connection != null) { 1504 try { 1505 return connection.setMagnificationScaleAndCenter(mDisplayId, 1506 scale, Float.NaN, Float.NaN, animate); 1507 } catch (RemoteException re) { 1508 Log.w(LOG_TAG, "Failed to set scale", re); 1509 re.rethrowFromSystemServer(); 1510 } 1511 } 1512 return false; 1513 } 1514 1515 /** 1516 * Sets the center of the magnified viewport. 1517 * <p> 1518 * <strong>Note:</strong> If the service is not yet connected (e.g. 1519 * {@link AccessibilityService#onServiceConnected()} has not yet been 1520 * called) or the service has been disconnected, this method will have 1521 * no effect and return {@code false}. 1522 * 1523 * @param centerX the unscaled screen-relative X coordinate on which to 1524 * center the viewport 1525 * @param centerY the unscaled screen-relative Y coordinate on which to 1526 * center the viewport 1527 * @param animate {@code true} to animate from the current viewport 1528 * center or {@code false} to set the center immediately 1529 * @return {@code true} on success, {@code false} on failure 1530 */ setCenter(float centerX, float centerY, boolean animate)1531 public boolean setCenter(float centerX, float centerY, boolean animate) { 1532 final IAccessibilityServiceConnection connection = 1533 AccessibilityInteractionClient.getInstance(mService).getConnection( 1534 mService.mConnectionId); 1535 if (connection != null) { 1536 try { 1537 return connection.setMagnificationScaleAndCenter(mDisplayId, 1538 Float.NaN, centerX, centerY, animate); 1539 } catch (RemoteException re) { 1540 Log.w(LOG_TAG, "Failed to set center", re); 1541 re.rethrowFromSystemServer(); 1542 } 1543 } 1544 return false; 1545 } 1546 1547 /** 1548 * Listener for changes in the state of magnification. 1549 */ 1550 public interface OnMagnificationChangedListener { 1551 /** 1552 * Called when the magnified region, scale, or center changes. 1553 * 1554 * @param controller the magnification controller 1555 * @param region the magnification region 1556 * @param scale the new scale 1557 * @param centerX the new X coordinate, in unscaled coordinates, around which 1558 * magnification is focused 1559 * @param centerY the new Y coordinate, in unscaled coordinates, around which 1560 * magnification is focused 1561 */ onMagnificationChanged(@onNull MagnificationController controller, @NonNull Region region, float scale, float centerX, float centerY)1562 void onMagnificationChanged(@NonNull MagnificationController controller, 1563 @NonNull Region region, float scale, float centerX, float centerY); 1564 } 1565 } 1566 1567 /** 1568 * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard 1569 * show mode. 1570 * 1571 * @return the soft keyboard controller 1572 */ 1573 @NonNull getSoftKeyboardController()1574 public final SoftKeyboardController getSoftKeyboardController() { 1575 synchronized (mLock) { 1576 if (mSoftKeyboardController == null) { 1577 mSoftKeyboardController = new SoftKeyboardController(this, mLock); 1578 } 1579 return mSoftKeyboardController; 1580 } 1581 } 1582 onSoftKeyboardShowModeChanged(int showMode)1583 private void onSoftKeyboardShowModeChanged(int showMode) { 1584 if (mSoftKeyboardController != null) { 1585 mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode); 1586 } 1587 } 1588 1589 /** 1590 * Used to control, query, and listen for changes to the soft keyboard show mode. 1591 * <p> 1592 * Accessibility services may request to override the decisions normally made about whether or 1593 * not the soft keyboard is shown. 1594 * <p> 1595 * If multiple services make conflicting requests, the last request is honored. A service may 1596 * register a listener to find out if the mode has changed under it. 1597 * <p> 1598 * If the user takes action to override the behavior behavior requested by an accessibility 1599 * service, the user's request takes precendence, the show mode will be reset to 1600 * {@link AccessibilityService#SHOW_MODE_AUTO}, and services will no longer be able to control 1601 * that aspect of the soft keyboard's behavior. 1602 * <p> 1603 * Note: Because soft keyboards are independent apps, the framework does not have total control 1604 * over their behavior. They may choose to show themselves, or not, without regard to requests 1605 * made here. So the framework will make a best effort to deliver the behavior requested, but 1606 * cannot guarantee success. 1607 * 1608 * @see AccessibilityService#SHOW_MODE_AUTO 1609 * @see AccessibilityService#SHOW_MODE_HIDDEN 1610 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD 1611 */ 1612 public static final class SoftKeyboardController { 1613 private final AccessibilityService mService; 1614 1615 /** 1616 * Map of listeners to their handlers. Lazily created when adding the first 1617 * soft keyboard change listener. 1618 */ 1619 private ArrayMap<OnShowModeChangedListener, Handler> mListeners; 1620 private final Object mLock; 1621 SoftKeyboardController(@onNull AccessibilityService service, @NonNull Object lock)1622 SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) { 1623 mService = service; 1624 mLock = lock; 1625 } 1626 1627 /** 1628 * Called when the service is connected. 1629 */ onServiceConnected()1630 void onServiceConnected() { 1631 synchronized(mLock) { 1632 if (mListeners != null && !mListeners.isEmpty()) { 1633 setSoftKeyboardCallbackEnabled(true); 1634 } 1635 } 1636 } 1637 1638 /** 1639 * Adds the specified change listener to the list of show mode change listeners. The 1640 * callback will occur on the service's main thread. Listener is not called on registration. 1641 */ addOnShowModeChangedListener(@onNull OnShowModeChangedListener listener)1642 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) { 1643 addOnShowModeChangedListener(listener, null); 1644 } 1645 1646 /** 1647 * Adds the specified change listener to the list of soft keyboard show mode change 1648 * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the 1649 * services's main thread if the handler is {@code null}. 1650 * 1651 * @param listener the listener to add, must be non-null 1652 * @param handler the handler on which to callback should execute, or {@code null} to 1653 * execute on the service's main thread 1654 */ addOnShowModeChangedListener(@onNull OnShowModeChangedListener listener, @Nullable Handler handler)1655 public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener, 1656 @Nullable Handler handler) { 1657 synchronized (mLock) { 1658 if (mListeners == null) { 1659 mListeners = new ArrayMap<>(); 1660 } 1661 1662 final boolean shouldEnableCallback = mListeners.isEmpty(); 1663 mListeners.put(listener, handler); 1664 1665 if (shouldEnableCallback) { 1666 // This may fail if the service is not connected yet, but if we still have 1667 // listeners when it connects, we can try again. 1668 setSoftKeyboardCallbackEnabled(true); 1669 } 1670 } 1671 } 1672 1673 /** 1674 * Removes the specified change listener from the list of keyboard show mode change 1675 * listeners. 1676 * 1677 * @param listener the listener to remove, must be non-null 1678 * @return {@code true} if the listener was removed, {@code false} otherwise 1679 */ removeOnShowModeChangedListener( @onNull OnShowModeChangedListener listener)1680 public boolean removeOnShowModeChangedListener( 1681 @NonNull OnShowModeChangedListener listener) { 1682 if (mListeners == null) { 1683 return false; 1684 } 1685 1686 synchronized (mLock) { 1687 final int keyIndex = mListeners.indexOfKey(listener); 1688 final boolean hasKey = keyIndex >= 0; 1689 if (hasKey) { 1690 mListeners.removeAt(keyIndex); 1691 } 1692 1693 if (hasKey && mListeners.isEmpty()) { 1694 // We just removed the last listener, so we don't need callbacks from the 1695 // service anymore. 1696 setSoftKeyboardCallbackEnabled(false); 1697 } 1698 1699 return hasKey; 1700 } 1701 } 1702 setSoftKeyboardCallbackEnabled(boolean enabled)1703 private void setSoftKeyboardCallbackEnabled(boolean enabled) { 1704 final IAccessibilityServiceConnection connection = 1705 AccessibilityInteractionClient.getInstance(mService).getConnection( 1706 mService.mConnectionId); 1707 if (connection != null) { 1708 try { 1709 connection.setSoftKeyboardCallbackEnabled(enabled); 1710 } catch (RemoteException re) { 1711 throw new RuntimeException(re); 1712 } 1713 } 1714 } 1715 1716 /** 1717 * Dispatches the soft keyboard show mode change to any registered listeners. This should 1718 * be called on the service's main thread. 1719 */ dispatchSoftKeyboardShowModeChanged(final int showMode)1720 void dispatchSoftKeyboardShowModeChanged(final int showMode) { 1721 final ArrayMap<OnShowModeChangedListener, Handler> entries; 1722 synchronized (mLock) { 1723 if (mListeners == null || mListeners.isEmpty()) { 1724 Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback" 1725 + " with no listeners registered!"); 1726 setSoftKeyboardCallbackEnabled(false); 1727 return; 1728 } 1729 1730 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent 1731 // modification. 1732 entries = new ArrayMap<>(mListeners); 1733 } 1734 1735 for (int i = 0, count = entries.size(); i < count; i++) { 1736 final OnShowModeChangedListener listener = entries.keyAt(i); 1737 final Handler handler = entries.valueAt(i); 1738 if (handler != null) { 1739 handler.post(new Runnable() { 1740 @Override 1741 public void run() { 1742 listener.onShowModeChanged(SoftKeyboardController.this, showMode); 1743 } 1744 }); 1745 } else { 1746 // We're already on the main thread, just run the listener. 1747 listener.onShowModeChanged(this, showMode); 1748 } 1749 } 1750 } 1751 1752 /** 1753 * Returns the show mode of the soft keyboard. 1754 * 1755 * @return the current soft keyboard show mode 1756 * 1757 * @see AccessibilityService#SHOW_MODE_AUTO 1758 * @see AccessibilityService#SHOW_MODE_HIDDEN 1759 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD 1760 */ 1761 @SoftKeyboardShowMode getShowMode()1762 public int getShowMode() { 1763 final IAccessibilityServiceConnection connection = 1764 AccessibilityInteractionClient.getInstance(mService).getConnection( 1765 mService.mConnectionId); 1766 if (connection != null) { 1767 try { 1768 return connection.getSoftKeyboardShowMode(); 1769 } catch (RemoteException re) { 1770 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re); 1771 re.rethrowFromSystemServer(); 1772 } 1773 } 1774 return SHOW_MODE_AUTO; 1775 } 1776 1777 /** 1778 * Sets the soft keyboard show mode. 1779 * <p> 1780 * <strong>Note:</strong> If the service is not yet connected (e.g. 1781 * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the 1782 * service has been disconnected, this method will have no effect and return {@code false}. 1783 * 1784 * @param showMode the new show mode for the soft keyboard 1785 * @return {@code true} on success 1786 * 1787 * @see AccessibilityService#SHOW_MODE_AUTO 1788 * @see AccessibilityService#SHOW_MODE_HIDDEN 1789 * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD 1790 */ setShowMode(@oftKeyboardShowMode int showMode)1791 public boolean setShowMode(@SoftKeyboardShowMode int showMode) { 1792 final IAccessibilityServiceConnection connection = 1793 AccessibilityInteractionClient.getInstance(mService).getConnection( 1794 mService.mConnectionId); 1795 if (connection != null) { 1796 try { 1797 return connection.setSoftKeyboardShowMode(showMode); 1798 } catch (RemoteException re) { 1799 Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re); 1800 re.rethrowFromSystemServer(); 1801 } 1802 } 1803 return false; 1804 } 1805 1806 /** 1807 * Listener for changes in the soft keyboard show mode. 1808 */ 1809 public interface OnShowModeChangedListener { 1810 /** 1811 * Called when the soft keyboard behavior changes. The default show mode is 1812 * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is 1813 * focused. An AccessibilityService can also request the show mode 1814 * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. 1815 * 1816 * @param controller the soft keyboard controller 1817 * @param showMode the current soft keyboard show mode 1818 */ onShowModeChanged(@onNull SoftKeyboardController controller, @SoftKeyboardShowMode int showMode)1819 void onShowModeChanged(@NonNull SoftKeyboardController controller, 1820 @SoftKeyboardShowMode int showMode); 1821 } 1822 1823 /** 1824 * Switches the current IME for the user for whom the service is enabled. The change will 1825 * persist until the current IME is explicitly changed again, and may persist beyond the 1826 * life cycle of the requesting service. 1827 * 1828 * @param imeId The ID of the input method to make current. This IME must be installed and 1829 * enabled. 1830 * @return {@code true} if the current input method was successfully switched to the input 1831 * method by {@code imeId}, 1832 * {@code false} if the input method specified is not installed, not enabled, or 1833 * otherwise not available to become the current IME 1834 * 1835 * @see android.view.inputmethod.InputMethodInfo#getId() 1836 */ switchToInputMethod(@onNull String imeId)1837 public boolean switchToInputMethod(@NonNull String imeId) { 1838 final IAccessibilityServiceConnection connection = 1839 AccessibilityInteractionClient.getInstance(mService).getConnection( 1840 mService.mConnectionId); 1841 if (connection != null) { 1842 try { 1843 return connection.switchToInputMethod(imeId); 1844 } catch (RemoteException re) { 1845 throw new RuntimeException(re); 1846 } 1847 } 1848 return false; 1849 } 1850 } 1851 1852 /** 1853 * Returns the controller for the accessibility button within the system's navigation area. 1854 * This instance may be used to query the accessibility button's state and register listeners 1855 * for interactions with and state changes for the accessibility button when 1856 * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set. 1857 * <p> 1858 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button 1859 * within a navigation area, and as such, use of this class should be considered only as an 1860 * optional feature or shortcut on supported device implementations. 1861 * </p> 1862 * 1863 * @return the accessibility button controller for this {@link AccessibilityService} 1864 */ 1865 @NonNull getAccessibilityButtonController()1866 public final AccessibilityButtonController getAccessibilityButtonController() { 1867 return getAccessibilityButtonController(Display.DEFAULT_DISPLAY); 1868 } 1869 1870 /** 1871 * Returns the controller of specified logical display for the accessibility button within the 1872 * system's navigation area. This instance may be used to query the accessibility button's 1873 * state and register listeners for interactions with and state changes for the accessibility 1874 * button when {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set. 1875 * <p> 1876 * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button 1877 * within a navigation area, and as such, use of this class should be considered only as an 1878 * optional feature or shortcut on supported device implementations. 1879 * </p> 1880 * 1881 * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for default 1882 * display. 1883 * @return the accessibility button controller for this {@link AccessibilityService} 1884 */ 1885 @NonNull getAccessibilityButtonController(int displayId)1886 public final AccessibilityButtonController getAccessibilityButtonController(int displayId) { 1887 synchronized (mLock) { 1888 AccessibilityButtonController controller = mAccessibilityButtonControllers.get( 1889 displayId); 1890 if (controller == null) { 1891 controller = new AccessibilityButtonController( 1892 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId)); 1893 mAccessibilityButtonControllers.put(displayId, controller); 1894 } 1895 return controller; 1896 } 1897 } 1898 onAccessibilityButtonClicked(int displayId)1899 private void onAccessibilityButtonClicked(int displayId) { 1900 getAccessibilityButtonController(displayId).dispatchAccessibilityButtonClicked(); 1901 } 1902 onAccessibilityButtonAvailabilityChanged(boolean available)1903 private void onAccessibilityButtonAvailabilityChanged(boolean available) { 1904 getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged( 1905 available); 1906 } 1907 1908 /** This is called when the system action list is changed. */ onSystemActionsChanged()1909 public void onSystemActionsChanged() { 1910 } 1911 1912 /** 1913 * Returns a list of system actions available in the system right now. 1914 * <p> 1915 * System actions that correspond to the global action constants will have matching action IDs. 1916 * For example, an with id {@link #GLOBAL_ACTION_BACK} will perform the back action. 1917 * </p> 1918 * <p> 1919 * These actions should be called by {@link #performGlobalAction}. 1920 * </p> 1921 * 1922 * @return A list of available system actions. 1923 */ getSystemActions()1924 public final @NonNull List<AccessibilityAction> getSystemActions() { 1925 IAccessibilityServiceConnection connection = 1926 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 1927 if (connection != null) { 1928 try { 1929 return connection.getSystemActions(); 1930 } catch (RemoteException re) { 1931 Log.w(LOG_TAG, "Error while calling getSystemActions", re); 1932 re.rethrowFromSystemServer(); 1933 } 1934 } 1935 return Collections.emptyList(); 1936 } 1937 1938 /** 1939 * Performs a global action. Such an action can be performed 1940 * at any moment regardless of the current application or user 1941 * location in that application. For example going back, going 1942 * home, opening recents, etc. 1943 * 1944 * <p> 1945 * Note: The global action ids themselves give no information about the current availability 1946 * of their corresponding actions. To determine if a global action is available, use 1947 * {@link #getSystemActions()} 1948 * 1949 * @param action The action to perform. 1950 * @return Whether the action was successfully performed. 1951 * 1952 * @see #GLOBAL_ACTION_BACK 1953 * @see #GLOBAL_ACTION_HOME 1954 * @see #GLOBAL_ACTION_NOTIFICATIONS 1955 * @see #GLOBAL_ACTION_RECENTS 1956 */ performGlobalAction(int action)1957 public final boolean performGlobalAction(int action) { 1958 IAccessibilityServiceConnection connection = 1959 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 1960 if (connection != null) { 1961 try { 1962 return connection.performGlobalAction(action); 1963 } catch (RemoteException re) { 1964 Log.w(LOG_TAG, "Error while calling performGlobalAction", re); 1965 re.rethrowFromSystemServer(); 1966 } 1967 } 1968 return false; 1969 } 1970 1971 /** 1972 * Find the view that has the specified focus type. The search is performed 1973 * across all windows. 1974 * <p> 1975 * <strong>Note:</strong> In order to access the windows your service has 1976 * to declare the capability to retrieve window content by setting the 1977 * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent} 1978 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 1979 * Also the service has to opt-in to retrieve the interactive windows by 1980 * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS} 1981 * flag. Otherwise, the search will be performed only in the active window. 1982 * </p> 1983 * <p> 1984 * <strong>Note:</strong> If the view with {@link AccessibilityNodeInfo#FOCUS_INPUT} 1985 * is on an embedded view hierarchy which is embedded in a {@link SurfaceView} via 1986 * {@link SurfaceView#setChildSurfacePackage}, there is a limitation that this API 1987 * won't be able to find the node for the view. It's because views don't know about 1988 * the embedded hierarchies. Instead, you could traverse all the nodes to find the 1989 * focus. 1990 * </p> 1991 * 1992 * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or 1993 * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}. 1994 * @return The node info of the focused view or null. 1995 * 1996 * @see AccessibilityNodeInfo#FOCUS_INPUT 1997 * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY 1998 */ findFocus(int focus)1999 public AccessibilityNodeInfo findFocus(int focus) { 2000 return AccessibilityInteractionClient.getInstance(this).findFocus(mConnectionId, 2001 AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus); 2002 } 2003 2004 /** 2005 * Gets the an {@link AccessibilityServiceInfo} describing this 2006 * {@link AccessibilityService}. This method is useful if one wants 2007 * to change some of the dynamically configurable properties at 2008 * runtime. 2009 * 2010 * @return The accessibility service info. 2011 * 2012 * @see AccessibilityServiceInfo 2013 */ getServiceInfo()2014 public final AccessibilityServiceInfo getServiceInfo() { 2015 IAccessibilityServiceConnection connection = 2016 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2017 if (connection != null) { 2018 try { 2019 return connection.getServiceInfo(); 2020 } catch (RemoteException re) { 2021 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re); 2022 re.rethrowFromSystemServer(); 2023 } 2024 } 2025 return null; 2026 } 2027 2028 /** 2029 * Sets the {@link AccessibilityServiceInfo} that describes this service. 2030 * <p> 2031 * Note: You can call this method any time but the info will be picked up after 2032 * the system has bound to this service and when this method is called thereafter. 2033 * 2034 * @param info The info. 2035 */ setServiceInfo(AccessibilityServiceInfo info)2036 public final void setServiceInfo(AccessibilityServiceInfo info) { 2037 mInfo = info; 2038 sendServiceInfo(); 2039 } 2040 2041 /** 2042 * Sets the {@link AccessibilityServiceInfo} for this service if the latter is 2043 * properly set and there is an {@link IAccessibilityServiceConnection} to the 2044 * AccessibilityManagerService. 2045 */ sendServiceInfo()2046 private void sendServiceInfo() { 2047 IAccessibilityServiceConnection connection = 2048 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2049 if (mInfo != null && connection != null) { 2050 try { 2051 connection.setServiceInfo(mInfo); 2052 mInfo = null; 2053 AccessibilityInteractionClient.getInstance(this).clearCache(); 2054 } catch (RemoteException re) { 2055 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re); 2056 re.rethrowFromSystemServer(); 2057 } 2058 } 2059 } 2060 2061 @Override getSystemService(@erviceName @onNull String name)2062 public Object getSystemService(@ServiceName @NonNull String name) { 2063 if (getBaseContext() == null) { 2064 throw new IllegalStateException( 2065 "System services not available to Activities before onCreate()"); 2066 } 2067 2068 // Guarantee that we always return the same window manager instance. 2069 if (WINDOW_SERVICE.equals(name)) { 2070 if (mWindowManager == null) { 2071 mWindowManager = (WindowManager) getBaseContext().getSystemService(name); 2072 } 2073 return mWindowManager; 2074 } 2075 return super.getSystemService(name); 2076 } 2077 2078 /** 2079 * Takes a screenshot of the specified display and returns it via an 2080 * {@link AccessibilityService.ScreenshotResult}. You can use {@link Bitmap#wrapHardwareBuffer} 2081 * to construct the bitmap from the ScreenshotResult's payload. 2082 * <p> 2083 * <strong>Note:</strong> In order to take screenshot your service has 2084 * to declare the capability to take screenshot by setting the 2085 * {@link android.R.styleable#AccessibilityService_canTakeScreenshot} 2086 * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}. 2087 * </p> 2088 * 2089 * @param displayId The logic display id, must be {@link Display#DEFAULT_DISPLAY} for 2090 * default display. 2091 * @param executor Executor on which to run the callback. 2092 * @param callback The callback invoked when taking screenshot has succeeded or failed. 2093 * See {@link TakeScreenshotCallback} for details. 2094 */ takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor, @NonNull TakeScreenshotCallback callback)2095 public void takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor, 2096 @NonNull TakeScreenshotCallback callback) { 2097 Preconditions.checkNotNull(executor, "executor cannot be null"); 2098 Preconditions.checkNotNull(callback, "callback cannot be null"); 2099 final IAccessibilityServiceConnection connection = 2100 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2101 if (connection == null) { 2102 sendScreenshotFailure(ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, executor, callback); 2103 return; 2104 } 2105 try { 2106 connection.takeScreenshot(displayId, new RemoteCallback((result) -> { 2107 final int status = result.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS); 2108 if (status != TAKE_SCREENSHOT_SUCCESS) { 2109 sendScreenshotFailure(status, executor, callback); 2110 return; 2111 } 2112 final HardwareBuffer hardwareBuffer = 2113 result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER); 2114 final ParcelableColorSpace colorSpace = 2115 result.getParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE); 2116 final ScreenshotResult screenshot = new ScreenshotResult(hardwareBuffer, 2117 colorSpace.getColorSpace(), 2118 result.getLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP)); 2119 sendScreenshotSuccess(screenshot, executor, callback); 2120 })); 2121 } catch (RemoteException re) { 2122 throw new RuntimeException(re); 2123 } 2124 } 2125 2126 /** 2127 * Sets the strokeWidth and color of the accessibility focus rectangle. 2128 * <p> 2129 * <strong>Note:</strong> This setting persists until this or another active 2130 * AccessibilityService changes it or the device reboots. 2131 * </p> 2132 * 2133 * @param strokeWidth The stroke width of the rectangle in pixels. 2134 * Setting this value to zero results in no focus rectangle being drawn. 2135 * @param color The color of the rectangle. 2136 */ setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color)2137 public void setAccessibilityFocusAppearance(int strokeWidth, @ColorInt int color) { 2138 IAccessibilityServiceConnection connection = 2139 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2140 if (connection != null) { 2141 try { 2142 connection.setFocusAppearance(strokeWidth, color); 2143 } catch (RemoteException re) { 2144 Log.w(LOG_TAG, "Error while setting the strokeWidth and color of the " 2145 + "accessibility focus rectangle", re); 2146 re.rethrowFromSystemServer(); 2147 } 2148 } 2149 } 2150 2151 /** 2152 * Implement to return the implementation of the internal accessibility 2153 * service interface. 2154 */ 2155 @Override onBind(Intent intent)2156 public final IBinder onBind(Intent intent) { 2157 return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() { 2158 @Override 2159 public void onServiceConnected() { 2160 AccessibilityService.this.dispatchServiceConnected(); 2161 } 2162 2163 @Override 2164 public void onInterrupt() { 2165 AccessibilityService.this.onInterrupt(); 2166 } 2167 2168 @Override 2169 public void onAccessibilityEvent(AccessibilityEvent event) { 2170 AccessibilityService.this.onAccessibilityEvent(event); 2171 } 2172 2173 @Override 2174 public void init(int connectionId, IBinder windowToken) { 2175 mConnectionId = connectionId; 2176 mWindowToken = windowToken; 2177 2178 // The client may have already obtained the window manager, so 2179 // update the default token on whatever manager we gave them. 2180 final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE); 2181 wm.setDefaultToken(windowToken); 2182 } 2183 2184 @Override 2185 public boolean onGesture(AccessibilityGestureEvent gestureEvent) { 2186 return AccessibilityService.this.onGesture(gestureEvent); 2187 } 2188 2189 @Override 2190 public boolean onKeyEvent(KeyEvent event) { 2191 return AccessibilityService.this.onKeyEvent(event); 2192 } 2193 2194 @Override 2195 public void onMagnificationChanged(int displayId, @NonNull Region region, 2196 float scale, float centerX, float centerY) { 2197 AccessibilityService.this.onMagnificationChanged(displayId, region, scale, 2198 centerX, centerY); 2199 } 2200 2201 @Override 2202 public void onSoftKeyboardShowModeChanged(int showMode) { 2203 AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode); 2204 } 2205 2206 @Override 2207 public void onPerformGestureResult(int sequence, boolean completedSuccessfully) { 2208 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully); 2209 } 2210 2211 @Override 2212 public void onFingerprintCapturingGesturesChanged(boolean active) { 2213 AccessibilityService.this.onFingerprintCapturingGesturesChanged(active); 2214 } 2215 2216 @Override 2217 public void onFingerprintGesture(int gesture) { 2218 AccessibilityService.this.onFingerprintGesture(gesture); 2219 } 2220 2221 @Override 2222 public void onAccessibilityButtonClicked(int displayId) { 2223 AccessibilityService.this.onAccessibilityButtonClicked(displayId); 2224 } 2225 2226 @Override 2227 public void onAccessibilityButtonAvailabilityChanged(boolean available) { 2228 AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available); 2229 } 2230 2231 @Override 2232 public void onSystemActionsChanged() { 2233 AccessibilityService.this.onSystemActionsChanged(); 2234 } 2235 }); 2236 } 2237 2238 /** 2239 * Implements the internal {@link IAccessibilityServiceClient} interface to convert 2240 * incoming calls to it back to calls on an {@link AccessibilityService}. 2241 * 2242 * @hide 2243 */ 2244 public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub 2245 implements HandlerCaller.Callback { 2246 private static final int DO_INIT = 1; 2247 private static final int DO_ON_INTERRUPT = 2; 2248 private static final int DO_ON_ACCESSIBILITY_EVENT = 3; 2249 private static final int DO_ON_GESTURE = 4; 2250 private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5; 2251 private static final int DO_ON_KEY_EVENT = 6; 2252 private static final int DO_ON_MAGNIFICATION_CHANGED = 7; 2253 private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8; 2254 private static final int DO_GESTURE_COMPLETE = 9; 2255 private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10; 2256 private static final int DO_ON_FINGERPRINT_GESTURE = 11; 2257 private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12; 2258 private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13; 2259 private static final int DO_ON_SYSTEM_ACTIONS_CHANGED = 14; 2260 2261 private final HandlerCaller mCaller; 2262 2263 private final Callbacks mCallback; 2264 private final Context mContext; 2265 2266 private int mConnectionId = AccessibilityInteractionClient.NO_ID; 2267 2268 public IAccessibilityServiceClientWrapper(Context context, Looper looper, 2269 Callbacks callback) { 2270 mCallback = callback; 2271 mContext = context; 2272 mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/); 2273 } 2274 2275 public void init(IAccessibilityServiceConnection connection, int connectionId, 2276 IBinder windowToken) { 2277 Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId, 2278 connection, windowToken); 2279 mCaller.sendMessage(message); 2280 } 2281 2282 public void onInterrupt() { 2283 Message message = mCaller.obtainMessage(DO_ON_INTERRUPT); 2284 mCaller.sendMessage(message); 2285 } 2286 2287 public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) { 2288 Message message = mCaller.obtainMessageBO( 2289 DO_ON_ACCESSIBILITY_EVENT, serviceWantsEvent, event); 2290 mCaller.sendMessage(message); 2291 } 2292 2293 @Override 2294 public void onGesture(AccessibilityGestureEvent gestureInfo) { 2295 Message message = mCaller.obtainMessageO(DO_ON_GESTURE, gestureInfo); 2296 mCaller.sendMessage(message); 2297 } 2298 2299 public void clearAccessibilityCache() { 2300 Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE); 2301 mCaller.sendMessage(message); 2302 } 2303 2304 @Override 2305 public void onKeyEvent(KeyEvent event, int sequence) { 2306 Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event); 2307 mCaller.sendMessage(message); 2308 } 2309 2310 /** Magnification changed callbacks for different displays */ 2311 public void onMagnificationChanged(int displayId, @NonNull Region region, 2312 float scale, float centerX, float centerY) { 2313 final SomeArgs args = SomeArgs.obtain(); 2314 args.arg1 = region; 2315 args.arg2 = scale; 2316 args.arg3 = centerX; 2317 args.arg4 = centerY; 2318 args.argi1 = displayId; 2319 2320 final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args); 2321 mCaller.sendMessage(message); 2322 } 2323 2324 public void onSoftKeyboardShowModeChanged(int showMode) { 2325 final Message message = 2326 mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode); 2327 mCaller.sendMessage(message); 2328 } 2329 2330 public void onPerformGestureResult(int sequence, boolean successfully) { 2331 Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence, 2332 successfully ? 1 : 0); 2333 mCaller.sendMessage(message); 2334 } 2335 2336 public void onFingerprintCapturingGesturesChanged(boolean active) { 2337 mCaller.sendMessage(mCaller.obtainMessageI( 2338 DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0)); 2339 } 2340 2341 public void onFingerprintGesture(int gesture) { 2342 mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture)); 2343 } 2344 2345 /** Accessibility button clicked callbacks for different displays */ 2346 public void onAccessibilityButtonClicked(int displayId) { 2347 final Message message = mCaller.obtainMessageI(DO_ACCESSIBILITY_BUTTON_CLICKED, 2348 displayId); 2349 mCaller.sendMessage(message); 2350 } 2351 2352 public void onAccessibilityButtonAvailabilityChanged(boolean available) { 2353 final Message message = mCaller.obtainMessageI( 2354 DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0)); 2355 mCaller.sendMessage(message); 2356 } 2357 2358 /** This is called when the system action list is changed. */ 2359 public void onSystemActionsChanged() { 2360 mCaller.sendMessage(mCaller.obtainMessage(DO_ON_SYSTEM_ACTIONS_CHANGED)); 2361 } 2362 2363 @Override 2364 public void executeMessage(Message message) { 2365 switch (message.what) { 2366 case DO_ON_ACCESSIBILITY_EVENT: { 2367 AccessibilityEvent event = (AccessibilityEvent) message.obj; 2368 boolean serviceWantsEvent = message.arg1 != 0; 2369 if (event != null) { 2370 // Send the event to AccessibilityCache via AccessibilityInteractionClient 2371 AccessibilityInteractionClient.getInstance(mContext).onAccessibilityEvent( 2372 event); 2373 if (serviceWantsEvent 2374 && (mConnectionId != AccessibilityInteractionClient.NO_ID)) { 2375 // Send the event to AccessibilityService 2376 mCallback.onAccessibilityEvent(event); 2377 } 2378 // Make sure the event is recycled. 2379 try { 2380 event.recycle(); 2381 } catch (IllegalStateException ise) { 2382 /* ignore - best effort */ 2383 } 2384 } 2385 return; 2386 } 2387 case DO_ON_INTERRUPT: { 2388 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2389 mCallback.onInterrupt(); 2390 } 2391 return; 2392 } 2393 case DO_INIT: { 2394 mConnectionId = message.arg1; 2395 SomeArgs args = (SomeArgs) message.obj; 2396 IAccessibilityServiceConnection connection = 2397 (IAccessibilityServiceConnection) args.arg1; 2398 IBinder windowToken = (IBinder) args.arg2; 2399 args.recycle(); 2400 if (connection != null) { 2401 AccessibilityInteractionClient.getInstance(mContext).addConnection( 2402 mConnectionId, connection); 2403 mCallback.init(mConnectionId, windowToken); 2404 mCallback.onServiceConnected(); 2405 } else { 2406 AccessibilityInteractionClient.getInstance(mContext).removeConnection( 2407 mConnectionId); 2408 mConnectionId = AccessibilityInteractionClient.NO_ID; 2409 AccessibilityInteractionClient.getInstance(mContext).clearCache(); 2410 mCallback.init(AccessibilityInteractionClient.NO_ID, null); 2411 } 2412 return; 2413 } 2414 case DO_ON_GESTURE: { 2415 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2416 mCallback.onGesture((AccessibilityGestureEvent) message.obj); 2417 } 2418 return; 2419 } 2420 case DO_CLEAR_ACCESSIBILITY_CACHE: { 2421 AccessibilityInteractionClient.getInstance(mContext).clearCache(); 2422 return; 2423 } 2424 case DO_ON_KEY_EVENT: { 2425 KeyEvent event = (KeyEvent) message.obj; 2426 try { 2427 IAccessibilityServiceConnection connection = AccessibilityInteractionClient 2428 .getInstance(mContext).getConnection(mConnectionId); 2429 if (connection != null) { 2430 final boolean result = mCallback.onKeyEvent(event); 2431 final int sequence = message.arg1; 2432 try { 2433 connection.setOnKeyEventResult(result, sequence); 2434 } catch (RemoteException re) { 2435 /* ignore */ 2436 } 2437 } 2438 } finally { 2439 // Make sure the event is recycled. 2440 try { 2441 event.recycle(); 2442 } catch (IllegalStateException ise) { 2443 /* ignore - best effort */ 2444 } 2445 } 2446 return; 2447 } 2448 case DO_ON_MAGNIFICATION_CHANGED: { 2449 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2450 final SomeArgs args = (SomeArgs) message.obj; 2451 final Region region = (Region) args.arg1; 2452 final float scale = (float) args.arg2; 2453 final float centerX = (float) args.arg3; 2454 final float centerY = (float) args.arg4; 2455 final int displayId = args.argi1; 2456 args.recycle(); 2457 mCallback.onMagnificationChanged(displayId, region, scale, 2458 centerX, centerY); 2459 } 2460 return; 2461 } 2462 case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: { 2463 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2464 final int showMode = (int) message.arg1; 2465 mCallback.onSoftKeyboardShowModeChanged(showMode); 2466 } 2467 return; 2468 } 2469 case DO_GESTURE_COMPLETE: { 2470 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2471 final boolean successfully = message.arg2 == 1; 2472 mCallback.onPerformGestureResult(message.arg1, successfully); 2473 } 2474 return; 2475 } 2476 case DO_ON_FINGERPRINT_ACTIVE_CHANGED: { 2477 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2478 mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1); 2479 } 2480 return; 2481 } 2482 case DO_ON_FINGERPRINT_GESTURE: { 2483 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2484 mCallback.onFingerprintGesture(message.arg1); 2485 } 2486 return; 2487 } 2488 case DO_ACCESSIBILITY_BUTTON_CLICKED: { 2489 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2490 mCallback.onAccessibilityButtonClicked(message.arg1); 2491 } 2492 return; 2493 } 2494 case DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: { 2495 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2496 final boolean available = (message.arg1 != 0); 2497 mCallback.onAccessibilityButtonAvailabilityChanged(available); 2498 } 2499 return; 2500 } 2501 case DO_ON_SYSTEM_ACTIONS_CHANGED: { 2502 if (mConnectionId != AccessibilityInteractionClient.NO_ID) { 2503 mCallback.onSystemActionsChanged(); 2504 } 2505 return; 2506 } 2507 default : 2508 Log.w(LOG_TAG, "Unknown message type " + message.what); 2509 } 2510 } 2511 } 2512 2513 /** 2514 * Class used to report status of dispatched gestures 2515 */ 2516 public static abstract class GestureResultCallback { 2517 /** Called when the gesture has completed successfully 2518 * 2519 * @param gestureDescription The description of the gesture that completed. 2520 */ 2521 public void onCompleted(GestureDescription gestureDescription) { 2522 } 2523 2524 /** Called when the gesture was cancelled 2525 * 2526 * @param gestureDescription The description of the gesture that was cancelled. 2527 */ 2528 public void onCancelled(GestureDescription gestureDescription) { 2529 } 2530 } 2531 2532 /* Object to keep track of gesture result callbacks */ 2533 private static class GestureResultCallbackInfo { 2534 GestureDescription gestureDescription; 2535 GestureResultCallback callback; 2536 Handler handler; 2537 2538 GestureResultCallbackInfo(GestureDescription gestureDescription, 2539 GestureResultCallback callback, Handler handler) { 2540 this.gestureDescription = gestureDescription; 2541 this.callback = callback; 2542 this.handler = handler; 2543 } 2544 } 2545 2546 private void sendScreenshotSuccess(ScreenshotResult screenshot, Executor executor, 2547 TakeScreenshotCallback callback) { 2548 executor.execute(() -> callback.onSuccess(screenshot)); 2549 } 2550 2551 private void sendScreenshotFailure(@ScreenshotErrorCode int errorCode, Executor executor, 2552 TakeScreenshotCallback callback) { 2553 executor.execute(() -> callback.onFailure(errorCode)); 2554 } 2555 2556 /** 2557 * Interface used to report status of taking screenshot. 2558 */ 2559 public interface TakeScreenshotCallback { 2560 /** Called when taking screenshot has completed successfully. 2561 * 2562 * @param screenshot The content of screenshot. 2563 */ 2564 void onSuccess(@NonNull ScreenshotResult screenshot); 2565 2566 /** Called when taking screenshot has failed. {@code errorCode} will identify the 2567 * reason of failure. 2568 * 2569 * @param errorCode The error code of this operation. 2570 */ 2571 void onFailure(@ScreenshotErrorCode int errorCode); 2572 } 2573 2574 /** 2575 * Can be used to construct a bitmap of the screenshot or any other operations for 2576 * {@link AccessibilityService#takeScreenshot} API. 2577 */ 2578 public static final class ScreenshotResult { 2579 private final @NonNull HardwareBuffer mHardwareBuffer; 2580 private final @NonNull ColorSpace mColorSpace; 2581 private final long mTimestamp; 2582 2583 private ScreenshotResult(@NonNull HardwareBuffer hardwareBuffer, 2584 @NonNull ColorSpace colorSpace, long timestamp) { 2585 Preconditions.checkNotNull(hardwareBuffer, "hardwareBuffer cannot be null"); 2586 Preconditions.checkNotNull(colorSpace, "colorSpace cannot be null"); 2587 mHardwareBuffer = hardwareBuffer; 2588 mColorSpace = colorSpace; 2589 mTimestamp = timestamp; 2590 } 2591 2592 /** 2593 * Gets the {@link ColorSpace} identifying a specific organization of colors of the 2594 * screenshot. 2595 * 2596 * @return the color space 2597 */ 2598 @NonNull 2599 public ColorSpace getColorSpace() { 2600 return mColorSpace; 2601 } 2602 2603 /** 2604 * Gets the {@link HardwareBuffer} representing a memory buffer of the screenshot. 2605 * <p> 2606 * <strong>Note:</strong> The application should call {@link HardwareBuffer#close()} when 2607 * the buffer is no longer needed to free the underlying resources. 2608 * </p> 2609 * 2610 * @return the hardware buffer 2611 */ 2612 @NonNull 2613 public HardwareBuffer getHardwareBuffer() { 2614 return mHardwareBuffer; 2615 } 2616 2617 /** 2618 * Gets the timestamp of taking the screenshot. 2619 * 2620 * @return milliseconds of non-sleep uptime before screenshot since boot and it's from 2621 * {@link SystemClock#uptimeMillis()} 2622 */ 2623 public long getTimestamp() { 2624 return mTimestamp; 2625 }; 2626 } 2627 2628 /** 2629 * When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this 2630 * function requests that touch interactions starting in the specified region of the screen 2631 * bypass the gesture detector. There can only be one gesture detection passthrough region per 2632 * display. Requesting a new gesture detection passthrough region clears the existing one. To 2633 * disable this passthrough and return to the original behavior, pass in an empty region. When 2634 * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this 2635 * function has no effect. 2636 * 2637 * @param displayId The display on which to set this region. 2638 * @param region the region of the screen. 2639 */ 2640 public void setGestureDetectionPassthroughRegion(int displayId, @NonNull Region region) { 2641 Preconditions.checkNotNull(region, "region cannot be null"); 2642 final IAccessibilityServiceConnection connection = 2643 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2644 if (connection != null) { 2645 try { 2646 connection.setGestureDetectionPassthroughRegion(displayId, region); 2647 } catch (RemoteException re) { 2648 throw new RuntimeException(re); 2649 } 2650 } 2651 } 2652 2653 /** 2654 * When {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, this 2655 * function requests that touch interactions starting in the specified region of the screen 2656 * bypass the touch explorer and go straight to the view hierarchy. There can only be one touch 2657 * exploration passthrough region per display. Requesting a new touch explorationpassthrough 2658 * region clears the existing one. To disable this passthrough and return to the original 2659 * behavior, pass in an empty region. When {@link 2660 * AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this function has 2661 * no effect. 2662 * 2663 * @param displayId The display on which to set this region. 2664 * @param region the region of the screen . 2665 */ 2666 public void setTouchExplorationPassthroughRegion(int displayId, @NonNull Region region) { 2667 Preconditions.checkNotNull(region, "region cannot be null"); 2668 final IAccessibilityServiceConnection connection = 2669 AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); 2670 if (connection != null) { 2671 try { 2672 connection.setTouchExplorationPassthroughRegion(displayId, region); 2673 } catch (RemoteException re) { 2674 throw new RuntimeException(re); 2675 } 2676 } 2677 } 2678 } 2679