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