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