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