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