1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.accessibilityservice;
18 
19 import android.accessibilityservice.GestureDescription.MotionEventGenerator;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.app.Service;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.ParceledListSlice;
29 import android.graphics.Region;
30 import android.os.Build;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.util.ArrayMap;
37 import android.util.Log;
38 import android.util.Slog;
39 import android.util.SparseArray;
40 import android.view.Display;
41 import android.view.KeyEvent;
42 import android.view.WindowManager;
43 import android.view.WindowManagerImpl;
44 import android.view.accessibility.AccessibilityEvent;
45 import android.view.accessibility.AccessibilityInteractionClient;
46 import android.view.accessibility.AccessibilityNodeInfo;
47 import android.view.accessibility.AccessibilityWindowInfo;
48 
49 import com.android.internal.os.HandlerCaller;
50 import com.android.internal.os.SomeArgs;
51 
52 import java.lang.annotation.Retention;
53 import java.lang.annotation.RetentionPolicy;
54 import java.util.List;
55 
56 /**
57  * Accessibility services should only be used to assist users with disabilities in using
58  * Android devices and apps. They run in the background and receive callbacks by the system
59  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
60  * in the user interface, for example, the focus has changed, a button has been clicked,
61  * etc. Such a service can optionally request the capability for querying the content
62  * of the active window. Development of an accessibility service requires extending this
63  * class and implementing its abstract methods.
64  *
65  * <div class="special reference">
66  * <h3>Developer Guides</h3>
67  * <p>For more information about creating AccessibilityServices, read the
68  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
69  * developer guide.</p>
70  * </div>
71  *
72  * <h3>Lifecycle</h3>
73  * <p>
74  * The lifecycle of an accessibility service is managed exclusively by the system and
75  * follows the established service life cycle. Starting an accessibility service is triggered
76  * exclusively by the user explicitly turning the service on in device settings. After the system
77  * binds to a service, it calls {@link AccessibilityService#onServiceConnected()}. This method can
78  * be overridden by clients that want to perform post binding setup.
79  * </p>
80  * <p>
81  * An accessibility service stops either when the user turns it off in device settings or when
82  * it calls {@link AccessibilityService#disableSelf()}.
83  * </p>
84  * <h3>Declaration</h3>
85  * <p>
86  * An accessibility is declared as any other service in an AndroidManifest.xml, but it
87  * must do two things:
88  * <ul>
89  *     <ol>
90  *         Specify that it handles the "android.accessibilityservice.AccessibilityService"
91  *         {@link android.content.Intent}.
92  *     </ol>
93  *     <ol>
94  *         Request the {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to
95  *         ensure that only the system can bind to it.
96  *     </ol>
97  * </ul>
98  * If either of these items is missing, the system will ignore the accessibility service.
99  * Following is an example declaration:
100  * </p>
101  * <pre> &lt;service android:name=".MyAccessibilityService"
102  *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
103  *     &lt;intent-filter&gt;
104  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
105  *     &lt;/intent-filter&gt;
106  *     . . .
107  * &lt;/service&gt;</pre>
108  * <h3>Configuration</h3>
109  * <p>
110  * An accessibility service can be configured to receive specific types of accessibility events,
111  * listen only to specific packages, get events from each type only once in a given time frame,
112  * retrieve window content, specify a settings activity, etc.
113  * </p>
114  * <p>
115  * There are two approaches for configuring an accessibility service:
116  * </p>
117  * <ul>
118  * <li>
119  * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
120  * the service. A service declaration with a meta-data tag is presented below:
121  * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
122  *     &lt;intent-filter&gt;
123  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
124  *     &lt;/intent-filter&gt;
125  *     &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
126  * &lt;/service&gt;</pre>
127  * <p class="note">
128  * <strong>Note:</strong> This approach enables setting all properties.
129  * </p>
130  * <p>
131  * For more details refer to {@link #SERVICE_META_DATA} and
132  * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
133  * </p>
134  * </li>
135  * <li>
136  * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
137  * that this method can be called any time to dynamically change the service configuration.
138  * <p class="note">
139  * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
140  * {@link AccessibilityServiceInfo#eventTypes},
141  * {@link AccessibilityServiceInfo#feedbackType},
142  * {@link AccessibilityServiceInfo#flags},
143  * {@link AccessibilityServiceInfo#notificationTimeout},
144  * {@link AccessibilityServiceInfo#packageNames}
145  * </p>
146  * <p>
147  * For more details refer to {@link AccessibilityServiceInfo}.
148  * </p>
149  * </li>
150  * </ul>
151  * <h3>Retrieving window content</h3>
152  * <p>
153  * A service can specify in its declaration that it can retrieve window
154  * content which is represented as a tree of {@link AccessibilityWindowInfo} and
155  * {@link AccessibilityNodeInfo} objects. Note that
156  * declaring this capability requires that the service declares its configuration via
157  * an XML resource referenced by {@link #SERVICE_META_DATA}.
158  * </p>
159  * <p>
160  * Window content may be retrieved with
161  * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()},
162  * {@link AccessibilityService#findFocus(int)},
163  * {@link AccessibilityService#getWindows()}, or
164  * {@link AccessibilityService#getRootInActiveWindow()}.
165  * </p>
166  * <p class="note">
167  * <strong>Note</strong> An accessibility service may have requested to be notified for
168  * a subset of the event types, and thus be unaware when the node hierarchy has changed. It is also
169  * possible for a node to contain outdated information because the window content may change at any
170  * time.
171  * </p>
172  * <h3>Notification strategy</h3>
173  * <p>
174  * All accessibility services are notified of all events they have requested, regardless of their
175  * feedback type.
176  * </p>
177  * <p class="note">
178  * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
179  * events to the client too frequently since this is accomplished via an expensive
180  * interprocess call. One can think of the timeout as a criteria to determine when
181  * event generation has settled down.</p>
182  * <h3>Event types</h3>
183  * <ul>
184  * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
185  * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
186  * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
187  * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li>
188  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li>
189  * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li>
190  * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li>
191  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li>
192  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li>
193  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
194  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
195  * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
196  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li>
197  * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li>
198  * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li>
199  * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li>
200  * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li>
201  * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li>
202  * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li>
203  * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li>
204  * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li>
205  * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li>
206  * </ul>
207  * <h3>Feedback types</h3>
208  * <ul>
209  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
210  * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li>
211  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
212  * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li>
213  * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li>
214  * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li>
215  * </ul>
216  * @see AccessibilityEvent
217  * @see AccessibilityServiceInfo
218  * @see android.view.accessibility.AccessibilityManager
219  */
220 public abstract class AccessibilityService extends Service {
221 
222     /**
223      * The user has performed a swipe up gesture on the touch screen.
224      */
225     public static final int GESTURE_SWIPE_UP = 1;
226 
227     /**
228      * The user has performed a swipe down gesture on the touch screen.
229      */
230     public static final int GESTURE_SWIPE_DOWN = 2;
231 
232     /**
233      * The user has performed a swipe left gesture on the touch screen.
234      */
235     public static final int GESTURE_SWIPE_LEFT = 3;
236 
237     /**
238      * The user has performed a swipe right gesture on the touch screen.
239      */
240     public static final int GESTURE_SWIPE_RIGHT = 4;
241 
242     /**
243      * The user has performed a swipe left and right gesture on the touch screen.
244      */
245     public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
246 
247     /**
248      * The user has performed a swipe right and left gesture on the touch screen.
249      */
250     public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
251 
252     /**
253      * The user has performed a swipe up and down gesture on the touch screen.
254      */
255     public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
256 
257     /**
258      * The user has performed a swipe down and up gesture on the touch screen.
259      */
260     public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
261 
262     /**
263      * The user has performed a left and up gesture on the touch screen.
264      */
265     public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
266 
267     /**
268      * The user has performed a left and down gesture on the touch screen.
269      */
270     public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
271 
272     /**
273      * The user has performed a right and up gesture on the touch screen.
274      */
275     public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
276 
277     /**
278      * The user has performed a right and down gesture on the touch screen.
279      */
280     public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
281 
282     /**
283      * The user has performed an up and left gesture on the touch screen.
284      */
285     public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
286 
287     /**
288      * The user has performed an up and right gesture on the touch screen.
289      */
290     public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
291 
292     /**
293      * The user has performed an down and left gesture on the touch screen.
294      */
295     public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
296 
297     /**
298      * The user has performed an down and right gesture on the touch screen.
299      */
300     public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
301 
302     /**
303      * The {@link Intent} that must be declared as handled by the service.
304      */
305     public static final String SERVICE_INTERFACE =
306         "android.accessibilityservice.AccessibilityService";
307 
308     /**
309      * Name under which an AccessibilityService component publishes information
310      * about itself. This meta-data must reference an XML resource containing an
311      * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
312      * tag. This is a sample XML file configuring an accessibility service:
313      * <pre> &lt;accessibility-service
314      *     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
315      *     android:packageNames="foo.bar, foo.baz"
316      *     android:accessibilityFeedbackType="feedbackSpoken"
317      *     android:notificationTimeout="100"
318      *     android:accessibilityFlags="flagDefault"
319      *     android:settingsActivity="foo.bar.TestBackActivity"
320      *     android:canRetrieveWindowContent="true"
321      *     android:canRequestTouchExplorationMode="true"
322      *     . . .
323      * /&gt;</pre>
324      */
325     public static final String SERVICE_META_DATA = "android.accessibilityservice";
326 
327     /**
328      * Action to go back.
329      */
330     public static final int GLOBAL_ACTION_BACK = 1;
331 
332     /**
333      * Action to go home.
334      */
335     public static final int GLOBAL_ACTION_HOME = 2;
336 
337     /**
338      * Action to toggle showing the overview of recent apps. Will fail on platforms that don't
339      * show recent apps.
340      */
341     public static final int GLOBAL_ACTION_RECENTS = 3;
342 
343     /**
344      * Action to open the notifications.
345      */
346     public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
347 
348     /**
349      * Action to open the quick settings.
350      */
351     public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5;
352 
353     /**
354      * Action to open the power long-press dialog.
355      */
356     public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
357 
358     /**
359      * Action to toggle docking the current app's window
360      */
361     public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7;
362 
363     /**
364      * Action to lock the screen
365      */
366     public static final int GLOBAL_ACTION_LOCK_SCREEN = 8;
367 
368     /**
369      * Action to take a screenshot
370      */
371     public static final int GLOBAL_ACTION_TAKE_SCREENSHOT = 9;
372 
373     private static final String LOG_TAG = "AccessibilityService";
374 
375     /**
376      * Interface used by IAccessibilityServiceWrapper to call the service from its main thread.
377      * @hide
378      */
379     public interface Callbacks {
onAccessibilityEvent(AccessibilityEvent event)380         void onAccessibilityEvent(AccessibilityEvent event);
onInterrupt()381         void onInterrupt();
onServiceConnected()382         void onServiceConnected();
init(int connectionId, IBinder windowToken)383         void init(int connectionId, IBinder windowToken);
onGesture(int gestureId)384         boolean onGesture(int gestureId);
onKeyEvent(KeyEvent event)385         boolean onKeyEvent(KeyEvent event);
386         /** Magnification changed callbacks for different displays */
onMagnificationChanged(int displayId, @NonNull Region region, float scale, float centerX, float centerY)387         void onMagnificationChanged(int displayId, @NonNull Region region,
388                 float scale, float centerX, float centerY);
onSoftKeyboardShowModeChanged(int showMode)389         void onSoftKeyboardShowModeChanged(int showMode);
onPerformGestureResult(int sequence, boolean completedSuccessfully)390         void onPerformGestureResult(int sequence, boolean completedSuccessfully);
onFingerprintCapturingGesturesChanged(boolean active)391         void onFingerprintCapturingGesturesChanged(boolean active);
onFingerprintGesture(int gesture)392         void onFingerprintGesture(int gesture);
onAccessibilityButtonClicked()393         void onAccessibilityButtonClicked();
onAccessibilityButtonAvailabilityChanged(boolean available)394         void onAccessibilityButtonAvailabilityChanged(boolean available);
395     }
396 
397     /**
398      * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
399      * @hide
400      */
401     @Retention(RetentionPolicy.SOURCE)
402     @IntDef(prefix = { "SHOW_MODE_" }, value = {
403             SHOW_MODE_AUTO,
404             SHOW_MODE_HIDDEN,
405             SHOW_MODE_IGNORE_HARD_KEYBOARD
406     })
407     public @interface SoftKeyboardShowMode {}
408 
409     /**
410      * Allow the system to control when the soft keyboard is shown.
411      * @see SoftKeyboardController
412      */
413     public static final int SHOW_MODE_AUTO = 0;
414 
415     /**
416      * Never show the soft keyboard.
417      * @see SoftKeyboardController
418      */
419     public static final int SHOW_MODE_HIDDEN = 1;
420 
421     /**
422      * Allow the soft keyboard to be shown, even if a hard keyboard is connected
423      * @see SoftKeyboardController
424      */
425     public static final int SHOW_MODE_IGNORE_HARD_KEYBOARD = 2;
426 
427     /**
428      * Mask used to cover the show modes supported in public API
429      * @hide
430      */
431     public static final int SHOW_MODE_MASK = 0x03;
432 
433     /**
434      * Bit used to hold the old value of the hard IME setting to restore when a service is shut
435      * down.
436      * @hide
437      */
438     public static final int SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE = 0x20000000;
439 
440     /**
441      * Bit for show mode setting to indicate that the user has overridden the hard keyboard
442      * behavior.
443      * @hide
444      */
445     public static final int SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN = 0x40000000;
446 
447     private int mConnectionId = AccessibilityInteractionClient.NO_ID;
448 
449     @UnsupportedAppUsage
450     private AccessibilityServiceInfo mInfo;
451 
452     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
453     private IBinder mWindowToken;
454 
455     private WindowManager mWindowManager;
456 
457     /** List of magnification controllers, mapping from displayId -> MagnificationController. */
458     private final SparseArray<MagnificationController> mMagnificationControllers =
459             new SparseArray<>(0);
460     private SoftKeyboardController mSoftKeyboardController;
461     private AccessibilityButtonController mAccessibilityButtonController;
462 
463     private int mGestureStatusCallbackSequence;
464 
465     private SparseArray<GestureResultCallbackInfo> mGestureStatusCallbackInfos;
466 
467     private final Object mLock = new Object();
468 
469     private FingerprintGestureController mFingerprintGestureController;
470 
471     /**
472      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
473      *
474      * @param event The new event. This event is owned by the caller and cannot be used after
475      * this method returns. Services wishing to use the event after this method returns should
476      * make a copy.
477      */
onAccessibilityEvent(AccessibilityEvent event)478     public abstract void onAccessibilityEvent(AccessibilityEvent event);
479 
480     /**
481      * Callback for interrupting the accessibility feedback.
482      */
onInterrupt()483     public abstract void onInterrupt();
484 
485     /**
486      * Dispatches service connection to internal components first, then the
487      * client code.
488      */
dispatchServiceConnected()489     private void dispatchServiceConnected() {
490         synchronized (mLock) {
491             for (int i = 0; i < mMagnificationControllers.size(); i++) {
492                 mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
493             }
494         }
495         if (mSoftKeyboardController != null) {
496             mSoftKeyboardController.onServiceConnected();
497         }
498 
499         // The client gets to handle service connection last, after we've set
500         // up any state upon which their code may rely.
501         onServiceConnected();
502     }
503 
504     /**
505      * This method is a part of the {@link AccessibilityService} lifecycle and is
506      * called after the system has successfully bound to the service. If is
507      * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
508      *
509      * @see AccessibilityServiceInfo
510      * @see #setServiceInfo(AccessibilityServiceInfo)
511      */
onServiceConnected()512     protected void onServiceConnected() {
513 
514     }
515 
516     /**
517      * Called by the system when the user performs a specific gesture on the
518      * touch screen.
519      *
520      * <strong>Note:</strong> To receive gestures an accessibility service must
521      * request that the device is in touch exploration mode by setting the
522      * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
523      * flag.
524      *
525      * @param gestureId The unique id of the performed gesture.
526      *
527      * @return Whether the gesture was handled.
528      *
529      * @see #GESTURE_SWIPE_UP
530      * @see #GESTURE_SWIPE_UP_AND_LEFT
531      * @see #GESTURE_SWIPE_UP_AND_DOWN
532      * @see #GESTURE_SWIPE_UP_AND_RIGHT
533      * @see #GESTURE_SWIPE_DOWN
534      * @see #GESTURE_SWIPE_DOWN_AND_LEFT
535      * @see #GESTURE_SWIPE_DOWN_AND_UP
536      * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
537      * @see #GESTURE_SWIPE_LEFT
538      * @see #GESTURE_SWIPE_LEFT_AND_UP
539      * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
540      * @see #GESTURE_SWIPE_LEFT_AND_DOWN
541      * @see #GESTURE_SWIPE_RIGHT
542      * @see #GESTURE_SWIPE_RIGHT_AND_UP
543      * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
544      * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
545      */
onGesture(int gestureId)546     protected boolean onGesture(int gestureId) {
547         return false;
548     }
549 
550     /**
551      * Callback that allows an accessibility service to observe the key events
552      * before they are passed to the rest of the system. This means that the events
553      * are first delivered here before they are passed to the device policy, the
554      * input method, or applications.
555      * <p>
556      * <strong>Note:</strong> It is important that key events are handled in such
557      * a way that the event stream that would be passed to the rest of the system
558      * is well-formed. For example, handling the down event but not the up event
559      * and vice versa would generate an inconsistent event stream.
560      * </p>
561      * <p>
562      * <strong>Note:</strong> The key events delivered in this method are copies
563      * and modifying them will have no effect on the events that will be passed
564      * to the system. This method is intended to perform purely filtering
565      * functionality.
566      * <p>
567      *
568      * @param event The event to be processed. This event is owned by the caller and cannot be used
569      * after this method returns. Services wishing to use the event after this method returns should
570      * make a copy.
571      * @return If true then the event will be consumed and not delivered to
572      *         applications, otherwise it will be delivered as usual.
573      */
onKeyEvent(KeyEvent event)574     protected boolean onKeyEvent(KeyEvent event) {
575         return false;
576     }
577 
578     /**
579      * Gets the windows on the screen. This method returns only the windows
580      * that a sighted user can interact with, as opposed to all windows.
581      * For example, if there is a modal dialog shown and the user cannot touch
582      * anything behind it, then only the modal window will be reported
583      * (assuming it is the top one). For convenience the returned windows
584      * are ordered in a descending layer order, which is the windows that
585      * are on top are reported first. Since the user can always
586      * interact with the window that has input focus by typing, the focused
587      * window is always returned (even if covered by a modal window).
588      * <p>
589      * <strong>Note:</strong> In order to access the windows your service has
590      * to declare the capability to retrieve window content by setting the
591      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
592      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
593      * Also the service has to opt-in to retrieve the interactive windows by
594      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
595      * flag.
596      * </p>
597      *
598      * @return The windows if there are windows and the service is can retrieve
599      *         them, otherwise an empty list.
600      */
getWindows()601     public List<AccessibilityWindowInfo> getWindows() {
602         return AccessibilityInteractionClient.getInstance().getWindows(mConnectionId);
603     }
604 
605     /**
606      * Gets the root node in the currently active window if this service
607      * can retrieve window content. The active window is the one that the user
608      * is currently touching or the window with input focus, if the user is not
609      * touching any window.
610      * <p>
611      * The currently active window is defined as the window that most recently fired one
612      * of the following events:
613      * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
614      * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
615      * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}.
616      * In other words, the last window shown that also has input focus.
617      * </p>
618      * <p>
619      * <strong>Note:</strong> In order to access the root node your service has
620      * to declare the capability to retrieve window content by setting the
621      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
622      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
623      * </p>
624      *
625      * @return The root node if this service can retrieve window content.
626      */
getRootInActiveWindow()627     public AccessibilityNodeInfo getRootInActiveWindow() {
628         return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
629     }
630 
631     /**
632      * Disables the service. After calling this method, the service will be disabled and settings
633      * will show that it is turned off.
634      */
disableSelf()635     public final void disableSelf() {
636         final IAccessibilityServiceConnection connection =
637                 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
638         if (connection != null) {
639             try {
640                 connection.disableSelf();
641             } catch (RemoteException re) {
642                 throw new RuntimeException(re);
643             }
644         }
645     }
646 
647     /**
648      * Returns the magnification controller, which may be used to query and
649      * modify the state of display magnification.
650      * <p>
651      * <strong>Note:</strong> In order to control magnification, your service
652      * must declare the capability by setting the
653      * {@link android.R.styleable#AccessibilityService_canControlMagnification}
654      * property in its meta-data. For more information, see
655      * {@link #SERVICE_META_DATA}.
656      *
657      * @return the magnification controller
658      */
659     @NonNull
getMagnificationController()660     public final MagnificationController getMagnificationController() {
661         return getMagnificationController(Display.DEFAULT_DISPLAY);
662     }
663 
664     /**
665      * Returns the magnification controller of specified logical display, which may be used to
666      * query and modify the state of display magnification.
667      * <p>
668      * <strong>Note:</strong> In order to control magnification, your service
669      * must declare the capability by setting the
670      * {@link android.R.styleable#AccessibilityService_canControlMagnification}
671      * property in its meta-data. For more information, see
672      * {@link #SERVICE_META_DATA}.
673      *
674      * @param displayId The logic display id, use {@link Display#DEFAULT_DISPLAY} for
675      *                  default display.
676      * @return the magnification controller
677      *
678      * @hide
679      */
680     @NonNull
getMagnificationController(int displayId)681     public final MagnificationController getMagnificationController(int displayId) {
682         synchronized (mLock) {
683             MagnificationController controller = mMagnificationControllers.get(displayId);
684             if (controller == null) {
685                 controller = new MagnificationController(this, mLock, displayId);
686                 mMagnificationControllers.put(displayId, controller);
687             }
688             return controller;
689         }
690     }
691 
692     /**
693      * Get the controller for fingerprint gestures. This feature requires {@link
694      * AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}.
695      *
696      *<strong>Note: </strong> The service must be connected before this method is called.
697      *
698      * @return The controller for fingerprint gestures, or {@code null} if gestures are unavailable.
699      */
700     @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
getFingerprintGestureController()701     public final @NonNull FingerprintGestureController getFingerprintGestureController() {
702         if (mFingerprintGestureController == null) {
703             mFingerprintGestureController = new FingerprintGestureController(
704                     AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
705         }
706         return mFingerprintGestureController;
707     }
708 
709     /**
710      * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
711      * the user, this service, or another service, will be cancelled.
712      * <p>
713      * The gesture will be dispatched as if it were performed directly on the screen by a user, so
714      * the events may be affected by features such as magnification and explore by touch.
715      * </p>
716      * <p>
717      * <strong>Note:</strong> In order to dispatch gestures, your service
718      * must declare the capability by setting the
719      * {@link android.R.styleable#AccessibilityService_canPerformGestures}
720      * property in its meta-data. For more information, see
721      * {@link #SERVICE_META_DATA}.
722      * </p>
723      *
724      * @param gesture The gesture to dispatch
725      * @param callback The object to call back when the status of the gesture is known. If
726      * {@code null}, no status is reported.
727      * @param handler The handler on which to call back the {@code callback} object. If
728      * {@code null}, the object is called back on the service's main thread.
729      *
730      * @return {@code true} if the gesture is dispatched, {@code false} if not.
731      */
dispatchGesture(@onNull GestureDescription gesture, @Nullable GestureResultCallback callback, @Nullable Handler handler)732     public final boolean dispatchGesture(@NonNull GestureDescription gesture,
733             @Nullable GestureResultCallback callback,
734             @Nullable Handler handler) {
735         final IAccessibilityServiceConnection connection =
736                 AccessibilityInteractionClient.getInstance().getConnection(
737                         mConnectionId);
738         if (connection == null) {
739             return false;
740         }
741         List<GestureDescription.GestureStep> steps =
742                 MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
743         try {
744             synchronized (mLock) {
745                 mGestureStatusCallbackSequence++;
746                 if (callback != null) {
747                     if (mGestureStatusCallbackInfos == null) {
748                         mGestureStatusCallbackInfos = new SparseArray<>();
749                     }
750                     GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture,
751                             callback, handler);
752                     mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
753                 }
754                 connection.sendGesture(mGestureStatusCallbackSequence,
755                         new ParceledListSlice<>(steps));
756             }
757         } catch (RemoteException re) {
758             throw new RuntimeException(re);
759         }
760         return true;
761     }
762 
onPerformGestureResult(int sequence, final boolean completedSuccessfully)763     void onPerformGestureResult(int sequence, final boolean completedSuccessfully) {
764         if (mGestureStatusCallbackInfos == null) {
765             return;
766         }
767         GestureResultCallbackInfo callbackInfo;
768         synchronized (mLock) {
769             callbackInfo = mGestureStatusCallbackInfos.get(sequence);
770         }
771         final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
772         if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
773                 && (callbackInfo.callback != null)) {
774             if (callbackInfo.handler != null) {
775                 callbackInfo.handler.post(new Runnable() {
776                     @Override
777                     public void run() {
778                         if (completedSuccessfully) {
779                             finalCallbackInfo.callback
780                                     .onCompleted(finalCallbackInfo.gestureDescription);
781                         } else {
782                             finalCallbackInfo.callback
783                                     .onCancelled(finalCallbackInfo.gestureDescription);
784                         }
785                     }
786                 });
787                 return;
788             }
789             if (completedSuccessfully) {
790                 callbackInfo.callback.onCompleted(callbackInfo.gestureDescription);
791             } else {
792                 callbackInfo.callback.onCancelled(callbackInfo.gestureDescription);
793             }
794         }
795     }
796 
onMagnificationChanged(int displayId, @NonNull Region region, float scale, float centerX, float centerY)797     private void onMagnificationChanged(int displayId, @NonNull Region region, float scale,
798             float centerX, float centerY) {
799         MagnificationController controller;
800         synchronized (mLock) {
801             controller = mMagnificationControllers.get(displayId);
802         }
803         if (controller != null) {
804             controller.dispatchMagnificationChanged(region, scale, centerX, centerY);
805         }
806     }
807 
808     /**
809      * Callback for fingerprint gesture handling
810      * @param active If gesture detection is active
811      */
onFingerprintCapturingGesturesChanged(boolean active)812     private void onFingerprintCapturingGesturesChanged(boolean active) {
813         getFingerprintGestureController().onGestureDetectionActiveChanged(active);
814     }
815 
816     /**
817      * Callback for fingerprint gesture handling
818      * @param gesture The identifier for the gesture performed
819      */
onFingerprintGesture(int gesture)820     private void onFingerprintGesture(int gesture) {
821         getFingerprintGestureController().onGesture(gesture);
822     }
823 
824     /**
825      * Used to control and query the state of display magnification.
826      */
827     public static final class MagnificationController {
828         private final AccessibilityService mService;
829         private final int mDisplayId;
830 
831         /**
832          * Map of listeners to their handlers. Lazily created when adding the
833          * first magnification listener.
834          */
835         private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
836         private final Object mLock;
837 
MagnificationController(@onNull AccessibilityService service, @NonNull Object lock, int displayId)838         MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock,
839                 int displayId) {
840             mService = service;
841             mLock = lock;
842             mDisplayId = displayId;
843         }
844 
845         /**
846          * Called when the service is connected.
847          */
onServiceConnectedLocked()848         void onServiceConnectedLocked() {
849             if (mListeners != null && !mListeners.isEmpty()) {
850                 setMagnificationCallbackEnabled(true);
851             }
852         }
853 
854         /**
855          * Adds the specified change listener to the list of magnification
856          * change listeners. The callback will occur on the service's main
857          * thread.
858          *
859          * @param listener the listener to add, must be non-{@code null}
860          */
addListener(@onNull OnMagnificationChangedListener listener)861         public void addListener(@NonNull OnMagnificationChangedListener listener) {
862             addListener(listener, null);
863         }
864 
865         /**
866          * Adds the specified change listener to the list of magnification
867          * change listeners. The callback will occur on the specified
868          * {@link Handler}'s thread, or on the service's main thread if the
869          * handler is {@code null}.
870          *
871          * @param listener the listener to add, must be non-null
872          * @param handler the handler on which the callback should execute, or
873          *        {@code null} to execute on the service's main thread
874          */
addListener(@onNull OnMagnificationChangedListener listener, @Nullable Handler handler)875         public void addListener(@NonNull OnMagnificationChangedListener listener,
876                 @Nullable Handler handler) {
877             synchronized (mLock) {
878                 if (mListeners == null) {
879                     mListeners = new ArrayMap<>();
880                 }
881 
882                 final boolean shouldEnableCallback = mListeners.isEmpty();
883                 mListeners.put(listener, handler);
884 
885                 if (shouldEnableCallback) {
886                     // This may fail if the service is not connected yet, but if we
887                     // still have listeners when it connects then we can try again.
888                     setMagnificationCallbackEnabled(true);
889                 }
890             }
891         }
892 
893         /**
894          * Removes the specified change listener from the list of magnification change listeners.
895          *
896          * @param listener the listener to remove, must be non-null
897          * @return {@code true} if the listener was removed, {@code false} otherwise
898          */
removeListener(@onNull OnMagnificationChangedListener listener)899         public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
900             if (mListeners == null) {
901                 return false;
902             }
903 
904             synchronized (mLock) {
905                 final int keyIndex = mListeners.indexOfKey(listener);
906                 final boolean hasKey = keyIndex >= 0;
907                 if (hasKey) {
908                     mListeners.removeAt(keyIndex);
909                 }
910 
911                 if (hasKey && mListeners.isEmpty()) {
912                     // We just removed the last listener, so we don't need
913                     // callbacks from the service anymore.
914                     setMagnificationCallbackEnabled(false);
915                 }
916 
917                 return hasKey;
918             }
919         }
920 
setMagnificationCallbackEnabled(boolean enabled)921         private void setMagnificationCallbackEnabled(boolean enabled) {
922             final IAccessibilityServiceConnection connection =
923                     AccessibilityInteractionClient.getInstance().getConnection(
924                             mService.mConnectionId);
925             if (connection != null) {
926                 try {
927                     connection.setMagnificationCallbackEnabled(mDisplayId, enabled);
928                 } catch (RemoteException re) {
929                     throw new RuntimeException(re);
930                 }
931             }
932         }
933 
934         /**
935          * Dispatches magnification changes to any registered listeners. This
936          * should be called on the service's main thread.
937          */
dispatchMagnificationChanged(final @NonNull Region region, final float scale, final float centerX, final float centerY)938         void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
939                 final float centerX, final float centerY) {
940             final ArrayMap<OnMagnificationChangedListener, Handler> entries;
941             synchronized (mLock) {
942                 if (mListeners == null || mListeners.isEmpty()) {
943                     Slog.d(LOG_TAG, "Received magnification changed "
944                             + "callback with no listeners registered!");
945                     setMagnificationCallbackEnabled(false);
946                     return;
947                 }
948 
949                 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
950                 // modification.
951                 entries = new ArrayMap<>(mListeners);
952             }
953 
954             for (int i = 0, count = entries.size(); i < count; i++) {
955                 final OnMagnificationChangedListener listener = entries.keyAt(i);
956                 final Handler handler = entries.valueAt(i);
957                 if (handler != null) {
958                     handler.post(new Runnable() {
959                         @Override
960                         public void run() {
961                             listener.onMagnificationChanged(MagnificationController.this,
962                                     region, scale, centerX, centerY);
963                         }
964                     });
965                 } else {
966                     // We're already on the main thread, just run the listener.
967                     listener.onMagnificationChanged(this, region, scale, centerX, centerY);
968                 }
969             }
970         }
971 
972         /**
973          * Returns the current magnification scale.
974          * <p>
975          * <strong>Note:</strong> If the service is not yet connected (e.g.
976          * {@link AccessibilityService#onServiceConnected()} has not yet been
977          * called) or the service has been disconnected, this method will
978          * return a default value of {@code 1.0f}.
979          *
980          * @return the current magnification scale
981          */
getScale()982         public float getScale() {
983             final IAccessibilityServiceConnection connection =
984                     AccessibilityInteractionClient.getInstance().getConnection(
985                             mService.mConnectionId);
986             if (connection != null) {
987                 try {
988                     return connection.getMagnificationScale(mDisplayId);
989                 } catch (RemoteException re) {
990                     Log.w(LOG_TAG, "Failed to obtain scale", re);
991                     re.rethrowFromSystemServer();
992                 }
993             }
994             return 1.0f;
995         }
996 
997         /**
998          * Returns the unscaled screen-relative X coordinate of the focal
999          * center of the magnified region. This is the point around which
1000          * zooming occurs and is guaranteed to lie within the magnified
1001          * region.
1002          * <p>
1003          * <strong>Note:</strong> If the service is not yet connected (e.g.
1004          * {@link AccessibilityService#onServiceConnected()} has not yet been
1005          * called) or the service has been disconnected, this method will
1006          * return a default value of {@code 0.0f}.
1007          *
1008          * @return the unscaled screen-relative X coordinate of the center of
1009          *         the magnified region
1010          */
getCenterX()1011         public float getCenterX() {
1012             final IAccessibilityServiceConnection connection =
1013                     AccessibilityInteractionClient.getInstance().getConnection(
1014                             mService.mConnectionId);
1015             if (connection != null) {
1016                 try {
1017                     return connection.getMagnificationCenterX(mDisplayId);
1018                 } catch (RemoteException re) {
1019                     Log.w(LOG_TAG, "Failed to obtain center X", re);
1020                     re.rethrowFromSystemServer();
1021                 }
1022             }
1023             return 0.0f;
1024         }
1025 
1026         /**
1027          * Returns the unscaled screen-relative Y coordinate of the focal
1028          * center of the magnified region. This is the point around which
1029          * zooming occurs and is guaranteed to lie within the magnified
1030          * region.
1031          * <p>
1032          * <strong>Note:</strong> If the service is not yet connected (e.g.
1033          * {@link AccessibilityService#onServiceConnected()} has not yet been
1034          * called) or the service has been disconnected, this method will
1035          * return a default value of {@code 0.0f}.
1036          *
1037          * @return the unscaled screen-relative Y coordinate of the center of
1038          *         the magnified region
1039          */
getCenterY()1040         public float getCenterY() {
1041             final IAccessibilityServiceConnection connection =
1042                     AccessibilityInteractionClient.getInstance().getConnection(
1043                             mService.mConnectionId);
1044             if (connection != null) {
1045                 try {
1046                     return connection.getMagnificationCenterY(mDisplayId);
1047                 } catch (RemoteException re) {
1048                     Log.w(LOG_TAG, "Failed to obtain center Y", re);
1049                     re.rethrowFromSystemServer();
1050                 }
1051             }
1052             return 0.0f;
1053         }
1054 
1055         /**
1056          * Returns the region of the screen currently active for magnification. Changes to
1057          * magnification scale and center only affect this portion of the screen. The rest of the
1058          * screen, for example input methods, cannot be magnified. This region is relative to the
1059          * unscaled screen and is independent of the scale and center point.
1060          * <p>
1061          * The returned region will be empty if magnification is not active. Magnification is active
1062          * if magnification gestures are enabled or if a service is running that can control
1063          * magnification.
1064          * <p>
1065          * <strong>Note:</strong> If the service is not yet connected (e.g.
1066          * {@link AccessibilityService#onServiceConnected()} has not yet been
1067          * called) or the service has been disconnected, this method will
1068          * return an empty region.
1069          *
1070          * @return the region of the screen currently active for magnification, or an empty region
1071          * if magnification is not active.
1072          */
1073         @NonNull
getMagnificationRegion()1074         public Region getMagnificationRegion() {
1075             final IAccessibilityServiceConnection connection =
1076                     AccessibilityInteractionClient.getInstance().getConnection(
1077                             mService.mConnectionId);
1078             if (connection != null) {
1079                 try {
1080                     return connection.getMagnificationRegion(mDisplayId);
1081                 } catch (RemoteException re) {
1082                     Log.w(LOG_TAG, "Failed to obtain magnified region", re);
1083                     re.rethrowFromSystemServer();
1084                 }
1085             }
1086             return Region.obtain();
1087         }
1088 
1089         /**
1090          * Resets magnification scale and center to their default (e.g. no
1091          * magnification) values.
1092          * <p>
1093          * <strong>Note:</strong> If the service is not yet connected (e.g.
1094          * {@link AccessibilityService#onServiceConnected()} has not yet been
1095          * called) or the service has been disconnected, this method will have
1096          * no effect and return {@code false}.
1097          *
1098          * @param animate {@code true} to animate from the current scale and
1099          *                center or {@code false} to reset the scale and center
1100          *                immediately
1101          * @return {@code true} on success, {@code false} on failure
1102          */
reset(boolean animate)1103         public boolean reset(boolean animate) {
1104             final IAccessibilityServiceConnection connection =
1105                     AccessibilityInteractionClient.getInstance().getConnection(
1106                             mService.mConnectionId);
1107             if (connection != null) {
1108                 try {
1109                     return connection.resetMagnification(mDisplayId, animate);
1110                 } catch (RemoteException re) {
1111                     Log.w(LOG_TAG, "Failed to reset", re);
1112                     re.rethrowFromSystemServer();
1113                 }
1114             }
1115             return false;
1116         }
1117 
1118         /**
1119          * Sets the magnification scale.
1120          * <p>
1121          * <strong>Note:</strong> If the service is not yet connected (e.g.
1122          * {@link AccessibilityService#onServiceConnected()} has not yet been
1123          * called) or the service has been disconnected, this method will have
1124          * no effect and return {@code false}.
1125          *
1126          * @param scale the magnification scale to set, must be >= 1 and <= 8
1127          * @param animate {@code true} to animate from the current scale or
1128          *                {@code false} to set the scale immediately
1129          * @return {@code true} on success, {@code false} on failure
1130          */
setScale(float scale, boolean animate)1131         public boolean setScale(float scale, boolean animate) {
1132             final IAccessibilityServiceConnection connection =
1133                     AccessibilityInteractionClient.getInstance().getConnection(
1134                             mService.mConnectionId);
1135             if (connection != null) {
1136                 try {
1137                     return connection.setMagnificationScaleAndCenter(mDisplayId,
1138                             scale, Float.NaN, Float.NaN, animate);
1139                 } catch (RemoteException re) {
1140                     Log.w(LOG_TAG, "Failed to set scale", re);
1141                     re.rethrowFromSystemServer();
1142                 }
1143             }
1144             return false;
1145         }
1146 
1147         /**
1148          * Sets the center of the magnified viewport.
1149          * <p>
1150          * <strong>Note:</strong> If the service is not yet connected (e.g.
1151          * {@link AccessibilityService#onServiceConnected()} has not yet been
1152          * called) or the service has been disconnected, this method will have
1153          * no effect and return {@code false}.
1154          *
1155          * @param centerX the unscaled screen-relative X coordinate on which to
1156          *                center the viewport
1157          * @param centerY the unscaled screen-relative Y coordinate on which to
1158          *                center the viewport
1159          * @param animate {@code true} to animate from the current viewport
1160          *                center or {@code false} to set the center immediately
1161          * @return {@code true} on success, {@code false} on failure
1162          */
setCenter(float centerX, float centerY, boolean animate)1163         public boolean setCenter(float centerX, float centerY, boolean animate) {
1164             final IAccessibilityServiceConnection connection =
1165                     AccessibilityInteractionClient.getInstance().getConnection(
1166                             mService.mConnectionId);
1167             if (connection != null) {
1168                 try {
1169                     return connection.setMagnificationScaleAndCenter(mDisplayId,
1170                             Float.NaN, centerX, centerY, animate);
1171                 } catch (RemoteException re) {
1172                     Log.w(LOG_TAG, "Failed to set center", re);
1173                     re.rethrowFromSystemServer();
1174                 }
1175             }
1176             return false;
1177         }
1178 
1179         /**
1180          * Listener for changes in the state of magnification.
1181          */
1182         public interface OnMagnificationChangedListener {
1183             /**
1184              * Called when the magnified region, scale, or center changes.
1185              *
1186              * @param controller the magnification controller
1187              * @param region the magnification region
1188              * @param scale the new scale
1189              * @param centerX the new X coordinate, in unscaled coordinates, around which
1190              * magnification is focused
1191              * @param centerY the new Y coordinate, in unscaled coordinates, around which
1192              * magnification is focused
1193              */
onMagnificationChanged(@onNull MagnificationController controller, @NonNull Region region, float scale, float centerX, float centerY)1194             void onMagnificationChanged(@NonNull MagnificationController controller,
1195                     @NonNull Region region, float scale, float centerX, float centerY);
1196         }
1197     }
1198 
1199     /**
1200      * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
1201      * show mode.
1202      *
1203      * @return the soft keyboard controller
1204      */
1205     @NonNull
getSoftKeyboardController()1206     public final SoftKeyboardController getSoftKeyboardController() {
1207         synchronized (mLock) {
1208             if (mSoftKeyboardController == null) {
1209                 mSoftKeyboardController = new SoftKeyboardController(this, mLock);
1210             }
1211             return mSoftKeyboardController;
1212         }
1213     }
1214 
onSoftKeyboardShowModeChanged(int showMode)1215     private void onSoftKeyboardShowModeChanged(int showMode) {
1216         if (mSoftKeyboardController != null) {
1217             mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
1218         }
1219     }
1220 
1221     /**
1222      * Used to control, query, and listen for changes to the soft keyboard show mode.
1223      * <p>
1224      * Accessibility services may request to override the decisions normally made about whether or
1225      * not the soft keyboard is shown.
1226      * <p>
1227      * If multiple services make conflicting requests, the last request is honored. A service may
1228      * register a listener to find out if the mode has changed under it.
1229      * <p>
1230      * If the user takes action to override the behavior behavior requested by an accessibility
1231      * service, the user's request takes precendence, the show mode will be reset to
1232      * {@link AccessibilityService#SHOW_MODE_AUTO}, and services will no longer be able to control
1233      * that aspect of the soft keyboard's behavior.
1234      * <p>
1235      * Note: Because soft keyboards are independent apps, the framework does not have total control
1236      * over their behavior. They may choose to show themselves, or not, without regard to requests
1237      * made here. So the framework will make a best effort to deliver the behavior requested, but
1238      * cannot guarantee success.
1239      *
1240      * @see AccessibilityService#SHOW_MODE_AUTO
1241      * @see AccessibilityService#SHOW_MODE_HIDDEN
1242      * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
1243      */
1244     public static final class SoftKeyboardController {
1245         private final AccessibilityService mService;
1246 
1247         /**
1248          * Map of listeners to their handlers. Lazily created when adding the first
1249          * soft keyboard change listener.
1250          */
1251         private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
1252         private final Object mLock;
1253 
SoftKeyboardController(@onNull AccessibilityService service, @NonNull Object lock)1254         SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
1255             mService = service;
1256             mLock = lock;
1257         }
1258 
1259         /**
1260          * Called when the service is connected.
1261          */
onServiceConnected()1262         void onServiceConnected() {
1263             synchronized(mLock) {
1264                 if (mListeners != null && !mListeners.isEmpty()) {
1265                     setSoftKeyboardCallbackEnabled(true);
1266                 }
1267             }
1268         }
1269 
1270         /**
1271          * Adds the specified change listener to the list of show mode change listeners. The
1272          * callback will occur on the service's main thread. Listener is not called on registration.
1273          */
addOnShowModeChangedListener(@onNull OnShowModeChangedListener listener)1274         public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
1275             addOnShowModeChangedListener(listener, null);
1276         }
1277 
1278         /**
1279          * Adds the specified change listener to the list of soft keyboard show mode change
1280          * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
1281          * services's main thread if the handler is {@code null}.
1282          *
1283          * @param listener the listener to add, must be non-null
1284          * @param handler the handler on which to callback should execute, or {@code null} to
1285          *        execute on the service's main thread
1286          */
addOnShowModeChangedListener(@onNull OnShowModeChangedListener listener, @Nullable Handler handler)1287         public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
1288                 @Nullable Handler handler) {
1289             synchronized (mLock) {
1290                 if (mListeners == null) {
1291                     mListeners = new ArrayMap<>();
1292                 }
1293 
1294                 final boolean shouldEnableCallback = mListeners.isEmpty();
1295                 mListeners.put(listener, handler);
1296 
1297                 if (shouldEnableCallback) {
1298                     // This may fail if the service is not connected yet, but if we still have
1299                     // listeners when it connects, we can try again.
1300                     setSoftKeyboardCallbackEnabled(true);
1301                 }
1302             }
1303         }
1304 
1305         /**
1306          * Removes the specified change listener from the list of keyboard show mode change
1307          * listeners.
1308          *
1309          * @param listener the listener to remove, must be non-null
1310          * @return {@code true} if the listener was removed, {@code false} otherwise
1311          */
removeOnShowModeChangedListener( @onNull OnShowModeChangedListener listener)1312         public boolean removeOnShowModeChangedListener(
1313                 @NonNull OnShowModeChangedListener listener) {
1314             if (mListeners == null) {
1315                 return false;
1316             }
1317 
1318             synchronized (mLock) {
1319                 final int keyIndex = mListeners.indexOfKey(listener);
1320                 final boolean hasKey = keyIndex >= 0;
1321                 if (hasKey) {
1322                     mListeners.removeAt(keyIndex);
1323                 }
1324 
1325                 if (hasKey && mListeners.isEmpty()) {
1326                     // We just removed the last listener, so we don't need callbacks from the
1327                     // service anymore.
1328                     setSoftKeyboardCallbackEnabled(false);
1329                 }
1330 
1331                 return hasKey;
1332             }
1333         }
1334 
setSoftKeyboardCallbackEnabled(boolean enabled)1335         private void setSoftKeyboardCallbackEnabled(boolean enabled) {
1336             final IAccessibilityServiceConnection connection =
1337                     AccessibilityInteractionClient.getInstance().getConnection(
1338                             mService.mConnectionId);
1339             if (connection != null) {
1340                 try {
1341                     connection.setSoftKeyboardCallbackEnabled(enabled);
1342                 } catch (RemoteException re) {
1343                     throw new RuntimeException(re);
1344                 }
1345             }
1346         }
1347 
1348         /**
1349          * Dispatches the soft keyboard show mode change to any registered listeners. This should
1350          * be called on the service's main thread.
1351          */
dispatchSoftKeyboardShowModeChanged(final int showMode)1352         void dispatchSoftKeyboardShowModeChanged(final int showMode) {
1353             final ArrayMap<OnShowModeChangedListener, Handler> entries;
1354             synchronized (mLock) {
1355                 if (mListeners == null || mListeners.isEmpty()) {
1356                     Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
1357                             + " with no listeners registered!");
1358                     setSoftKeyboardCallbackEnabled(false);
1359                     return;
1360                 }
1361 
1362                 // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
1363                 // modification.
1364                 entries = new ArrayMap<>(mListeners);
1365             }
1366 
1367             for (int i = 0, count = entries.size(); i < count; i++) {
1368                 final OnShowModeChangedListener listener = entries.keyAt(i);
1369                 final Handler handler = entries.valueAt(i);
1370                 if (handler != null) {
1371                     handler.post(new Runnable() {
1372                         @Override
1373                         public void run() {
1374                             listener.onShowModeChanged(SoftKeyboardController.this, showMode);
1375                         }
1376                     });
1377                 } else {
1378                     // We're already on the main thread, just run the listener.
1379                     listener.onShowModeChanged(this, showMode);
1380                 }
1381             }
1382         }
1383 
1384         /**
1385          * Returns the show mode of the soft keyboard.
1386          *
1387          * @return the current soft keyboard show mode
1388          *
1389          * @see AccessibilityService#SHOW_MODE_AUTO
1390          * @see AccessibilityService#SHOW_MODE_HIDDEN
1391          * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
1392          */
1393         @SoftKeyboardShowMode
getShowMode()1394         public int getShowMode() {
1395             final IAccessibilityServiceConnection connection =
1396                     AccessibilityInteractionClient.getInstance().getConnection(
1397                             mService.mConnectionId);
1398             if (connection != null) {
1399                 try {
1400                     return connection.getSoftKeyboardShowMode();
1401                 } catch (RemoteException re) {
1402                     Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
1403                     re.rethrowFromSystemServer();
1404                 }
1405             }
1406             return SHOW_MODE_AUTO;
1407         }
1408 
1409         /**
1410          * Sets the soft keyboard show mode.
1411          * <p>
1412          * <strong>Note:</strong> If the service is not yet connected (e.g.
1413          * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
1414          * service has been disconnected, this method will have no effect and return {@code false}.
1415          *
1416          * @param showMode the new show mode for the soft keyboard
1417          * @return {@code true} on success
1418          *
1419          * @see AccessibilityService#SHOW_MODE_AUTO
1420          * @see AccessibilityService#SHOW_MODE_HIDDEN
1421          * @see AccessibilityService#SHOW_MODE_IGNORE_HARD_KEYBOARD
1422          */
setShowMode(@oftKeyboardShowMode int showMode)1423         public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
1424            final IAccessibilityServiceConnection connection =
1425                    AccessibilityInteractionClient.getInstance().getConnection(
1426                            mService.mConnectionId);
1427            if (connection != null) {
1428                try {
1429                    return connection.setSoftKeyboardShowMode(showMode);
1430                } catch (RemoteException re) {
1431                    Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
1432                    re.rethrowFromSystemServer();
1433                }
1434            }
1435            return false;
1436         }
1437 
1438         /**
1439          * Listener for changes in the soft keyboard show mode.
1440          */
1441         public interface OnShowModeChangedListener {
1442            /**
1443             * Called when the soft keyboard behavior changes. The default show mode is
1444             * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1445             * focused. An AccessibilityService can also request the show mode
1446             * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
1447             *
1448             * @param controller the soft keyboard controller
1449             * @param showMode the current soft keyboard show mode
1450             */
onShowModeChanged(@onNull SoftKeyboardController controller, @SoftKeyboardShowMode int showMode)1451             void onShowModeChanged(@NonNull SoftKeyboardController controller,
1452                     @SoftKeyboardShowMode int showMode);
1453         }
1454     }
1455 
1456     /**
1457      * Returns the controller for the accessibility button within the system's navigation area.
1458      * This instance may be used to query the accessibility button's state and register listeners
1459      * for interactions with and state changes for the accessibility button when
1460      * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
1461      * <p>
1462      * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
1463      * within a navigation area, and as such, use of this class should be considered only as an
1464      * optional feature or shortcut on supported device implementations.
1465      * </p>
1466      *
1467      * @return the accessibility button controller for this {@link AccessibilityService}
1468      */
1469     @NonNull
getAccessibilityButtonController()1470     public final AccessibilityButtonController getAccessibilityButtonController() {
1471         synchronized (mLock) {
1472             if (mAccessibilityButtonController == null) {
1473                 mAccessibilityButtonController = new AccessibilityButtonController(
1474                         AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
1475             }
1476             return mAccessibilityButtonController;
1477         }
1478     }
1479 
onAccessibilityButtonClicked()1480     private void onAccessibilityButtonClicked() {
1481         getAccessibilityButtonController().dispatchAccessibilityButtonClicked();
1482     }
1483 
onAccessibilityButtonAvailabilityChanged(boolean available)1484     private void onAccessibilityButtonAvailabilityChanged(boolean available) {
1485         getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged(
1486                 available);
1487     }
1488 
1489     /**
1490      * Performs a global action. Such an action can be performed
1491      * at any moment regardless of the current application or user
1492      * location in that application. For example going back, going
1493      * home, opening recents, etc.
1494      *
1495      * @param action The action to perform.
1496      * @return Whether the action was successfully performed.
1497      *
1498      * @see #GLOBAL_ACTION_BACK
1499      * @see #GLOBAL_ACTION_HOME
1500      * @see #GLOBAL_ACTION_NOTIFICATIONS
1501      * @see #GLOBAL_ACTION_RECENTS
1502      */
performGlobalAction(int action)1503     public final boolean performGlobalAction(int action) {
1504         IAccessibilityServiceConnection connection =
1505             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1506         if (connection != null) {
1507             try {
1508                 return connection.performGlobalAction(action);
1509             } catch (RemoteException re) {
1510                 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
1511                 re.rethrowFromSystemServer();
1512             }
1513         }
1514         return false;
1515     }
1516 
1517     /**
1518      * Find the view that has the specified focus type. The search is performed
1519      * across all windows.
1520      * <p>
1521      * <strong>Note:</strong> In order to access the windows your service has
1522      * to declare the capability to retrieve window content by setting the
1523      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
1524      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
1525      * Also the service has to opt-in to retrieve the interactive windows by
1526      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
1527      * flag. Otherwise, the search will be performed only in the active window.
1528      * </p>
1529      *
1530      * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
1531      *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
1532      * @return The node info of the focused view or null.
1533      *
1534      * @see AccessibilityNodeInfo#FOCUS_INPUT
1535      * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
1536      */
findFocus(int focus)1537     public AccessibilityNodeInfo findFocus(int focus) {
1538         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
1539                 AccessibilityWindowInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
1540     }
1541 
1542     /**
1543      * Gets the an {@link AccessibilityServiceInfo} describing this
1544      * {@link AccessibilityService}. This method is useful if one wants
1545      * to change some of the dynamically configurable properties at
1546      * runtime.
1547      *
1548      * @return The accessibility service info.
1549      *
1550      * @see AccessibilityServiceInfo
1551      */
getServiceInfo()1552     public final AccessibilityServiceInfo getServiceInfo() {
1553         IAccessibilityServiceConnection connection =
1554             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1555         if (connection != null) {
1556             try {
1557                 return connection.getServiceInfo();
1558             } catch (RemoteException re) {
1559                 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
1560                 re.rethrowFromSystemServer();
1561             }
1562         }
1563         return null;
1564     }
1565 
1566     /**
1567      * Sets the {@link AccessibilityServiceInfo} that describes this service.
1568      * <p>
1569      * Note: You can call this method any time but the info will be picked up after
1570      *       the system has bound to this service and when this method is called thereafter.
1571      *
1572      * @param info The info.
1573      */
setServiceInfo(AccessibilityServiceInfo info)1574     public final void setServiceInfo(AccessibilityServiceInfo info) {
1575         mInfo = info;
1576         sendServiceInfo();
1577     }
1578 
1579     /**
1580      * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
1581      * properly set and there is an {@link IAccessibilityServiceConnection} to the
1582      * AccessibilityManagerService.
1583      */
sendServiceInfo()1584     private void sendServiceInfo() {
1585         IAccessibilityServiceConnection connection =
1586             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1587         if (mInfo != null && connection != null) {
1588             try {
1589                 connection.setServiceInfo(mInfo);
1590                 mInfo = null;
1591                 AccessibilityInteractionClient.getInstance().clearCache();
1592             } catch (RemoteException re) {
1593                 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
1594                 re.rethrowFromSystemServer();
1595             }
1596         }
1597     }
1598 
1599     @Override
getSystemService(@erviceName @onNull String name)1600     public Object getSystemService(@ServiceName @NonNull String name) {
1601         if (getBaseContext() == null) {
1602             throw new IllegalStateException(
1603                     "System services not available to Activities before onCreate()");
1604         }
1605 
1606         // Guarantee that we always return the same window manager instance.
1607         if (WINDOW_SERVICE.equals(name)) {
1608             if (mWindowManager == null) {
1609                 mWindowManager = (WindowManager) getBaseContext().getSystemService(name);
1610             }
1611             return mWindowManager;
1612         }
1613         return super.getSystemService(name);
1614     }
1615 
1616     /**
1617      * Implement to return the implementation of the internal accessibility
1618      * service interface.
1619      */
1620     @Override
onBind(Intent intent)1621     public final IBinder onBind(Intent intent) {
1622         return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
1623             @Override
1624             public void onServiceConnected() {
1625                 AccessibilityService.this.dispatchServiceConnected();
1626             }
1627 
1628             @Override
1629             public void onInterrupt() {
1630                 AccessibilityService.this.onInterrupt();
1631             }
1632 
1633             @Override
1634             public void onAccessibilityEvent(AccessibilityEvent event) {
1635                 AccessibilityService.this.onAccessibilityEvent(event);
1636             }
1637 
1638             @Override
1639             public void init(int connectionId, IBinder windowToken) {
1640                 mConnectionId = connectionId;
1641                 mWindowToken = windowToken;
1642 
1643                 // The client may have already obtained the window manager, so
1644                 // update the default token on whatever manager we gave them.
1645                 final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
1646                 wm.setDefaultToken(windowToken);
1647             }
1648 
1649             @Override
1650             public boolean onGesture(int gestureId) {
1651                 return AccessibilityService.this.onGesture(gestureId);
1652             }
1653 
1654             @Override
1655             public boolean onKeyEvent(KeyEvent event) {
1656                 return AccessibilityService.this.onKeyEvent(event);
1657             }
1658 
1659             @Override
1660             public void onMagnificationChanged(int displayId, @NonNull Region region,
1661                     float scale, float centerX, float centerY) {
1662                 AccessibilityService.this.onMagnificationChanged(displayId, region, scale,
1663                         centerX, centerY);
1664             }
1665 
1666             @Override
1667             public void onSoftKeyboardShowModeChanged(int showMode) {
1668                 AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
1669             }
1670 
1671             @Override
1672             public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
1673                 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
1674             }
1675 
1676             @Override
1677             public void onFingerprintCapturingGesturesChanged(boolean active) {
1678                 AccessibilityService.this.onFingerprintCapturingGesturesChanged(active);
1679             }
1680 
1681             @Override
1682             public void onFingerprintGesture(int gesture) {
1683                 AccessibilityService.this.onFingerprintGesture(gesture);
1684             }
1685 
1686             @Override
1687             public void onAccessibilityButtonClicked() {
1688                 AccessibilityService.this.onAccessibilityButtonClicked();
1689             }
1690 
1691             @Override
1692             public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1693                 AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
1694             }
1695         });
1696     }
1697 
1698     /**
1699      * Implements the internal {@link IAccessibilityServiceClient} interface to convert
1700      * incoming calls to it back to calls on an {@link AccessibilityService}.
1701      *
1702      * @hide
1703      */
1704     public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
1705             implements HandlerCaller.Callback {
1706         private static final int DO_INIT = 1;
1707         private static final int DO_ON_INTERRUPT = 2;
1708         private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
1709         private static final int DO_ON_GESTURE = 4;
1710         private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
1711         private static final int DO_ON_KEY_EVENT = 6;
1712         private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
1713         private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
1714         private static final int DO_GESTURE_COMPLETE = 9;
1715         private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
1716         private static final int DO_ON_FINGERPRINT_GESTURE = 11;
1717         private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
1718         private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
1719 
1720         private final HandlerCaller mCaller;
1721 
1722         private final Callbacks mCallback;
1723 
1724         private int mConnectionId = AccessibilityInteractionClient.NO_ID;
1725 
1726         public IAccessibilityServiceClientWrapper(Context context, Looper looper,
1727                 Callbacks callback) {
1728             mCallback = callback;
1729             mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
1730         }
1731 
1732         public void init(IAccessibilityServiceConnection connection, int connectionId,
1733                 IBinder windowToken) {
1734             Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
1735                     connection, windowToken);
1736             mCaller.sendMessage(message);
1737         }
1738 
1739         public void onInterrupt() {
1740             Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
1741             mCaller.sendMessage(message);
1742         }
1743 
1744         public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) {
1745             Message message = mCaller.obtainMessageBO(
1746                     DO_ON_ACCESSIBILITY_EVENT, serviceWantsEvent, event);
1747             mCaller.sendMessage(message);
1748         }
1749 
1750         public void onGesture(int gestureId) {
1751             Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
1752             mCaller.sendMessage(message);
1753         }
1754 
1755         public void clearAccessibilityCache() {
1756             Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
1757             mCaller.sendMessage(message);
1758         }
1759 
1760         @Override
1761         public void onKeyEvent(KeyEvent event, int sequence) {
1762             Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
1763             mCaller.sendMessage(message);
1764         }
1765 
1766         /** Magnification changed callbacks for different displays */
1767         public void onMagnificationChanged(int displayId, @NonNull Region region,
1768                 float scale, float centerX, float centerY) {
1769             final SomeArgs args = SomeArgs.obtain();
1770             args.arg1 = region;
1771             args.arg2 = scale;
1772             args.arg3 = centerX;
1773             args.arg4 = centerY;
1774             args.argi1 = displayId;
1775 
1776             final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args);
1777             mCaller.sendMessage(message);
1778         }
1779 
1780         public void onSoftKeyboardShowModeChanged(int showMode) {
1781           final Message message =
1782                   mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
1783           mCaller.sendMessage(message);
1784         }
1785 
1786         public void onPerformGestureResult(int sequence, boolean successfully) {
1787             Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
1788                     successfully ? 1 : 0);
1789             mCaller.sendMessage(message);
1790         }
1791 
1792         public void onFingerprintCapturingGesturesChanged(boolean active) {
1793             mCaller.sendMessage(mCaller.obtainMessageI(
1794                     DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0));
1795         }
1796 
1797         public void onFingerprintGesture(int gesture) {
1798             mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
1799         }
1800 
1801         public void onAccessibilityButtonClicked() {
1802             final Message message = mCaller.obtainMessage(DO_ACCESSIBILITY_BUTTON_CLICKED);
1803             mCaller.sendMessage(message);
1804         }
1805 
1806         public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1807             final Message message = mCaller.obtainMessageI(
1808                     DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0));
1809             mCaller.sendMessage(message);
1810         }
1811 
1812         @Override
1813         public void executeMessage(Message message) {
1814             switch (message.what) {
1815                 case DO_ON_ACCESSIBILITY_EVENT: {
1816                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
1817                     boolean serviceWantsEvent = message.arg1 != 0;
1818                     if (event != null) {
1819                         // Send the event to AccessibilityCache via AccessibilityInteractionClient
1820                         AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
1821                         if (serviceWantsEvent
1822                                 && (mConnectionId != AccessibilityInteractionClient.NO_ID)) {
1823                             // Send the event to AccessibilityService
1824                             mCallback.onAccessibilityEvent(event);
1825                         }
1826                         // Make sure the event is recycled.
1827                         try {
1828                             event.recycle();
1829                         } catch (IllegalStateException ise) {
1830                             /* ignore - best effort */
1831                         }
1832                     }
1833                 } return;
1834 
1835                 case DO_ON_INTERRUPT: {
1836                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1837                         mCallback.onInterrupt();
1838                     }
1839                 } return;
1840 
1841                 case DO_INIT: {
1842                     mConnectionId = message.arg1;
1843                     SomeArgs args = (SomeArgs) message.obj;
1844                     IAccessibilityServiceConnection connection =
1845                             (IAccessibilityServiceConnection) args.arg1;
1846                     IBinder windowToken = (IBinder) args.arg2;
1847                     args.recycle();
1848                     if (connection != null) {
1849                         AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
1850                                 connection);
1851                         mCallback.init(mConnectionId, windowToken);
1852                         mCallback.onServiceConnected();
1853                     } else {
1854                         AccessibilityInteractionClient.getInstance().removeConnection(
1855                                 mConnectionId);
1856                         mConnectionId = AccessibilityInteractionClient.NO_ID;
1857                         AccessibilityInteractionClient.getInstance().clearCache();
1858                         mCallback.init(AccessibilityInteractionClient.NO_ID, null);
1859                     }
1860                 } return;
1861 
1862                 case DO_ON_GESTURE: {
1863                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1864                         final int gestureId = message.arg1;
1865                         mCallback.onGesture(gestureId);
1866                     }
1867                 } return;
1868 
1869                 case DO_CLEAR_ACCESSIBILITY_CACHE: {
1870                     AccessibilityInteractionClient.getInstance().clearCache();
1871                 } return;
1872 
1873                 case DO_ON_KEY_EVENT: {
1874                     KeyEvent event = (KeyEvent) message.obj;
1875                     try {
1876                         IAccessibilityServiceConnection connection = AccessibilityInteractionClient
1877                                 .getInstance().getConnection(mConnectionId);
1878                         if (connection != null) {
1879                             final boolean result = mCallback.onKeyEvent(event);
1880                             final int sequence = message.arg1;
1881                             try {
1882                                 connection.setOnKeyEventResult(result, sequence);
1883                             } catch (RemoteException re) {
1884                                 /* ignore */
1885                             }
1886                         }
1887                     } finally {
1888                         // Make sure the event is recycled.
1889                         try {
1890                             event.recycle();
1891                         } catch (IllegalStateException ise) {
1892                             /* ignore - best effort */
1893                         }
1894                     }
1895                 } return;
1896 
1897                 case DO_ON_MAGNIFICATION_CHANGED: {
1898                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1899                         final SomeArgs args = (SomeArgs) message.obj;
1900                         final Region region = (Region) args.arg1;
1901                         final float scale = (float) args.arg2;
1902                         final float centerX = (float) args.arg3;
1903                         final float centerY = (float) args.arg4;
1904                         final int displayId = args.argi1;
1905                         args.recycle();
1906                         mCallback.onMagnificationChanged(displayId, region, scale,
1907                                 centerX, centerY);
1908                     }
1909                 } return;
1910 
1911                 case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
1912                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1913                         final int showMode = (int) message.arg1;
1914                         mCallback.onSoftKeyboardShowModeChanged(showMode);
1915                     }
1916                 } return;
1917 
1918                 case DO_GESTURE_COMPLETE: {
1919                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1920                         final boolean successfully = message.arg2 == 1;
1921                         mCallback.onPerformGestureResult(message.arg1, successfully);
1922                     }
1923                 } return;
1924                 case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
1925                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1926                         mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
1927                     }
1928                 } return;
1929                 case DO_ON_FINGERPRINT_GESTURE: {
1930                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1931                         mCallback.onFingerprintGesture(message.arg1);
1932                     }
1933                 } return;
1934 
1935                 case (DO_ACCESSIBILITY_BUTTON_CLICKED): {
1936                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1937                         mCallback.onAccessibilityButtonClicked();
1938                     }
1939                 } return;
1940 
1941                 case (DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED): {
1942                     if (mConnectionId != AccessibilityInteractionClient.NO_ID) {
1943                         final boolean available = (message.arg1 != 0);
1944                         mCallback.onAccessibilityButtonAvailabilityChanged(available);
1945                     }
1946                 } return;
1947 
1948                 default :
1949                     Log.w(LOG_TAG, "Unknown message type " + message.what);
1950             }
1951         }
1952     }
1953 
1954     /**
1955      * Class used to report status of dispatched gestures
1956      */
1957     public static abstract class GestureResultCallback {
1958         /** Called when the gesture has completed successfully
1959          *
1960          * @param gestureDescription The description of the gesture that completed.
1961          */
1962         public void onCompleted(GestureDescription gestureDescription) {
1963         }
1964 
1965         /** Called when the gesture was cancelled
1966          *
1967          * @param gestureDescription The description of the gesture that was cancelled.
1968          */
1969         public void onCancelled(GestureDescription gestureDescription) {
1970         }
1971     }
1972 
1973     /* Object to keep track of gesture result callbacks */
1974     private static class GestureResultCallbackInfo {
1975         GestureDescription gestureDescription;
1976         GestureResultCallback callback;
1977         Handler handler;
1978 
1979         GestureResultCallbackInfo(GestureDescription gestureDescription,
1980                 GestureResultCallback callback, Handler handler) {
1981             this.gestureDescription = gestureDescription;
1982             this.callback = callback;
1983             this.handler = handler;
1984         }
1985     }
1986 }
1987