OSDN Git Service

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