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