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