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