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