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