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