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.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.accessibility.AccessibilityEvent;
     28 import android.view.accessibility.AccessibilityInteractionClient;
     29 import android.view.accessibility.AccessibilityNodeInfo;
     30 
     31 import com.android.internal.os.HandlerCaller;
     32 
     33 /**
     34  * An accessibility service runs in the background and receives callbacks by the system
     35  * when {@link AccessibilityEvent}s are fired. Such events denote some state transition
     36  * in the user interface, for example, the focus has changed, a button has been clicked,
     37  * etc. Such a service can optionally request the capability for querying the content
     38  * of the active window. Development of an accessibility service requires extending this
     39  * class and implementing its abstract methods.
     40  *
     41  * <div class="special reference">
     42  * <h3>Developer Guides</h3>
     43  * <p>For more information about creating AccessibilityServices, read the
     44  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     45  * developer guide.</p>
     46  * </div>
     47  *
     48  * <h3>Lifecycle</h3>
     49  * <p>
     50  * The lifecycle of an accessibility service is managed exclusively by the system and
     51  * follows the established service life cycle. Additionally, starting or stopping an
     52  * accessibility service is triggered exclusively by an explicit user action through
     53  * enabling or disabling it in the device settings. After the system binds to a service it
     54  * calls {@link AccessibilityService#onServiceConnected()}. This method can be
     55  * overriden by clients that want to perform post binding setup.
     56  * </p>
     57  * <h3>Declaration</h3>
     58  * <p>
     59  * An accessibility is declared as any other service in an AndroidManifest.xml but it
     60  * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
     61  * {@link android.content.Intent}. Failure to declare this intent will cause the system to
     62  * ignore the accessibility service. Additionally an accessibility service must request the
     63  * {@link android.Manifest.permission#BIND_ACCESSIBILITY_SERVICE} permission to ensure
     64  * that only the system
     65  * can bind to it. Failure to declare this intent will cause the system to ignore the
     66  * accessibility service. Following is an example declaration:
     67  * </p>
     68  * <pre> &lt;service android:name=".MyAccessibilityService"
     69  *         android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"&gt;
     70  *     &lt;intent-filter&gt;
     71  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
     72  *     &lt;/intent-filter&gt;
     73  *     . . .
     74  * &lt;/service&gt;</pre>
     75  * <h3>Configuration</h3>
     76  * <p>
     77  * An accessibility service can be configured to receive specific types of accessibility events,
     78  * listen only to specific packages, get events from each type only once in a given time frame,
     79  * retrieve window content, specify a settings activity, etc.
     80  * </p>
     81  * <p>
     82  * There are two approaches for configuring an accessibility service:
     83  * </p>
     84  * <ul>
     85  * <li>
     86  * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
     87  * the service. A service declaration with a meta-data tag is presented below:
     88  * <pre> &lt;service android:name=".MyAccessibilityService"&gt;
     89  *     &lt;intent-filter&gt;
     90  *         &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
     91  *     &lt;/intent-filter&gt;
     92  *     &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
     93  * &lt;/service&gt;</pre>
     94  * <p class="note">
     95  * <strong>Note:</strong> This approach enables setting all properties.
     96  * </p>
     97  * <p>
     98  * For more details refer to {@link #SERVICE_META_DATA} and
     99  * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>.
    100  * </p>
    101  * </li>
    102  * <li>
    103  * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
    104  * that this method can be called any time to dynamically change the service configuration.
    105  * <p class="note">
    106  * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
    107  * {@link AccessibilityServiceInfo#eventTypes},
    108  * {@link AccessibilityServiceInfo#feedbackType},
    109  * {@link AccessibilityServiceInfo#flags},
    110  * {@link AccessibilityServiceInfo#notificationTimeout},
    111  * {@link AccessibilityServiceInfo#packageNames}
    112  * </p>
    113  * <p>
    114  * For more details refer to {@link AccessibilityServiceInfo}.
    115  * </p>
    116  * </li>
    117  * </ul>
    118  * <h3>Retrieving window content</h3>
    119  * <p>
    120  * A service can specify in its declaration that it can retrieve the active window
    121  * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
    122  * declaring this capability requires that the service declares its configuration via
    123  * an XML resource referenced by {@link #SERVICE_META_DATA}.
    124  * </p>
    125  * <p>
    126  * For security purposes an accessibility service can retrieve only the content of the
    127  * currently active window. The currently active window is defined as the window from
    128  * which was fired the last event of the following types:
    129  * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
    130  * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
    131  * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
    132  * In other words, the last window that was shown or the last window that the user has touched
    133  * during touch exploration.
    134  * </p>
    135  * <p>
    136  * The entry point for retrieving window content is through calling
    137  * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
    138  * event of the above types or a previous event from the same window
    139  * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
    140  * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
    141  * window content which represented as a tree of such objects.
    142  * </p>
    143  * <p class="note">
    144  * <strong>Note</strong> An accessibility service may have requested to be notified for
    145  * a subset of the event types, thus be unaware that the active window has changed. Therefore
    146  * accessibility service that would like to retrieve window content should:
    147  * <ul>
    148  * <li>
    149  * Register for all event types with no notification timeout and keep track for the active
    150  * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
    151  * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
    152  * methods on the latter.
    153  * </li>
    154  * <li>
    155  * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
    156  * active window has changed and the service did not get the accessibility event yet. Note
    157  * that it is possible to have a retrieval method failing even adopting the strategy
    158  * specified in the previous bullet because the accessibility event dispatch is asynchronous
    159  * and crosses process boundaries.
    160  * </li>
    161  * </ul>
    162  * </p>
    163  * <h3>Notification strategy</h3>
    164  * <p>
    165  * For each feedback type only one accessibility service is notified. Services are notified
    166  * in the order of registration. Hence, if two services are registered for the same
    167  * feedback type in the same package the first one wins. It is possible however, to
    168  * register a service as the default one for a given feedback type. In such a case this
    169  * service is invoked if no other service was interested in the event. In other words, default
    170  * services do not compete with other services and are notified last regardless of the
    171  * registration order. This enables "generic" accessibility services that work reasonably
    172  * well with most applications to coexist with "polished" ones that are targeted for
    173  * specific applications.
    174  * </p>
    175  * <p class="note">
    176  * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
    177  * events to the client too frequently since this is accomplished via an expensive
    178  * interprocess call. One can think of the timeout as a criteria to determine when
    179  * event generation has settled down.</p>
    180  * <h3>Event types</h3>
    181  * <ul>
    182  * <li>{@link AccessibilityEvent#TYPE_VIEW_CLICKED}
    183  * <li>{@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}
    184  * <li>{@link AccessibilityEvent#TYPE_VIEW_FOCUSED}
    185  * <li>{@link AccessibilityEvent#TYPE_VIEW_SELECTED}
    186  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}
    187  * <li>{@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}
    188  * <li>{@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}
    189  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}
    190  * <li>{@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}
    191  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}
    192  * <li>{@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}
    193  * <li>{@link AccessibilityEvent#TYPE_VIEW_SCROLLED}
    194  * <li>{@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}
    195  * <li>{@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
    196  * </ul>
    197  * <h3>Feedback types</h3>
    198  * <ul>
    199  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}
    200  * <li>{@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}
    201  * <li>{@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}
    202  * <li>{@link AccessibilityServiceInfo#FEEDBACK_VISUAL}
    203  * <li>{@link AccessibilityServiceInfo#FEEDBACK_GENERIC}
    204  * </ul>
    205  * @see AccessibilityEvent
    206  * @see AccessibilityServiceInfo
    207  * @see android.view.accessibility.AccessibilityManager
    208  */
    209 public abstract class AccessibilityService extends Service {
    210 
    211     /**
    212      * The user has performed a swipe up gesture on the touch screen.
    213      */
    214     public static final int GESTURE_SWIPE_UP = 1;
    215 
    216     /**
    217      * The user has performed a swipe down gesture on the touch screen.
    218      */
    219     public static final int GESTURE_SWIPE_DOWN = 2;
    220 
    221     /**
    222      * The user has performed a swipe left gesture on the touch screen.
    223      */
    224     public static final int GESTURE_SWIPE_LEFT = 3;
    225 
    226     /**
    227      * The user has performed a swipe right gesture on the touch screen.
    228      */
    229     public static final int GESTURE_SWIPE_RIGHT = 4;
    230 
    231     /**
    232      * The user has performed a swipe left and right gesture on the touch screen.
    233      */
    234     public static final int GESTURE_SWIPE_LEFT_AND_RIGHT = 5;
    235 
    236     /**
    237      * The user has performed a swipe right and left gesture on the touch screen.
    238      */
    239     public static final int GESTURE_SWIPE_RIGHT_AND_LEFT = 6;
    240 
    241     /**
    242      * The user has performed a swipe up and down gesture on the touch screen.
    243      */
    244     public static final int GESTURE_SWIPE_UP_AND_DOWN = 7;
    245 
    246     /**
    247      * The user has performed a swipe down and up gesture on the touch screen.
    248      */
    249     public static final int GESTURE_SWIPE_DOWN_AND_UP = 8;
    250 
    251     /**
    252      * The user has performed a left and up gesture on the touch screen.
    253      */
    254     public static final int GESTURE_SWIPE_LEFT_AND_UP = 9;
    255 
    256     /**
    257      * The user has performed a left and down gesture on the touch screen.
    258      */
    259     public static final int GESTURE_SWIPE_LEFT_AND_DOWN = 10;
    260 
    261     /**
    262      * The user has performed a right and up gesture on the touch screen.
    263      */
    264     public static final int GESTURE_SWIPE_RIGHT_AND_UP = 11;
    265 
    266     /**
    267      * The user has performed a right and down gesture on the touch screen.
    268      */
    269     public static final int GESTURE_SWIPE_RIGHT_AND_DOWN = 12;
    270 
    271     /**
    272      * The user has performed an up and left gesture on the touch screen.
    273      */
    274     public static final int GESTURE_SWIPE_UP_AND_LEFT = 13;
    275 
    276     /**
    277      * The user has performed an up and right gesture on the touch screen.
    278      */
    279     public static final int GESTURE_SWIPE_UP_AND_RIGHT = 14;
    280 
    281     /**
    282      * The user has performed an down and left gesture on the touch screen.
    283      */
    284     public static final int GESTURE_SWIPE_DOWN_AND_LEFT = 15;
    285 
    286     /**
    287      * The user has performed an down and right gesture on the touch screen.
    288      */
    289     public static final int GESTURE_SWIPE_DOWN_AND_RIGHT = 16;
    290 
    291     /**
    292      * The {@link Intent} that must be declared as handled by the service.
    293      */
    294     public static final String SERVICE_INTERFACE =
    295         "android.accessibilityservice.AccessibilityService";
    296 
    297     /**
    298      * Name under which an AccessibilityService component publishes information
    299      * about itself. This meta-data must reference an XML resource containing an
    300      * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
    301      * tag. This is a a sample XML file configuring an accessibility service:
    302      * <pre> &lt;accessibility-service
    303      *     android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
    304      *     android:packageNames="foo.bar, foo.baz"
    305      *     android:accessibilityFeedbackType="feedbackSpoken"
    306      *     android:notificationTimeout="100"
    307      *     android:accessibilityFlags="flagDefault"
    308      *     android:settingsActivity="foo.bar.TestBackActivity"
    309      *     android:canRetrieveWindowContent="true"
    310      *     . . .
    311      * /&gt;</pre>
    312      */
    313     public static final String SERVICE_META_DATA = "android.accessibilityservice";
    314 
    315     /**
    316      * Action to go back.
    317      */
    318     public static final int GLOBAL_ACTION_BACK = 1;
    319 
    320     /**
    321      * Action to go home.
    322      */
    323     public static final int GLOBAL_ACTION_HOME = 2;
    324 
    325     /**
    326      * Action to open the recents.
    327      */
    328     public static final int GLOBAL_ACTION_RECENTS = 3;
    329 
    330     /**
    331      * Action to open the notifications.
    332      */
    333     public static final int GLOBAL_ACTION_NOTIFICATIONS = 4;
    334 
    335     private static final String LOG_TAG = "AccessibilityService";
    336 
    337     interface Callbacks {
    338         public void onAccessibilityEvent(AccessibilityEvent event);
    339         public void onInterrupt();
    340         public void onServiceConnected();
    341         public void onSetConnectionId(int connectionId);
    342         public boolean onGesture(int gestureId);
    343     }
    344 
    345     private int mConnectionId;
    346 
    347     private AccessibilityServiceInfo mInfo;
    348 
    349     /**
    350      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
    351      *
    352      * @param event An event.
    353      */
    354     public abstract void onAccessibilityEvent(AccessibilityEvent event);
    355 
    356     /**
    357      * Callback for interrupting the accessibility feedback.
    358      */
    359     public abstract void onInterrupt();
    360 
    361     /**
    362      * This method is a part of the {@link AccessibilityService} lifecycle and is
    363      * called after the system has successfully bound to the service. If is
    364      * convenient to use this method for setting the {@link AccessibilityServiceInfo}.
    365      *
    366      * @see AccessibilityServiceInfo
    367      * @see #setServiceInfo(AccessibilityServiceInfo)
    368      */
    369     protected void onServiceConnected() {
    370 
    371     }
    372 
    373     /**
    374      * Called by the system when the user performs a specific gesture on the
    375      * touch screen.
    376      *
    377      * <strong>Note:</strong> To receive gestures an accessibility service must
    378      * request that the device is in touch exploration mode by setting the
    379      * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}
    380      * flag.
    381      *
    382      * @param gestureId The unique id of the performed gesture.
    383      *
    384      * @return Whether the gesture was handled.
    385      *
    386      * @see #GESTURE_SWIPE_UP
    387      * @see #GESTURE_SWIPE_UP_AND_LEFT
    388      * @see #GESTURE_SWIPE_UP_AND_DOWN
    389      * @see #GESTURE_SWIPE_UP_AND_RIGHT
    390      * @see #GESTURE_SWIPE_DOWN
    391      * @see #GESTURE_SWIPE_DOWN_AND_LEFT
    392      * @see #GESTURE_SWIPE_DOWN_AND_UP
    393      * @see #GESTURE_SWIPE_DOWN_AND_RIGHT
    394      * @see #GESTURE_SWIPE_LEFT
    395      * @see #GESTURE_SWIPE_LEFT_AND_UP
    396      * @see #GESTURE_SWIPE_LEFT_AND_RIGHT
    397      * @see #GESTURE_SWIPE_LEFT_AND_DOWN
    398      * @see #GESTURE_SWIPE_RIGHT
    399      * @see #GESTURE_SWIPE_RIGHT_AND_UP
    400      * @see #GESTURE_SWIPE_RIGHT_AND_LEFT
    401      * @see #GESTURE_SWIPE_RIGHT_AND_DOWN
    402      */
    403     protected boolean onGesture(int gestureId) {
    404         return false;
    405     }
    406 
    407     /**
    408      * Gets the root node in the currently active window if this service
    409      * can retrieve window content.
    410      *
    411      * @return The root node if this service can retrieve window content.
    412      */
    413     public AccessibilityNodeInfo getRootInActiveWindow() {
    414         return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId);
    415     }
    416 
    417     /**
    418      * Performs a global action. Such an action can be performed
    419      * at any moment regardless of the current application or user
    420      * location in that application. For example going back, going
    421      * home, opening recents, etc.
    422      *
    423      * @param action The action to perform.
    424      * @return Whether the action was successfully performed.
    425      *
    426      * @see #GLOBAL_ACTION_BACK
    427      * @see #GLOBAL_ACTION_HOME
    428      * @see #GLOBAL_ACTION_NOTIFICATIONS
    429      * @see #GLOBAL_ACTION_RECENTS
    430      */
    431     public final boolean performGlobalAction(int action) {
    432         IAccessibilityServiceConnection connection =
    433             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
    434         if (connection != null) {
    435             try {
    436                 return connection.performGlobalAction(action);
    437             } catch (RemoteException re) {
    438                 Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
    439             }
    440         }
    441         return false;
    442     }
    443 
    444     /**
    445      * Gets the an {@link AccessibilityServiceInfo} describing this
    446      * {@link AccessibilityService}. This method is useful if one wants
    447      * to change some of the dynamically configurable properties at
    448      * runtime.
    449      *
    450      * @return The accessibility service info.
    451      *
    452      * @see AccessibilityNodeInfo
    453      */
    454     public final AccessibilityServiceInfo getServiceInfo() {
    455         IAccessibilityServiceConnection connection =
    456             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
    457         if (connection != null) {
    458             try {
    459                 return connection.getServiceInfo();
    460             } catch (RemoteException re) {
    461                 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
    462             }
    463         }
    464         return null;
    465     }
    466 
    467     /**
    468      * Sets the {@link AccessibilityServiceInfo} that describes this service.
    469      * <p>
    470      * Note: You can call this method any time but the info will be picked up after
    471      *       the system has bound to this service and when this method is called thereafter.
    472      *
    473      * @param info The info.
    474      */
    475     public final void setServiceInfo(AccessibilityServiceInfo info) {
    476         mInfo = info;
    477         sendServiceInfo();
    478     }
    479 
    480     /**
    481      * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
    482      * properly set and there is an {@link IAccessibilityServiceConnection} to the
    483      * AccessibilityManagerService.
    484      */
    485     private void sendServiceInfo() {
    486         IAccessibilityServiceConnection connection =
    487             AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
    488         if (mInfo != null && connection != null) {
    489             try {
    490                 connection.setServiceInfo(mInfo);
    491                 mInfo = null;
    492                 AccessibilityInteractionClient.getInstance().clearCache();
    493             } catch (RemoteException re) {
    494                 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
    495             }
    496         }
    497     }
    498 
    499     /**
    500      * Implement to return the implementation of the internal accessibility
    501      * service interface.
    502      */
    503     @Override
    504     public final IBinder onBind(Intent intent) {
    505         return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() {
    506             @Override
    507             public void onServiceConnected() {
    508                 AccessibilityService.this.onServiceConnected();
    509             }
    510 
    511             @Override
    512             public void onInterrupt() {
    513                 AccessibilityService.this.onInterrupt();
    514             }
    515 
    516             @Override
    517             public void onAccessibilityEvent(AccessibilityEvent event) {
    518                 AccessibilityService.this.onAccessibilityEvent(event);
    519             }
    520 
    521             @Override
    522             public void onSetConnectionId( int connectionId) {
    523                 mConnectionId = connectionId;
    524             }
    525 
    526             @Override
    527             public boolean onGesture(int gestureId) {
    528                 return AccessibilityService.this.onGesture(gestureId);
    529             }
    530         });
    531     }
    532 
    533     /**
    534      * Implements the internal {@link IAccessibilityServiceClient} interface to convert
    535      * incoming calls to it back to calls on an {@link AccessibilityService}.
    536      */
    537     static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
    538             implements HandlerCaller.Callback {
    539 
    540         static final int NO_ID = -1;
    541 
    542         private static final int DO_SET_SET_CONNECTION = 10;
    543         private static final int DO_ON_INTERRUPT = 20;
    544         private static final int DO_ON_ACCESSIBILITY_EVENT = 30;
    545         private static final int DO_ON_GESTURE = 40;
    546 
    547         private final HandlerCaller mCaller;
    548 
    549         private final Callbacks mCallback;
    550 
    551         public IAccessibilityServiceClientWrapper(Context context, Looper looper,
    552                 Callbacks callback) {
    553             mCallback = callback;
    554             mCaller = new HandlerCaller(context, looper, this);
    555         }
    556 
    557         public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
    558             Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId,
    559                     connection);
    560             mCaller.sendMessage(message);
    561         }
    562 
    563         public void onInterrupt() {
    564             Message message = mCaller.obtainMessage(DO_ON_INTERRUPT);
    565             mCaller.sendMessage(message);
    566         }
    567 
    568         public void onAccessibilityEvent(AccessibilityEvent event) {
    569             Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
    570             mCaller.sendMessage(message);
    571         }
    572 
    573         public void onGesture(int gestureId) {
    574             Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId);
    575             mCaller.sendMessage(message);
    576         }
    577 
    578         public void executeMessage(Message message) {
    579             switch (message.what) {
    580                 case DO_ON_ACCESSIBILITY_EVENT :
    581                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
    582                     if (event != null) {
    583                         AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
    584                         mCallback.onAccessibilityEvent(event);
    585                         event.recycle();
    586                     }
    587                     return;
    588                 case DO_ON_INTERRUPT :
    589                     mCallback.onInterrupt();
    590                     return;
    591                 case DO_SET_SET_CONNECTION :
    592                     final int connectionId = message.arg1;
    593                     IAccessibilityServiceConnection connection =
    594                         (IAccessibilityServiceConnection) message.obj;
    595                     if (connection != null) {
    596                         AccessibilityInteractionClient.getInstance().addConnection(connectionId,
    597                                 connection);
    598                         mCallback.onSetConnectionId(connectionId);
    599                         mCallback.onServiceConnected();
    600                     } else {
    601                         AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
    602                         mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
    603                     }
    604                     return;
    605                 case DO_ON_GESTURE :
    606                     final int gestureId = message.arg1;
    607                     mCallback.onGesture(gestureId);
    608                     return;
    609                 default :
    610                     Log.w(LOG_TAG, "Unknown message type " + message.what);
    611             }
    612         }
    613     }
    614 }
    615