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