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