1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.accessibilityservice;
18 
19 import android.annotation.NonNull;
20 import android.app.Service;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.IBinder;
24 import android.os.Looper;
25 import android.os.Message;
26 import android.os.RemoteException;
27 import android.util.Log;
28 import android.view.KeyEvent;
29 import android.view.WindowManager;
30 import android.view.WindowManagerImpl;
31 import android.view.accessibility.AccessibilityEvent;
32 import android.view.accessibility.AccessibilityInteractionClient;
33 import android.view.accessibility.AccessibilityNodeInfo;
34 import android.view.accessibility.AccessibilityWindowInfo;
35 
36 import com.android.internal.os.HandlerCaller;
37 import com.android.internal.os.SomeArgs;
38 
39 import java.util.List;
40 
41 /**
42  * An accessibility service runs in the background and receives callbacks by the system
43  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
44  * in the user interface, for example, the focus has changed, a button has been clicked,
45  * etc. Such a service can optionally request the capability for querying the content
46  * of the active window. Development of an accessibility service requires extending this
47  * class and implementing its abstract methods.
48  *
49  * <div class="special reference">
50  * <h3>Developer Guides</h3>
51  * <p>For more information about creating AccessibilityServices, read the
52  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
53  * developer guide.</p>
54  * </div>
55  *
56  * <h3>Lifecycle</h3>
57  * <p>
58  * The lifecycle of an accessibility service is managed exclusively by the system and
59  * follows the established service life cycle. Additionally, starting or stopping an
60  * accessibility service is triggered exclusively by an explicit user action through
61  * enabling or disabling it in the device settings. After the system binds to a service it
62  * calls {@link AccessibilityService#onServiceConnected()}. This method can be
63  * overriden by clients that want to perform post binding setup.
64  * </p>
65  * <h3>Declaration</h3>
66  * <p>
67  * An accessibility is declared as any other service in an AndroidManifest.xml but it
68  * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
69  * {@link android.content.Intent}. Failure to declare this intent will cause the system to
70  * ignore the accessibility service. Additionally an accessibility service must request the
71  * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
72  * that only the system
73  * can bind to it. Failure to declare this intent will cause the system to ignore the
74  * accessibility service. Following is an example declaration:
75  * </p>
76  * <pre> &lt;service android:name=".MyAccessibilityService"
77  *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
78  *     &lt;intent-filter&gt;
79  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
80  *     &lt;/intent-filter&gt;
81  *     . . .
82  * &lt;/service&gt;</pre>
83  * <h3>Configuration</h3>
84  * <p>
85  * An accessibility service can be configured to receive specific types of accessibility events,
86  * listen only to specific packages, get events from each type only once in a given time frame,
87  * retrieve window content, specify a settings activity, etc.
88  * </p>
89  * <p>
90  * There are two approaches for configuring an accessibility service:
91  * </p>
92  * <ul>
93  * <li>
94  * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
95  * the service. A service declaration with a meta-data tag is presented below:
96  * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
97  *     &lt;intent-filter&gt;
98  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
99  *     &lt;/intent-filter&gt;
100  *     &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
101  * &lt;/service&gt;</pre>
102  * <p class="note">
103  * <strong>Note:</strong> This approach enables setting all properties.
104  * </p>
105  * <p>
106  * For more details refer to {@link #SERVICE_META_DATA} and
107  * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
108  * </p>
109  * </li>
110  * <li>
111  * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
112  * that this method can be called any time to dynamically change the service configuration.
113  * <p class="note">
114  * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
115  * {@link AccessibilityServiceInfo#eventTypes},
116  * {@link AccessibilityServiceInfo#feedbackType},
117  * {@link AccessibilityServiceInfo#flags},
118  * {@link AccessibilityServiceInfo#notificationTimeout},
119  * {@link AccessibilityServiceInfo#packageNames}
120  * </p>
121  * <p>
122  * For more details refer to {@link AccessibilityServiceInfo}.
123  * </p>
124  * </li>
125  * </ul>
126  * <h3>Retrieving window content</h3>
127  * <p>
128  * A service can specify in its declaration that it can retrieve the active window
129  * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
130  * declaring this capability requires that the service declares its configuration via
131  * an XML resource referenced by {@link #SERVICE_META_DATA}.
132  * </p>
133  * <p>
134  * For security purposes an accessibility service can retrieve only the content of the
135  * currently active window. The currently active window is defined as the window from
136  * which was fired the last event of the following types:
137  * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
138  * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
139  * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
140  * In other words, the last window that was shown or the last window that the user has touched
141  * during touch exploration.
142  * </p>
143  * <p>
144  * The entry point for retrieving window content is through calling
145  * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
146  * event of the above types or a previous event from the same window
147  * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
148  * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
149  * window content which represented as a tree of such objects.
150  * </p>
151  * <p class="note">
152  * <strong>Note</strong> An accessibility service may have requested to be notified for
153  * a subset of the event types, thus be unaware that the active window has changed. Therefore
154  * accessibility service that would like to retrieve window content should:
155  * <ul>
156  * <li>
157  * Register for all event types with no notification timeout and keep track for the active
158  * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
159  * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
160  * methods on the latter.
161  * </li>
162  * <li>
163  * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
164  * active window has changed and the service did not get the accessibility event yet. Note
165  * that it is possible to have a retrieval method failing even adopting the strategy
166  * specified in the previous bullet because the accessibility event dispatch is asynchronous
167  * and crosses process boundaries.
168  * </li>
169  * </ul>
170  * </p>
171  * <h3>Notification strategy</h3>
172  * <p>
173  * For each feedback type only one accessibility service is notified. Services are notified
174  * in the order of registration. Hence, if two services are registered for the same
175  * feedback type in the same package the first one wins. It is possible however, to
176  * register a service as the default one for a given feedback type. In such a case this
177  * service is invoked if no other service was interested in the event. In other words, default
178  * services do not compete with other services and are notified last regardless of the
179  * registration order. This enables "generic" accessibility services that work reasonably
180  * well with most applications to coexist with "polished" ones that are targeted for
181  * specific applications.
182  * </p>
183  * <p class="note">
184  * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
185  * events to the client too frequently since this is accomplished via an expensive
186  * interprocess call. One can think of the timeout as a criteria to determine when
187  * event generation has settled down.</p>
188  * <h3>Event types</h3>
189  * <ul>
190  * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}</li>
191  * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}</li>
192  * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}</li>
193  * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}</li>
194  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}</li>
195  * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}</li>
196  * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}</li>
197  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}</li>
198  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}</li>
199  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}</li>
200  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}</li>
201  * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}</li>
202  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}</li>
203  * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}</li>
204  * <li>{@link AccessibilityEvent#TYPE_ANNOUNCEMENT}</li>
205  * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_START}</li>
206  * <li>{@link AccessibilityEvent#TYPE_GESTURE_DETECTION_END}</li>
207  * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_START}</li>
208  * <li>{@link AccessibilityEvent#TYPE_TOUCH_INTERACTION_END}</li>
209  * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED}</li>
210  * <li>{@link AccessibilityEvent#TYPE_WINDOWS_CHANGED}</li>
211  * <li>{@link AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED}</li>
212  * </ul>
213  * <h3>Feedback types</h3>
214  * <ul>
215  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
216  * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}</li>
217  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}</li>
218  * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}</li>
219  * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}</li>
220  * <li>{@link AccessibilityServiceInfo#FEEDBACK_BRAILLE}</li>
221  * </ul>
222  * @see AccessibilityEvent
223  * @see AccessibilityServiceInfo
224  * @see android.view.accessibility.AccessibilityManager
225  */
226 public abstract class AccessibilityService extends Service {
227 
228     /**
229      * The user has performed a swipe up gesture on the touch screen.
230      */
231     public static final int GESTURE_SWIPE_UP = 1;
232 
233     /**
234      * The user has performed a swipe down gesture on the touch screen.
235      */
236     public static final int GESTURE_SWIPE_DOWN = 2;
237 
238     /**
239      * The user has performed a swipe left gesture on the touch screen.
240      */
241     public static final int GESTURE_SWIPE_LEFT = 3;
242 
243     /**
244      * The user has performed a swipe right gesture on the touch screen.
245      */
246     public static final int GESTURE_SWIPE_RIGHT = 4;
247 
248     /**
249      * The user has performed a swipe left and right gesture on the touch screen.
250      */
251     public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
252 
253     /**
254      * The user has performed a swipe right and left gesture on the touch screen.
255      */
256     public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
257 
258     /**
259      * The user has performed a swipe up and down gesture on the touch screen.
260      */
261     public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
262 
263     /**
264      * The user has performed a swipe down and up gesture on the touch screen.
265      */
266     public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
267 
268     /**
269      * The user has performed a left and up gesture on the touch screen.
270      */
271     public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
272 
273     /**
274      * The user has performed a left and down gesture on the touch screen.
275      */
276     public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
277 
278     /**
279      * The user has performed a right and up gesture on the touch screen.
280      */
281     public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
282 
283     /**
284      * The user has performed a right and down gesture on the touch screen.
285      */
286     public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
287 
288     /**
289      * The user has performed an up and left gesture on the touch screen.
290      */
291     public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
292 
293     /**
294      * The user has performed an up and right gesture on the touch screen.
295      */
296     public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
297 
298     /**
299      * The user has performed an down and left gesture on the touch screen.
300      */
301     public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
302 
303     /**
304      * The user has performed an down and right gesture on the touch screen.
305      */
306     public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
307 
308     /**
309      * The {@link Intent} that must be declared as handled by the service.
310      */
311     public static final String SERVICE_INTERFACE =
312         "android.accessibilityservice.AccessibilityService";
313 
314     /**
315      * Name under which an AccessibilityService component publishes information
316      * about itself. This meta-data must reference an XML resource containing an
317      * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
318      * tag. This is a a sample XML file configuring an accessibility service:
319      * <pre> &lt;accessibility-service
320      *     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
321      *     android:packageNames="foo.bar, foo.baz"
322      *     android:accessibilityFeedbackType="feedbackSpoken"
323      *     android:notificationTimeout="100"
324      *     android:accessibilityFlags="flagDefault"
325      *     android:settingsActivity="foo.bar.TestBackActivity"
326      *     android:canRetrieveWindowContent="true"
327      *     android:canRequestTouchExplorationMode="true"
328      *     android:canRequestEnhancedWebAccessibility="true"
329      *     . . .
330      * /&gt;</pre>
331      */
332     public static final String SERVICE_META_DATA = "android.accessibilityservice";
333 
334     /**
335      * Action to go back.
336      */
337     public static final int GLOBAL_ACTION_BACK = 1;
338 
339     /**
340      * Action to go home.
341      */
342     public static final int GLOBAL_ACTION_HOME = 2;
343 
344     /**
345      * Action to open the recent apps.
346      */
347     public static final int GLOBAL_ACTION_RECENTS = 3;
348 
349     /**
350      * Action to open the notifications.
351      */
352     public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
353 
354     /**
355      * Action to open the quick settings.
356      */
357     public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5;
358 
359     /**
360      * Action to open the power long-press dialog.
361      */
362     public static final int GLOBAL_ACTION_POWER_DIALOG = 6;
363 
364     private static final String LOG_TAG = "AccessibilityService";
365 
366     /**
367      * @hide
368      */
369     public interface Callbacks {
onAccessibilityEvent(AccessibilityEvent event)370         public void onAccessibilityEvent(AccessibilityEvent event);
onInterrupt()371         public void onInterrupt();
onServiceConnected()372         public void onServiceConnected();
init(int connectionId, IBinder windowToken)373         public void init(int connectionId, IBinder windowToken);
onGesture(int gestureId)374         public boolean onGesture(int gestureId);
onKeyEvent(KeyEvent event)375         public boolean onKeyEvent(KeyEvent event);
376     }
377 
378     private int mConnectionId;
379 
380     private AccessibilityServiceInfo mInfo;
381 
382     private IBinder mWindowToken;
383 
384     private WindowManager mWindowManager;
385 
386     /**
387      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
388      *
389      * @param event An event.
390      */
onAccessibilityEvent(AccessibilityEvent event)391     public abstract void onAccessibilityEvent(AccessibilityEvent event);
392 
393     /**
394      * Callback for interrupting the accessibility feedback.
395      */
onInterrupt()396     public abstract void onInterrupt();
397 
398     /**
399      * This method is a part of the {@link AccessibilityService} lifecycle and is
400      * called after the system has successfully bound to the service. If is
401      * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
402      *
403      * @see AccessibilityServiceInfo
404      * @see #setServiceInfo(AccessibilityServiceInfo)
405      */
onServiceConnected()406     protected void onServiceConnected() {
407 
408     }
409 
410     /**
411      * Called by the system when the user performs a specific gesture on the
412      * touch screen.
413      *
414      * <strong>Note:</strong> To receive gestures an accessibility service must
415      * request that the device is in touch exploration mode by setting the
416      * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
417      * flag.
418      *
419      * @param gestureId The unique id of the performed gesture.
420      *
421      * @return Whether the gesture was handled.
422      *
423      * @see #GESTURE_SWIPE_UP
424      * @see #GESTURE_SWIPE_UP_AND_LEFT
425      * @see #GESTURE_SWIPE_UP_AND_DOWN
426      * @see #GESTURE_SWIPE_UP_AND_RIGHT
427      * @see #GESTURE_SWIPE_DOWN
428      * @see #GESTURE_SWIPE_DOWN_AND_LEFT
429      * @see #GESTURE_SWIPE_DOWN_AND_UP
430      * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
431      * @see #GESTURE_SWIPE_LEFT
432      * @see #GESTURE_SWIPE_LEFT_AND_UP
433      * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
434      * @see #GESTURE_SWIPE_LEFT_AND_DOWN
435      * @see #GESTURE_SWIPE_RIGHT
436      * @see #GESTURE_SWIPE_RIGHT_AND_UP
437      * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
438      * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
439      */
onGesture(int gestureId)440     protected boolean onGesture(int gestureId) {
441         return false;
442     }
443 
444     /**
445      * Callback that allows an accessibility service to observe the key events
446      * before they are passed to the rest of the system. This means that the events
447      * are first delivered here before they are passed to the device policy, the
448      * input method, or applications.
449      * <p>
450      * <strong>Note:</strong> It is important that key events are handled in such
451      * a way that the event stream that would be passed to the rest of the system
452      * is well-formed. For example, handling the down event but not the up event
453      * and vice versa would generate an inconsistent event stream.
454      * </p>
455      * <p>
456      * <strong>Note:</strong> The key events delivered in this method are copies
457      * and modifying them will have no effect on the events that will be passed
458      * to the system. This method is intended to perform purely filtering
459      * functionality.
460      * <p>
461      *
462      * @param event The event to be processed.
463      * @return If true then the event will be consumed and not delivered to
464      *         applications, otherwise it will be delivered as usual.
465      */
onKeyEvent(KeyEvent event)466     protected boolean onKeyEvent(KeyEvent event) {
467         return false;
468     }
469 
470     /**
471      * Gets the windows on the screen. This method returns only the windows
472      * that a sighted user can interact with, as opposed to all windows.
473      * For example, if there is a modal dialog shown and the user cannot touch
474      * anything behind it, then only the modal window will be reported
475      * (assuming it is the top one). For convenience the returned windows
476      * are ordered in a descending layer order, which is the windows that
477      * are higher in the Z-order are reported first. Since the user can always
478      * interact with the window that has input focus by typing, the focused
479      * window is always returned (even if covered by a modal window).
480      * <p>
481      * <strong>Note:</strong> In order to access the windows your service has
482      * to declare the capability to retrieve window content by setting the
483      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
484      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
485      * Also the service has to opt-in to retrieve the interactive windows by
486      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
487      * flag.
488      * </p>
489      *
490      * @return The windows if there are windows and the service is can retrieve
491      *         them, otherwise an empty list.
492      */
getWindows()493     public List<AccessibilityWindowInfo> getWindows() {
494         return AccessibilityInteractionClient.getInstance().getWindows(mConnectionId);
495     }
496 
497     /**
498      * Gets the root node in the currently active window if this service
499      * can retrieve window content. The active window is the one that the user
500      * is currently touching or the window with input focus, if the user is not
501      * touching any window.
502      * <p>
503      * <strong>Note:</strong> In order to access the root node your service has
504      * to declare the capability to retrieve window content by setting the
505      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
506      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
507      * </p>
508      *
509      * @return The root node if this service can retrieve window content.
510      */
getRootInActiveWindow()511     public AccessibilityNodeInfo getRootInActiveWindow() {
512         return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
513     }
514 
515     /**
516      * Performs a global action. Such an action can be performed
517      * at any moment regardless of the current application or user
518      * location in that application. For example going back, going
519      * home, opening recents, etc.
520      *
521      * @param action The action to perform.
522      * @return Whether the action was successfully performed.
523      *
524      * @see #GLOBAL_ACTION_BACK
525      * @see #GLOBAL_ACTION_HOME
526      * @see #GLOBAL_ACTION_NOTIFICATIONS
527      * @see #GLOBAL_ACTION_RECENTS
528      */
performGlobalAction(int action)529     public final boolean performGlobalAction(int action) {
530         IAccessibilityServiceConnection connection =
531             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
532         if (connection != null) {
533             try {
534                 return connection.performGlobalAction(action);
535             } catch (RemoteException re) {
536                 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
537             }
538         }
539         return false;
540     }
541 
542     /**
543      * Find the view that has the specified focus type. The search is performed
544      * across all windows.
545      * <p>
546      * <strong>Note:</strong> In order to access the windows your service has
547      * to declare the capability to retrieve window content by setting the
548      * {@link android.R.styleable#AccessibilityService_canRetrieveWindowContent}
549      * property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
550      * Also the service has to opt-in to retrieve the interactive windows by
551      * setting the {@link AccessibilityServiceInfo#FLAG_RETRIEVE_INTERACTIVE_WINDOWS}
552      * flag.Otherwise, the search will be performed only in the active window.
553      * </p>
554      *
555      * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
556      *         {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
557      * @return The node info of the focused view or null.
558      *
559      * @see AccessibilityNodeInfo#FOCUS_INPUT
560      * @see AccessibilityNodeInfo#FOCUS_ACCESSIBILITY
561      */
findFocus(int focus)562     public AccessibilityNodeInfo findFocus(int focus) {
563         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId,
564                 AccessibilityNodeInfo.ANY_WINDOW_ID, AccessibilityNodeInfo.ROOT_NODE_ID, focus);
565     }
566 
567     /**
568      * Gets the an {@link AccessibilityServiceInfo} describing this
569      * {@link AccessibilityService}. This method is useful if one wants
570      * to change some of the dynamically configurable properties at
571      * runtime.
572      *
573      * @return The accessibility service info.
574      *
575      * @see AccessibilityServiceInfo
576      */
getServiceInfo()577     public final AccessibilityServiceInfo getServiceInfo() {
578         IAccessibilityServiceConnection connection =
579             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
580         if (connection != null) {
581             try {
582                 return connection.getServiceInfo();
583             } catch (RemoteException re) {
584                 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
585             }
586         }
587         return null;
588     }
589 
590     /**
591      * Sets the {@link AccessibilityServiceInfo} that describes this service.
592      * <p>
593      * Note: You can call this method any time but the info will be picked up after
594      *       the system has bound to this service and when this method is called thereafter.
595      *
596      * @param info The info.
597      */
setServiceInfo(AccessibilityServiceInfo info)598     public final void setServiceInfo(AccessibilityServiceInfo info) {
599         mInfo = info;
600         sendServiceInfo();
601     }
602 
603     /**
604      * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
605      * properly set and there is an {@link IAccessibilityServiceConnection} to the
606      * AccessibilityManagerService.
607      */
sendServiceInfo()608     private void sendServiceInfo() {
609         IAccessibilityServiceConnection connection =
610             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
611         if (mInfo != null && connection != null) {
612             try {
613                 connection.setServiceInfo(mInfo);
614                 mInfo = null;
615                 AccessibilityInteractionClient.getInstance().clearCache();
616             } catch (RemoteException re) {
617                 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
618             }
619         }
620     }
621 
622     @Override
getSystemService(@erviceName @onNull String name)623     public Object getSystemService(@ServiceName @NonNull String name) {
624         if (getBaseContext() == null) {
625             throw new IllegalStateException(
626                     "System services not available to Activities before onCreate()");
627         }
628 
629         // Guarantee that we always return the same window manager instance.
630         if (WINDOW_SERVICE.equals(name)) {
631             if (mWindowManager == null) {
632                 mWindowManager = (WindowManager) getBaseContext().getSystemService(name);
633             }
634             return mWindowManager;
635         }
636         return super.getSystemService(name);
637     }
638 
639     /**
640      * Implement to return the implementation of the internal accessibility
641      * service interface.
642      */
643     @Override
onBind(Intent intent)644     public final IBinder onBind(Intent intent) {
645         return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
646             @Override
647             public void onServiceConnected() {
648                 AccessibilityService.this.onServiceConnected();
649             }
650 
651             @Override
652             public void onInterrupt() {
653                 AccessibilityService.this.onInterrupt();
654             }
655 
656             @Override
657             public void onAccessibilityEvent(AccessibilityEvent event) {
658                 AccessibilityService.this.onAccessibilityEvent(event);
659             }
660 
661             @Override
662             public void init(int connectionId, IBinder windowToken) {
663                 mConnectionId = connectionId;
664                 mWindowToken = windowToken;
665 
666                 // The client may have already obtained the window manager, so
667                 // update the default token on whatever manager we gave them.
668                 final WindowManagerImpl wm = (WindowManagerImpl) getSystemService(WINDOW_SERVICE);
669                 wm.setDefaultToken(windowToken);
670             }
671 
672             @Override
673             public boolean onGesture(int gestureId) {
674                 return AccessibilityService.this.onGesture(gestureId);
675             }
676 
677             @Override
678             public boolean onKeyEvent(KeyEvent event) {
679                 return AccessibilityService.this.onKeyEvent(event);
680             }
681         });
682     }
683 
684     /**
685      * Implements the internal {@link IAccessibilityServiceClient} interface to convert
686      * incoming calls to it back to calls on an {@link AccessibilityService}.
687      *
688      * @hide
689      */
690     public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
691             implements HandlerCaller.Callback {
692         private static final int DO_INIT = 1;
693         private static final int DO_ON_INTERRUPT = 2;
694         private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
695         private static final int DO_ON_GESTURE = 4;
696         private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
697         private static final int DO_ON_KEY_EVENT = 6;
698 
699         private final HandlerCaller mCaller;
700 
701         private final Callbacks mCallback;
702 
703         private int mConnectionId;
704 
705         public IAccessibilityServiceClientWrapper(Context context, Looper looper,
706                 Callbacks callback) {
707             mCallback = callback;
708             mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
709         }
710 
711         public void init(IAccessibilityServiceConnection connection, int connectionId,
712                 IBinder windowToken) {
713             Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
714                     connection, windowToken);
715             mCaller.sendMessage(message);
716         }
717 
718         public void onInterrupt() {
719             Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
720             mCaller.sendMessage(message);
721         }
722 
723         public void onAccessibilityEvent(AccessibilityEvent event) {
724             Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
725             mCaller.sendMessage(message);
726         }
727 
728         public void onGesture(int gestureId) {
729             Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
730             mCaller.sendMessage(message);
731         }
732 
733         public void clearAccessibilityCache() {
734             Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_CACHE);
735             mCaller.sendMessage(message);
736         }
737 
738         @Override
739         public void onKeyEvent(KeyEvent event, int sequence) {
740             Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event);
741             mCaller.sendMessage(message);
742         }
743 
744         @Override
745         public void executeMessage(Message message) {
746             switch (message.what) {
747                 case DO_ON_ACCESSIBILITY_EVENT: {
748                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
749                     if (event != null) {
750                         AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
751                         mCallback.onAccessibilityEvent(event);
752                         // Make sure the event is recycled.
753                         try {
754                             event.recycle();
755                         } catch (IllegalStateException ise) {
756                             /* ignore - best effort */
757                         }
758                     }
759                 } return;
760 
761                 case DO_ON_INTERRUPT: {
762                     mCallback.onInterrupt();
763                 } return;
764 
765                 case DO_INIT: {
766                     mConnectionId = message.arg1;
767                     SomeArgs args = (SomeArgs) message.obj;
768                     IAccessibilityServiceConnection connection =
769                             (IAccessibilityServiceConnection) args.arg1;
770                     IBinder windowToken = (IBinder) args.arg2;
771                     args.recycle();
772                     if (connection != null) {
773                         AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
774                                 connection);
775                         mCallback.init(mConnectionId, windowToken);
776                         mCallback.onServiceConnected();
777                     } else {
778                         AccessibilityInteractionClient.getInstance().removeConnection(
779                                 mConnectionId);
780                         mConnectionId = AccessibilityInteractionClient.NO_ID;
781                         AccessibilityInteractionClient.getInstance().clearCache();
782                         mCallback.init(AccessibilityInteractionClient.NO_ID, null);
783                     }
784                 } return;
785 
786                 case DO_ON_GESTURE: {
787                     final int gestureId = message.arg1;
788                     mCallback.onGesture(gestureId);
789                 } return;
790 
791                 case DO_CLEAR_ACCESSIBILITY_CACHE: {
792                     AccessibilityInteractionClient.getInstance().clearCache();
793                 } return;
794 
795                 case DO_ON_KEY_EVENT: {
796                     KeyEvent event = (KeyEvent) message.obj;
797                     try {
798                         IAccessibilityServiceConnection connection = AccessibilityInteractionClient
799                                 .getInstance().getConnection(mConnectionId);
800                         if (connection != null) {
801                             final boolean result = mCallback.onKeyEvent(event);
802                             final int sequence = message.arg1;
803                             try {
804                                 connection.setOnKeyEventResult(result, sequence);
805                             } catch (RemoteException re) {
806                                 /* ignore */
807                             }
808                         }
809                     } finally {
810                         // Make sure the event is recycled.
811                         try {
812                             event.recycle();
813                         } catch (IllegalStateException ise) {
814                             /* ignore - best effort */
815                         }
816                     }
817                 } return;
818 
819                 default :
820                     Log.w(LOG_TAG, "Unknown message type " + message.what);
821             }
822         }
823     }
824 }
825