AccessibilityService.java revision 7917a2f020b95a6372dd3c506183ea345ab5ae24
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
55import 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 */
221public 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_CAPTURE_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 @Nullable FingerprintGestureController getFingerprintGestureController() {
623        if ((mFingerprintGestureController == null)
624                && getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT)) {
625            FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
626            if ((fingerprintManager != null) && fingerprintManager.isHardwareDetected()) {
627                AccessibilityServiceInfo info = getServiceInfo();
628                int fingerprintCapabilityMask =
629                        AccessibilityServiceInfo.CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES;
630                if ((info.getCapabilities() & fingerprintCapabilityMask) != 0) {
631                    mFingerprintGestureController = new FingerprintGestureController(
632                            AccessibilityInteractionClient.getInstance()
633                                    .getConnection(mConnectionId));
634                }
635            }
636        }
637        return mFingerprintGestureController;
638    }
639
640    /**
641     * Dispatch a gesture to the touch screen. Any gestures currently in progress, whether from
642     * the user, this service, or another service, will be cancelled.
643     * <p>
644     * The gesture will be dispatched as if it were performed directly on the screen by a user, so
645     * the events may be affected by features such as magnification and explore by touch.
646     * </p>
647     * <p>
648     * <strong>Note:</strong> In order to dispatch gestures, your service
649     * must declare the capability by setting the
650     * {@link android.R.styleable#AccessibilityService_canPerformGestures}
651     * property in its meta-data. For more information, see
652     * {@link #SERVICE_META_DATA}.
653     * </p>
654     *
655     * @param gesture The gesture to dispatch
656     * @param callback The object to call back when the status of the gesture is known. If
657     * {@code null}, no status is reported.
658     * @param handler The handler on which to call back the {@code callback} object. If
659     * {@code null}, the object is called back on the service's main thread.
660     *
661     * @return {@code true} if the gesture is dispatched, {@code false} if not.
662     */
663    public final boolean dispatchGesture(@NonNull GestureDescription gesture,
664            @Nullable GestureResultCallback callback,
665            @Nullable Handler handler) {
666        final IAccessibilityServiceConnection connection =
667                AccessibilityInteractionClient.getInstance().getConnection(
668                        mConnectionId);
669        if (connection == null) {
670            return false;
671        }
672        List<GestureDescription.GestureStep> steps =
673                MotionEventGenerator.getGestureStepsFromGestureDescription(gesture, 100);
674        try {
675            synchronized (mLock) {
676                mGestureStatusCallbackSequence++;
677                if (callback != null) {
678                    if (mGestureStatusCallbackInfos == null) {
679                        mGestureStatusCallbackInfos = new SparseArray<>();
680                    }
681                    GestureResultCallbackInfo callbackInfo = new GestureResultCallbackInfo(gesture,
682                            callback, handler);
683                    mGestureStatusCallbackInfos.put(mGestureStatusCallbackSequence, callbackInfo);
684                }
685                connection.sendGesture(mGestureStatusCallbackSequence,
686                        new ParceledListSlice<>(steps));
687            }
688        } catch (RemoteException re) {
689            throw new RuntimeException(re);
690        }
691        return true;
692    }
693
694    void onPerformGestureResult(int sequence, final boolean completedSuccessfully) {
695        if (mGestureStatusCallbackInfos == null) {
696            return;
697        }
698        GestureResultCallbackInfo callbackInfo;
699        synchronized (mLock) {
700            callbackInfo = mGestureStatusCallbackInfos.get(sequence);
701        }
702        final GestureResultCallbackInfo finalCallbackInfo = callbackInfo;
703        if ((callbackInfo != null) && (callbackInfo.gestureDescription != null)
704                && (callbackInfo.callback != null)) {
705            if (callbackInfo.handler != null) {
706                callbackInfo.handler.post(new Runnable() {
707                    @Override
708                    public void run() {
709                        if (completedSuccessfully) {
710                            finalCallbackInfo.callback
711                                    .onCompleted(finalCallbackInfo.gestureDescription);
712                        } else {
713                            finalCallbackInfo.callback
714                                    .onCancelled(finalCallbackInfo.gestureDescription);
715                        }
716                    }
717                });
718                return;
719            }
720            if (completedSuccessfully) {
721                callbackInfo.callback.onCompleted(callbackInfo.gestureDescription);
722            } else {
723                callbackInfo.callback.onCancelled(callbackInfo.gestureDescription);
724            }
725        }
726    }
727
728    private void onMagnificationChanged(@NonNull Region region, float scale,
729            float centerX, float centerY) {
730        if (mMagnificationController != null) {
731            mMagnificationController.dispatchMagnificationChanged(
732                    region, scale, centerX, centerY);
733        }
734    }
735
736    /**
737     * Callback for fingerprint gesture handling
738     * @param active If gesture detection is active
739     */
740    private void onFingerprintCapturingGesturesChanged(boolean active) {
741        getFingerprintGestureController().onGestureDetectionActiveChanged(active);
742    }
743
744    /**
745     * Callback for fingerprint gesture handling
746     * @param gesture The identifier for the gesture performed
747     */
748    private void onFingerprintGesture(int gesture) {
749        getFingerprintGestureController().onGesture(gesture);
750    }
751
752    /**
753     * Used to control and query the state of display magnification.
754     */
755    public static final class MagnificationController {
756        private final AccessibilityService mService;
757
758        /**
759         * Map of listeners to their handlers. Lazily created when adding the
760         * first magnification listener.
761         */
762        private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
763        private final Object mLock;
764
765        MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
766            mService = service;
767            mLock = lock;
768        }
769
770        /**
771         * Called when the service is connected.
772         */
773        void onServiceConnected() {
774            synchronized (mLock) {
775                if (mListeners != null && !mListeners.isEmpty()) {
776                    setMagnificationCallbackEnabled(true);
777                }
778            }
779        }
780
781        /**
782         * Adds the specified change listener to the list of magnification
783         * change listeners. The callback will occur on the service's main
784         * thread.
785         *
786         * @param listener the listener to add, must be non-{@code null}
787         */
788        public void addListener(@NonNull OnMagnificationChangedListener listener) {
789            addListener(listener, null);
790        }
791
792        /**
793         * Adds the specified change listener to the list of magnification
794         * change listeners. The callback will occur on the specified
795         * {@link Handler}'s thread, or on the service's main thread if the
796         * handler is {@code null}.
797         *
798         * @param listener the listener to add, must be non-null
799         * @param handler the handler on which the callback should execute, or
800         *        {@code null} to execute on the service's main thread
801         */
802        public void addListener(@NonNull OnMagnificationChangedListener listener,
803                @Nullable Handler handler) {
804            synchronized (mLock) {
805                if (mListeners == null) {
806                    mListeners = new ArrayMap<>();
807                }
808
809                final boolean shouldEnableCallback = mListeners.isEmpty();
810                mListeners.put(listener, handler);
811
812                if (shouldEnableCallback) {
813                    // This may fail if the service is not connected yet, but if we
814                    // still have listeners when it connects then we can try again.
815                    setMagnificationCallbackEnabled(true);
816                }
817            }
818        }
819
820        /**
821         * Removes the specified change listener from the list of magnification change listeners.
822         *
823         * @param listener the listener to remove, must be non-null
824         * @return {@code true} if the listener was removed, {@code false} otherwise
825         */
826        public boolean removeListener(@NonNull OnMagnificationChangedListener listener) {
827            if (mListeners == null) {
828                return false;
829            }
830
831            synchronized (mLock) {
832                final int keyIndex = mListeners.indexOfKey(listener);
833                final boolean hasKey = keyIndex >= 0;
834                if (hasKey) {
835                    mListeners.removeAt(keyIndex);
836                }
837
838                if (hasKey && mListeners.isEmpty()) {
839                    // We just removed the last listener, so we don't need
840                    // callbacks from the service anymore.
841                    setMagnificationCallbackEnabled(false);
842                }
843
844                return hasKey;
845            }
846        }
847
848        private void setMagnificationCallbackEnabled(boolean enabled) {
849            final IAccessibilityServiceConnection connection =
850                    AccessibilityInteractionClient.getInstance().getConnection(
851                            mService.mConnectionId);
852            if (connection != null) {
853                try {
854                    connection.setMagnificationCallbackEnabled(enabled);
855                } catch (RemoteException re) {
856                    throw new RuntimeException(re);
857                }
858            }
859        }
860
861        /**
862         * Dispatches magnification changes to any registered listeners. This
863         * should be called on the service's main thread.
864         */
865        void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
866                final float centerX, final float centerY) {
867            final ArrayMap<OnMagnificationChangedListener, Handler> entries;
868            synchronized (mLock) {
869                if (mListeners == null || mListeners.isEmpty()) {
870                    Slog.d(LOG_TAG, "Received magnification changed "
871                            + "callback with no listeners registered!");
872                    setMagnificationCallbackEnabled(false);
873                    return;
874                }
875
876                // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
877                // modification.
878                entries = new ArrayMap<>(mListeners);
879            }
880
881            for (int i = 0, count = entries.size(); i < count; i++) {
882                final OnMagnificationChangedListener listener = entries.keyAt(i);
883                final Handler handler = entries.valueAt(i);
884                if (handler != null) {
885                    handler.post(new Runnable() {
886                        @Override
887                        public void run() {
888                            listener.onMagnificationChanged(MagnificationController.this,
889                                    region, scale, centerX, centerY);
890                        }
891                    });
892                } else {
893                    // We're already on the main thread, just run the listener.
894                    listener.onMagnificationChanged(this, region, scale, centerX, centerY);
895                }
896            }
897        }
898
899        /**
900         * Returns the current magnification scale.
901         * <p>
902         * <strong>Note:</strong> If the service is not yet connected (e.g.
903         * {@link AccessibilityService#onServiceConnected()} has not yet been
904         * called) or the service has been disconnected, this method will
905         * return a default value of {@code 1.0f}.
906         *
907         * @return the current magnification scale
908         */
909        public float getScale() {
910            final IAccessibilityServiceConnection connection =
911                    AccessibilityInteractionClient.getInstance().getConnection(
912                            mService.mConnectionId);
913            if (connection != null) {
914                try {
915                    return connection.getMagnificationScale();
916                } catch (RemoteException re) {
917                    Log.w(LOG_TAG, "Failed to obtain scale", re);
918                    re.rethrowFromSystemServer();
919                }
920            }
921            return 1.0f;
922        }
923
924        /**
925         * Returns the unscaled screen-relative X coordinate of the focal
926         * center of the magnified region. This is the point around which
927         * zooming occurs and is guaranteed to lie within the magnified
928         * region.
929         * <p>
930         * <strong>Note:</strong> If the service is not yet connected (e.g.
931         * {@link AccessibilityService#onServiceConnected()} has not yet been
932         * called) or the service has been disconnected, this method will
933         * return a default value of {@code 0.0f}.
934         *
935         * @return the unscaled screen-relative X coordinate of the center of
936         *         the magnified region
937         */
938        public float getCenterX() {
939            final IAccessibilityServiceConnection connection =
940                    AccessibilityInteractionClient.getInstance().getConnection(
941                            mService.mConnectionId);
942            if (connection != null) {
943                try {
944                    return connection.getMagnificationCenterX();
945                } catch (RemoteException re) {
946                    Log.w(LOG_TAG, "Failed to obtain center X", re);
947                    re.rethrowFromSystemServer();
948                }
949            }
950            return 0.0f;
951        }
952
953        /**
954         * Returns the unscaled screen-relative Y coordinate of the focal
955         * center of the magnified region. This is the point around which
956         * zooming occurs and is guaranteed to lie within the magnified
957         * region.
958         * <p>
959         * <strong>Note:</strong> If the service is not yet connected (e.g.
960         * {@link AccessibilityService#onServiceConnected()} has not yet been
961         * called) or the service has been disconnected, this method will
962         * return a default value of {@code 0.0f}.
963         *
964         * @return the unscaled screen-relative Y coordinate of the center of
965         *         the magnified region
966         */
967        public float getCenterY() {
968            final IAccessibilityServiceConnection connection =
969                    AccessibilityInteractionClient.getInstance().getConnection(
970                            mService.mConnectionId);
971            if (connection != null) {
972                try {
973                    return connection.getMagnificationCenterY();
974                } catch (RemoteException re) {
975                    Log.w(LOG_TAG, "Failed to obtain center Y", re);
976                    re.rethrowFromSystemServer();
977                }
978            }
979            return 0.0f;
980        }
981
982        /**
983         * Returns the region of the screen currently active for magnification. Changes to
984         * magnification scale and center only affect this portion of the screen. The rest of the
985         * screen, for example input methods, cannot be magnified. This region is relative to the
986         * unscaled screen and is independent of the scale and center point.
987         * <p>
988         * The returned region will be empty if magnification is not active. Magnification is active
989         * if magnification gestures are enabled or if a service is running that can control
990         * magnification.
991         * <p>
992         * <strong>Note:</strong> If the service is not yet connected (e.g.
993         * {@link AccessibilityService#onServiceConnected()} has not yet been
994         * called) or the service has been disconnected, this method will
995         * return an empty region.
996         *
997         * @return the region of the screen currently active for magnification, or an empty region
998         * if magnification is not active.
999         */
1000        @NonNull
1001        public Region getMagnificationRegion() {
1002            final IAccessibilityServiceConnection connection =
1003                    AccessibilityInteractionClient.getInstance().getConnection(
1004                            mService.mConnectionId);
1005            if (connection != null) {
1006                try {
1007                    return connection.getMagnificationRegion();
1008                } catch (RemoteException re) {
1009                    Log.w(LOG_TAG, "Failed to obtain magnified region", re);
1010                    re.rethrowFromSystemServer();
1011                }
1012            }
1013            return Region.obtain();
1014        }
1015
1016        /**
1017         * Resets magnification scale and center to their default (e.g. no
1018         * magnification) values.
1019         * <p>
1020         * <strong>Note:</strong> If the service is not yet connected (e.g.
1021         * {@link AccessibilityService#onServiceConnected()} has not yet been
1022         * called) or the service has been disconnected, this method will have
1023         * no effect and return {@code false}.
1024         *
1025         * @param animate {@code true} to animate from the current scale and
1026         *                center or {@code false} to reset the scale and center
1027         *                immediately
1028         * @return {@code true} on success, {@code false} on failure
1029         */
1030        public boolean reset(boolean animate) {
1031            final IAccessibilityServiceConnection connection =
1032                    AccessibilityInteractionClient.getInstance().getConnection(
1033                            mService.mConnectionId);
1034            if (connection != null) {
1035                try {
1036                    return connection.resetMagnification(animate);
1037                } catch (RemoteException re) {
1038                    Log.w(LOG_TAG, "Failed to reset", re);
1039                    re.rethrowFromSystemServer();
1040                }
1041            }
1042            return false;
1043        }
1044
1045        /**
1046         * Sets the magnification scale.
1047         * <p>
1048         * <strong>Note:</strong> If the service is not yet connected (e.g.
1049         * {@link AccessibilityService#onServiceConnected()} has not yet been
1050         * called) or the service has been disconnected, this method will have
1051         * no effect and return {@code false}.
1052         *
1053         * @param scale the magnification scale to set, must be >= 1 and <= 5
1054         * @param animate {@code true} to animate from the current scale or
1055         *                {@code false} to set the scale immediately
1056         * @return {@code true} on success, {@code false} on failure
1057         */
1058        public boolean setScale(float scale, boolean animate) {
1059            final IAccessibilityServiceConnection connection =
1060                    AccessibilityInteractionClient.getInstance().getConnection(
1061                            mService.mConnectionId);
1062            if (connection != null) {
1063                try {
1064                    return connection.setMagnificationScaleAndCenter(
1065                            scale, Float.NaN, Float.NaN, animate);
1066                } catch (RemoteException re) {
1067                    Log.w(LOG_TAG, "Failed to set scale", re);
1068                    re.rethrowFromSystemServer();
1069                }
1070            }
1071            return false;
1072        }
1073
1074        /**
1075         * Sets the center of the magnified viewport.
1076         * <p>
1077         * <strong>Note:</strong> If the service is not yet connected (e.g.
1078         * {@link AccessibilityService#onServiceConnected()} has not yet been
1079         * called) or the service has been disconnected, this method will have
1080         * no effect and return {@code false}.
1081         *
1082         * @param centerX the unscaled screen-relative X coordinate on which to
1083         *                center the viewport
1084         * @param centerY the unscaled screen-relative Y coordinate on which to
1085         *                center the viewport
1086         * @param animate {@code true} to animate from the current viewport
1087         *                center or {@code false} to set the center immediately
1088         * @return {@code true} on success, {@code false} on failure
1089         */
1090        public boolean setCenter(float centerX, float centerY, boolean animate) {
1091            final IAccessibilityServiceConnection connection =
1092                    AccessibilityInteractionClient.getInstance().getConnection(
1093                            mService.mConnectionId);
1094            if (connection != null) {
1095                try {
1096                    return connection.setMagnificationScaleAndCenter(
1097                            Float.NaN, centerX, centerY, animate);
1098                } catch (RemoteException re) {
1099                    Log.w(LOG_TAG, "Failed to set center", re);
1100                    re.rethrowFromSystemServer();
1101                }
1102            }
1103            return false;
1104        }
1105
1106        /**
1107         * Listener for changes in the state of magnification.
1108         */
1109        public interface OnMagnificationChangedListener {
1110            /**
1111             * Called when the magnified region, scale, or center changes.
1112             *
1113             * @param controller the magnification controller
1114             * @param region the magnification region
1115             * @param scale the new scale
1116             * @param centerX the new X coordinate, in unscaled coordinates, around which
1117             * magnification is focused
1118             * @param centerY the new Y coordinate, in unscaled coordinates, around which
1119             * magnification is focused
1120             */
1121            void onMagnificationChanged(@NonNull MagnificationController controller,
1122                    @NonNull Region region, float scale, float centerX, float centerY);
1123        }
1124    }
1125
1126    /**
1127     * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
1128     * show mode.
1129     *
1130     * @return the soft keyboard controller
1131     */
1132    @NonNull
1133    public final SoftKeyboardController getSoftKeyboardController() {
1134        synchronized (mLock) {
1135            if (mSoftKeyboardController == null) {
1136                mSoftKeyboardController = new SoftKeyboardController(this, mLock);
1137            }
1138            return mSoftKeyboardController;
1139        }
1140    }
1141
1142    private void onSoftKeyboardShowModeChanged(int showMode) {
1143        if (mSoftKeyboardController != null) {
1144            mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
1145        }
1146    }
1147
1148    /**
1149     * Used to control and query the soft keyboard show mode.
1150     */
1151    public static final class SoftKeyboardController {
1152        private final AccessibilityService mService;
1153
1154        /**
1155         * Map of listeners to their handlers. Lazily created when adding the first
1156         * soft keyboard change listener.
1157         */
1158        private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
1159        private final Object mLock;
1160
1161        SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
1162            mService = service;
1163            mLock = lock;
1164        }
1165
1166        /**
1167         * Called when the service is connected.
1168         */
1169        void onServiceConnected() {
1170            synchronized(mLock) {
1171                if (mListeners != null && !mListeners.isEmpty()) {
1172                    setSoftKeyboardCallbackEnabled(true);
1173                }
1174            }
1175        }
1176
1177        /**
1178         * Adds the specified change listener to the list of show mode change listeners. The
1179         * callback will occur on the service's main thread. Listener is not called on registration.
1180         */
1181        public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
1182            addOnShowModeChangedListener(listener, null);
1183        }
1184
1185        /**
1186         * Adds the specified change listener to the list of soft keyboard show mode change
1187         * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
1188         * services's main thread if the handler is {@code null}.
1189         *
1190         * @param listener the listener to add, must be non-null
1191         * @param handler the handler on which to callback should execute, or {@code null} to
1192         *        execute on the service's main thread
1193         */
1194        public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
1195                @Nullable Handler handler) {
1196            synchronized (mLock) {
1197                if (mListeners == null) {
1198                    mListeners = new ArrayMap<>();
1199                }
1200
1201                final boolean shouldEnableCallback = mListeners.isEmpty();
1202                mListeners.put(listener, handler);
1203
1204                if (shouldEnableCallback) {
1205                    // This may fail if the service is not connected yet, but if we still have
1206                    // listeners when it connects, we can try again.
1207                    setSoftKeyboardCallbackEnabled(true);
1208                }
1209            }
1210        }
1211
1212        /**
1213         * Removes the specified change listener from the list of keyboard show mode change
1214         * listeners.
1215         *
1216         * @param listener the listener to remove, must be non-null
1217         * @return {@code true} if the listener was removed, {@code false} otherwise
1218         */
1219        public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
1220            if (mListeners == null) {
1221                return false;
1222            }
1223
1224            synchronized (mLock) {
1225                final int keyIndex = mListeners.indexOfKey(listener);
1226                final boolean hasKey = keyIndex >= 0;
1227                if (hasKey) {
1228                    mListeners.removeAt(keyIndex);
1229                }
1230
1231                if (hasKey && mListeners.isEmpty()) {
1232                    // We just removed the last listener, so we don't need callbacks from the
1233                    // service anymore.
1234                    setSoftKeyboardCallbackEnabled(false);
1235                }
1236
1237                return hasKey;
1238            }
1239        }
1240
1241        private void setSoftKeyboardCallbackEnabled(boolean enabled) {
1242            final IAccessibilityServiceConnection connection =
1243                    AccessibilityInteractionClient.getInstance().getConnection(
1244                            mService.mConnectionId);
1245            if (connection != null) {
1246                try {
1247                    connection.setSoftKeyboardCallbackEnabled(enabled);
1248                } catch (RemoteException re) {
1249                    throw new RuntimeException(re);
1250                }
1251            }
1252        }
1253
1254        /**
1255         * Dispatches the soft keyboard show mode change to any registered listeners. This should
1256         * be called on the service's main thread.
1257         */
1258        void dispatchSoftKeyboardShowModeChanged(final int showMode) {
1259            final ArrayMap<OnShowModeChangedListener, Handler> entries;
1260            synchronized (mLock) {
1261                if (mListeners == null || mListeners.isEmpty()) {
1262                    Slog.w(LOG_TAG, "Received soft keyboard show mode changed callback"
1263                            + " with no listeners registered!");
1264                    setSoftKeyboardCallbackEnabled(false);
1265                    return;
1266                }
1267
1268                // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
1269                // modification.
1270                entries = new ArrayMap<>(mListeners);
1271            }
1272
1273            for (int i = 0, count = entries.size(); i < count; i++) {
1274                final OnShowModeChangedListener listener = entries.keyAt(i);
1275                final Handler handler = entries.valueAt(i);
1276                if (handler != null) {
1277                    handler.post(new Runnable() {
1278                        @Override
1279                        public void run() {
1280                            listener.onShowModeChanged(SoftKeyboardController.this, showMode);
1281                        }
1282                    });
1283                } else {
1284                    // We're already on the main thread, just run the listener.
1285                    listener.onShowModeChanged(this, showMode);
1286                }
1287            }
1288        }
1289
1290        /**
1291         * Returns the show mode of the soft keyboard. The default show mode is
1292         * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1293         * focused. An AccessibilityService can also request the show mode
1294         * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
1295         *
1296         * @return the current soft keyboard show mode
1297         */
1298        @SoftKeyboardShowMode
1299        public int getShowMode() {
1300           try {
1301               return Settings.Secure.getInt(mService.getContentResolver(),
1302                       Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
1303           } catch (Settings.SettingNotFoundException e) {
1304               Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
1305               // The settings hasn't been changed yet, so it's value is null. Return the default.
1306               return 0;
1307           }
1308        }
1309
1310        /**
1311         * Sets the soft keyboard show mode. The default show mode is
1312         * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1313         * focused. An AccessibilityService can also request the show mode
1314         * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
1315         * The lastto this method will be honored, regardless of any previous calls (including those
1316         * made by other AccessibilityServices).
1317         * <p>
1318         * <strong>Note:</strong> If the service is not yet connected (e.g.
1319         * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
1320         * service has been disconnected, this method will have no effect and return {@code false}.
1321         *
1322         * @param showMode the new show mode for the soft keyboard
1323         * @return {@code true} on success
1324         */
1325        public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
1326           final IAccessibilityServiceConnection connection =
1327                   AccessibilityInteractionClient.getInstance().getConnection(
1328                           mService.mConnectionId);
1329           if (connection != null) {
1330               try {
1331                   return connection.setSoftKeyboardShowMode(showMode);
1332               } catch (RemoteException re) {
1333                   Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
1334                   re.rethrowFromSystemServer();
1335               }
1336           }
1337           return false;
1338        }
1339
1340        /**
1341         * Listener for changes in the soft keyboard show mode.
1342         */
1343        public interface OnShowModeChangedListener {
1344           /**
1345            * Called when the soft keyboard behavior changes. The default show mode is
1346            * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
1347            * focused. An AccessibilityService can also request the show mode
1348            * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
1349            *
1350            * @param controller the soft keyboard controller
1351            * @param showMode the current soft keyboard show mode
1352            */
1353            void onShowModeChanged(@NonNull SoftKeyboardController controller,
1354                    @SoftKeyboardShowMode int showMode);
1355        }
1356    }
1357
1358    /**
1359     * Returns the controller for the accessibility button within the system's navigation area.
1360     * This instance may be used to query the accessibility button's state and register listeners
1361     * for interactions with and state changes for the accessibility button when
1362     * {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON} is set.
1363     * <p>
1364     * <strong>Note:</strong> Not all devices are capable of displaying the accessibility button
1365     * within a navigation area, and as such, use of this class should be considered only as an
1366     * optional feature or shortcut on supported device implementations.
1367     * </p>
1368     *
1369     * @return the accessibility button controller for this {@link AccessibilityService}
1370     */
1371    @NonNull
1372    public final AccessibilityButtonController getAccessibilityButtonController() {
1373        synchronized (mLock) {
1374            if (mAccessibilityButtonController == null) {
1375                mAccessibilityButtonController = new AccessibilityButtonController(
1376                        AccessibilityInteractionClient.getInstance().getConnection(mConnectionId));
1377            }
1378            return mAccessibilityButtonController;
1379        }
1380    }
1381
1382    private void onAccessibilityButtonClicked() {
1383        getAccessibilityButtonController().dispatchAccessibilityButtonClicked();
1384    }
1385
1386    private void onAccessibilityButtonAvailabilityChanged(boolean available) {
1387        getAccessibilityButtonController().dispatchAccessibilityButtonAvailabilityChanged(
1388                available);
1389    }
1390
1391    /**
1392     * Performs a global action. Such an action can be performed
1393     * at any moment regardless of the current application or user
1394     * location in that application. For example going back, going
1395     * home, opening recents, etc.
1396     *
1397     * @param action The action to perform.
1398     * @return Whether the action was successfully performed.
1399     *
1400     * @see #GLOBAL_ACTION_BACK
1401     * @see #GLOBAL_ACTION_HOME
1402     * @see #GLOBAL_ACTION_NOTIFICATIONS
1403     * @see #GLOBAL_ACTION_RECENTS
1404     */
1405    public final boolean performGlobalAction(int action) {
1406        IAccessibilityServiceConnection connection =
1407            AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1408        if (connection != null) {
1409            try {
1410                return connection.performGlobalAction(action);
1411            } catch (RemoteException re) {
1412                Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
1413                re.rethrowFromSystemServer();
1414            }
1415        }
1416        return false;
1417    }
1418
1419    /**
1420     * Find the view that has the specified focus type. The search is performed
1421     * across all windows.
1422     * <p>
1423     * <strong>Note:</strong> In order to access the windows your service has
1424     * to declare the capability to retrieve window content by setting the
1425     * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
1426     * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
1427     * Also the service has to opt-in to retrieve the interactive windows by
1428     * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
1429     * flag. Otherwise, the search will be performed only in the active window.
1430     * </p>
1431     *
1432     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
1433     *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
1434     * @return The node info of the focused view or null.
1435     *
1436     * @see AccessibilityNodeInfo#FOCUS_INPUT
1437     * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
1438     */
1439    public AccessibilityNodeInfo findFocus(int focus) {
1440        return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
1441                AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
1442    }
1443
1444    /**
1445     * Gets the an {@link AccessibilityServiceInfo} describing this
1446     * {@link AccessibilityService}. This method is useful if one wants
1447     * to change some of the dynamically configurable properties at
1448     * runtime.
1449     *
1450     * @return The accessibility service info.
1451     *
1452     * @see AccessibilityServiceInfo
1453     */
1454    public final AccessibilityServiceInfo getServiceInfo() {
1455        IAccessibilityServiceConnection connection =
1456            AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1457        if (connection != null) {
1458            try {
1459                return connection.getServiceInfo();
1460            } catch (RemoteException re) {
1461                Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
1462                re.rethrowFromSystemServer();
1463            }
1464        }
1465        return null;
1466    }
1467
1468    /**
1469     * Sets the {@link AccessibilityServiceInfo} that describes this service.
1470     * <p>
1471     * Note: You can call this method any time but the info will be picked up after
1472     *       the system has bound to this service and when this method is called thereafter.
1473     *
1474     * @param info The info.
1475     */
1476    public final void setServiceInfo(AccessibilityServiceInfo info) {
1477        mInfo = info;
1478        sendServiceInfo();
1479    }
1480
1481    /**
1482     * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
1483     * properly set and there is an {@link IAccessibilityServiceConnection} to the
1484     * AccessibilityManagerService.
1485     */
1486    private void sendServiceInfo() {
1487        IAccessibilityServiceConnection connection =
1488            AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
1489        if (mInfo != null && connection != null) {
1490            try {
1491                connection.setServiceInfo(mInfo);
1492                mInfo = null;
1493                AccessibilityInteractionClient.getInstance().clearCache();
1494            } catch (RemoteException re) {
1495                Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
1496                re.rethrowFromSystemServer();
1497            }
1498        }
1499    }
1500
1501    @Override
1502    public Object getSystemService(@ServiceName @NonNull String name) {
1503        if (getBaseContext() == null) {
1504            throw new IllegalStateException(
1505                    "System services not available to Activities before onCreate()");
1506        }
1507
1508        // Guarantee that we always return the same window manager instance.
1509        if (WINDOW_SERVICE.equals(name)) {
1510            if (mWindowManager == null) {
1511                mWindowManager = (WindowManager) getBaseContext().getSystemService(name);
1512            }
1513            return mWindowManager;
1514        }
1515        return super.getSystemService(name);
1516    }
1517
1518    /**
1519     * Implement to return the implementation of the internal accessibility
1520     * service interface.
1521     */
1522    @Override
1523    public final IBinder onBind(Intent intent) {
1524        return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
1525            @Override
1526            public void onServiceConnected() {
1527                AccessibilityService.this.dispatchServiceConnected();
1528            }
1529
1530            @Override
1531            public void onInterrupt() {
1532                AccessibilityService.this.onInterrupt();
1533            }
1534
1535            @Override
1536            public void onAccessibilityEvent(AccessibilityEvent event) {
1537                AccessibilityService.this.onAccessibilityEvent(event);
1538            }
1539
1540            @Override
1541            public void init(int connectionId, IBinder windowToken) {
1542                mConnectionId = connectionId;
1543                mWindowToken = windowToken;
1544
1545                // The client may have already obtained the window manager, so
1546                // update the default token on whatever manager we gave them.
1547                final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
1548                wm.setDefaultToken(windowToken);
1549            }
1550
1551            @Override
1552            public boolean onGesture(int gestureId) {
1553                return AccessibilityService.this.onGesture(gestureId);
1554            }
1555
1556            @Override
1557            public boolean onKeyEvent(KeyEvent event) {
1558                return AccessibilityService.this.onKeyEvent(event);
1559            }
1560
1561            @Override
1562            public void onMagnificationChanged(@NonNull Region region,
1563                    float scale, float centerX, float centerY) {
1564                AccessibilityService.this.onMagnificationChanged(region, scale, centerX, centerY);
1565            }
1566
1567            @Override
1568            public void onSoftKeyboardShowModeChanged(int showMode) {
1569                AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
1570            }
1571
1572            @Override
1573            public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
1574                AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
1575            }
1576
1577            @Override
1578            public void onFingerprintCapturingGesturesChanged(boolean active) {
1579                AccessibilityService.this.onFingerprintCapturingGesturesChanged(active);
1580            }
1581
1582            @Override
1583            public void onFingerprintGesture(int gesture) {
1584                AccessibilityService.this.onFingerprintGesture(gesture);
1585            }
1586
1587            @Override
1588            public void onAccessibilityButtonClicked() {
1589                AccessibilityService.this.onAccessibilityButtonClicked();
1590            }
1591
1592            @Override
1593            public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1594                AccessibilityService.this.onAccessibilityButtonAvailabilityChanged(available);
1595            }
1596        });
1597    }
1598
1599    /**
1600     * Implements the internal {@link IAccessibilityServiceClient} interface to convert
1601     * incoming calls to it back to calls on an {@link AccessibilityService}.
1602     *
1603     * @hide
1604     */
1605    public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
1606            implements HandlerCaller.Callback {
1607        private static final int DO_INIT = 1;
1608        private static final int DO_ON_INTERRUPT = 2;
1609        private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
1610        private static final int DO_ON_GESTURE = 4;
1611        private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
1612        private static final int DO_ON_KEY_EVENT = 6;
1613        private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
1614        private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
1615        private static final int DO_GESTURE_COMPLETE = 9;
1616        private static final int DO_ON_FINGERPRINT_ACTIVE_CHANGED = 10;
1617        private static final int DO_ON_FINGERPRINT_GESTURE = 11;
1618        private static final int DO_ACCESSIBILITY_BUTTON_CLICKED = 12;
1619        private static final int DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 13;
1620
1621        private final HandlerCaller mCaller;
1622
1623        private final Callbacks mCallback;
1624
1625        private int mConnectionId;
1626
1627        public IAccessibilityServiceClientWrapper(Context context, Looper looper,
1628                Callbacks callback) {
1629            mCallback = callback;
1630            mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
1631        }
1632
1633        public void init(IAccessibilityServiceConnection connection, int connectionId,
1634                IBinder windowToken) {
1635            Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
1636                    connection, windowToken);
1637            mCaller.sendMessage(message);
1638        }
1639
1640        public void onInterrupt() {
1641            Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
1642            mCaller.sendMessage(message);
1643        }
1644
1645        public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) {
1646            Message message = mCaller.obtainMessageBO(
1647                    DO_ON_ACCESSIBILITY_EVENT, serviceWantsEvent, event);
1648            mCaller.sendMessage(message);
1649        }
1650
1651        public void onGesture(int gestureId) {
1652            Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
1653            mCaller.sendMessage(message);
1654        }
1655
1656        public void clearAccessibilityCache() {
1657            Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
1658            mCaller.sendMessage(message);
1659        }
1660
1661        @Override
1662        public void onKeyEvent(KeyEvent event, int sequence) {
1663            Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
1664            mCaller.sendMessage(message);
1665        }
1666
1667        public void onMagnificationChanged(@NonNull Region region,
1668                float scale, float centerX, float centerY) {
1669            final SomeArgs args = SomeArgs.obtain();
1670            args.arg1 = region;
1671            args.arg2 = scale;
1672            args.arg3 = centerX;
1673            args.arg4 = centerY;
1674
1675            final Message message = mCaller.obtainMessageO(DO_ON_MAGNIFICATION_CHANGED, args);
1676            mCaller.sendMessage(message);
1677        }
1678
1679        public void onSoftKeyboardShowModeChanged(int showMode) {
1680          final Message message =
1681                  mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
1682          mCaller.sendMessage(message);
1683        }
1684
1685        public void onPerformGestureResult(int sequence, boolean successfully) {
1686            Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
1687                    successfully ? 1 : 0);
1688            mCaller.sendMessage(message);
1689        }
1690
1691        public void onFingerprintCapturingGesturesChanged(boolean active) {
1692            mCaller.sendMessage(mCaller.obtainMessageI(
1693                    DO_ON_FINGERPRINT_ACTIVE_CHANGED, active ? 1 : 0));
1694        }
1695
1696        public void onFingerprintGesture(int gesture) {
1697            mCaller.sendMessage(mCaller.obtainMessageI(DO_ON_FINGERPRINT_GESTURE, gesture));
1698        }
1699
1700        public void onAccessibilityButtonClicked() {
1701            final Message message = mCaller.obtainMessage(DO_ACCESSIBILITY_BUTTON_CLICKED);
1702            mCaller.sendMessage(message);
1703        }
1704
1705        public void onAccessibilityButtonAvailabilityChanged(boolean available) {
1706            final Message message = mCaller.obtainMessageI(
1707                    DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, (available ? 1 : 0));
1708            mCaller.sendMessage(message);
1709        }
1710
1711        @Override
1712        public void executeMessage(Message message) {
1713            switch (message.what) {
1714                case DO_ON_ACCESSIBILITY_EVENT: {
1715                    AccessibilityEvent event = (AccessibilityEvent) message.obj;
1716                    boolean serviceWantsEvent = message.arg1 != 0;
1717                    if (event != null) {
1718                        // Send the event to AccessibilityCache via AccessibilityInteractionClient
1719                        AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
1720                        if (serviceWantsEvent) {
1721                            // Send the event to AccessibilityService
1722                            mCallback.onAccessibilityEvent(event);
1723                        }
1724                        // Make sure the event is recycled.
1725                        try {
1726                            event.recycle();
1727                        } catch (IllegalStateException ise) {
1728                            /* ignore - best effort */
1729                        }
1730                    }
1731                } return;
1732
1733                case DO_ON_INTERRUPT: {
1734                    mCallback.onInterrupt();
1735                } return;
1736
1737                case DO_INIT: {
1738                    mConnectionId = message.arg1;
1739                    SomeArgs args = (SomeArgs) message.obj;
1740                    IAccessibilityServiceConnection connection =
1741                            (IAccessibilityServiceConnection) args.arg1;
1742                    IBinder windowToken = (IBinder) args.arg2;
1743                    args.recycle();
1744                    if (connection != null) {
1745                        AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
1746                                connection);
1747                        mCallback.init(mConnectionId, windowToken);
1748                        mCallback.onServiceConnected();
1749                    } else {
1750                        AccessibilityInteractionClient.getInstance().removeConnection(
1751                                mConnectionId);
1752                        mConnectionId = AccessibilityInteractionClient.NO_ID;
1753                        AccessibilityInteractionClient.getInstance().clearCache();
1754                        mCallback.init(AccessibilityInteractionClient.NO_ID, null);
1755                    }
1756                } return;
1757
1758                case DO_ON_GESTURE: {
1759                    final int gestureId = message.arg1;
1760                    mCallback.onGesture(gestureId);
1761                } return;
1762
1763                case DO_CLEAR_ACCESSIBILITY_CACHE: {
1764                    AccessibilityInteractionClient.getInstance().clearCache();
1765                } return;
1766
1767                case DO_ON_KEY_EVENT: {
1768                    KeyEvent event = (KeyEvent) message.obj;
1769                    try {
1770                        IAccessibilityServiceConnection connection = AccessibilityInteractionClient
1771                                .getInstance().getConnection(mConnectionId);
1772                        if (connection != null) {
1773                            final boolean result = mCallback.onKeyEvent(event);
1774                            final int sequence = message.arg1;
1775                            try {
1776                                connection.setOnKeyEventResult(result, sequence);
1777                            } catch (RemoteException re) {
1778                                /* ignore */
1779                            }
1780                        }
1781                    } finally {
1782                        // Make sure the event is recycled.
1783                        try {
1784                            event.recycle();
1785                        } catch (IllegalStateException ise) {
1786                            /* ignore - best effort */
1787                        }
1788                    }
1789                } return;
1790
1791                case DO_ON_MAGNIFICATION_CHANGED: {
1792                    final SomeArgs args = (SomeArgs) message.obj;
1793                    final Region region = (Region) args.arg1;
1794                    final float scale = (float) args.arg2;
1795                    final float centerX = (float) args.arg3;
1796                    final float centerY = (float) args.arg4;
1797                    mCallback.onMagnificationChanged(region, scale, centerX, centerY);
1798                } return;
1799
1800                case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
1801                    final int showMode = (int) message.arg1;
1802                    mCallback.onSoftKeyboardShowModeChanged(showMode);
1803                } return;
1804
1805                case DO_GESTURE_COMPLETE: {
1806                    final boolean successfully = message.arg2 == 1;
1807                    mCallback.onPerformGestureResult(message.arg1, successfully);
1808                } return;
1809                case DO_ON_FINGERPRINT_ACTIVE_CHANGED: {
1810                    mCallback.onFingerprintCapturingGesturesChanged(message.arg1 == 1);
1811                } return;
1812                case DO_ON_FINGERPRINT_GESTURE: {
1813                    mCallback.onFingerprintGesture(message.arg1);
1814                } return;
1815
1816                case (DO_ACCESSIBILITY_BUTTON_CLICKED): {
1817                    mCallback.onAccessibilityButtonClicked();
1818                } return;
1819
1820                case (DO_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED): {
1821                    final boolean available = (message.arg1 != 0);
1822                    mCallback.onAccessibilityButtonAvailabilityChanged(available);
1823                } return;
1824
1825                default :
1826                    Log.w(LOG_TAG, "Unknown message type " + message.what);
1827            }
1828        }
1829    }
1830
1831    /**
1832     * Class used to report status of dispatched gestures
1833     */
1834    public static abstract class GestureResultCallback {
1835        /** Called when the gesture has completed successfully
1836         *
1837         * @param gestureDescription The description of the gesture that completed.
1838         */
1839        public void onCompleted(GestureDescription gestureDescription) {
1840        }
1841
1842        /** Called when the gesture was cancelled
1843         *
1844         * @param gestureDescription The description of the gesture that was cancelled.
1845         */
1846        public void onCancelled(GestureDescription gestureDescription) {
1847        }
1848    }
1849
1850    /* Object to keep track of gesture result callbacks */
1851    private static class GestureResultCallbackInfo {
1852        GestureDescription gestureDescription;
1853        GestureResultCallback callback;
1854        Handler handler;
1855
1856        GestureResultCallbackInfo(GestureDescription gestureDescription,
1857                GestureResultCallback callback, Handler handler) {
1858            this.gestureDescription = gestureDescription;
1859            this.callback = callback;
1860            this.handler = handler;
1861        }
1862    }
1863}
1864