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