Home | History | Annotate | Download | only in accessibilityservice
      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 {
    371         public void onAccessibilityEvent(AccessibilityEvent event);
    372         public void onInterrupt();
    373         public void onServiceConnected();
    374         public void init(int connectionId, IBinder windowToken);
    375         public boolean onGesture(int gestureId);
    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      */
    392     public abstract void onAccessibilityEvent(AccessibilityEvent event);
    393 
    394     /**
    395      * Callback for interrupting the accessibility feedback.
    396      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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
    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