1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.accessibilityservice; 18 19 import android.app.Service; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.IBinder; 23 import android.os.Looper; 24 import android.os.Message; 25 import android.os.RemoteException; 26 import android.util.Log; 27 import android.view.KeyEvent; 28 import android.view.accessibility.AccessibilityEvent; 29 import android.view.accessibility.AccessibilityInteractionClient; 30 import android.view.accessibility.AccessibilityNodeInfo; 31 32 import 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 */ 210 public 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 * android:canRequestTouchExplorationMode="true" 312 * android:canRequestEnhancedWebAccessibility="true" 313 * . . . 314 * /></pre> 315 */ 316 public static final String SERVICE_META_DATA = "android.accessibilityservice"; 317 318 /** 319 * Action to go back. 320 */ 321 public static final int GLOBAL_ACTION_BACK = 1; 322 323 /** 324 * Action to go home. 325 */ 326 public static final int GLOBAL_ACTION_HOME = 2; 327 328 /** 329 * Action to open the recent apps. 330 */ 331 public static final int GLOBAL_ACTION_RECENTS = 3; 332 333 /** 334 * Action to open the notifications. 335 */ 336 public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; 337 338 /** 339 * Action to open the quick settings. 340 */ 341 public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; 342 343 private static final String LOG_TAG = "AccessibilityService"; 344 345 /** 346 * @hide 347 */ 348 public interface Callbacks { 349 public void onAccessibilityEvent(AccessibilityEvent event); 350 public void onInterrupt(); 351 public void onServiceConnected(); 352 public void onSetConnectionId(int connectionId); 353 public boolean onGesture(int gestureId); 354 public boolean onKeyEvent(KeyEvent event); 355 } 356 357 private int mConnectionId; 358 359 private AccessibilityServiceInfo mInfo; 360 361 /** 362 * Callback for {@link android.view.accessibility.AccessibilityEvent}s. 363 * 364 * @param event An event. 365 */ 366 public abstract void onAccessibilityEvent(AccessibilityEvent event); 367 368 /** 369 * Callback for interrupting the accessibility feedback. 370 */ 371 public abstract void onInterrupt(); 372 373 /** 374 * This method is a part of the {@link AccessibilityService} lifecycle and is 375 * called after the system has successfully bound to the service. If is 376 * convenient to use this method for setting the {@link AccessibilityServiceInfo}. 377 * 378 * @see AccessibilityServiceInfo 379 * @see #setServiceInfo(AccessibilityServiceInfo) 380 */ 381 protected void onServiceConnected() { 382 383 } 384 385 /** 386 * Called by the system when the user performs a specific gesture on the 387 * touch screen. 388 * 389 * <strong>Note:</strong> To receive gestures an accessibility service must 390 * request that the device is in touch exploration mode by setting the 391 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} 392 * flag. 393 * 394 * @param gestureId The unique id of the performed gesture. 395 * 396 * @return Whether the gesture was handled. 397 * 398 * @see #GESTURE_SWIPE_UP 399 * @see #GESTURE_SWIPE_UP_AND_LEFT 400 * @see #GESTURE_SWIPE_UP_AND_DOWN 401 * @see #GESTURE_SWIPE_UP_AND_RIGHT 402 * @see #GESTURE_SWIPE_DOWN 403 * @see #GESTURE_SWIPE_DOWN_AND_LEFT 404 * @see #GESTURE_SWIPE_DOWN_AND_UP 405 * @see #GESTURE_SWIPE_DOWN_AND_RIGHT 406 * @see #GESTURE_SWIPE_LEFT 407 * @see #GESTURE_SWIPE_LEFT_AND_UP 408 * @see #GESTURE_SWIPE_LEFT_AND_RIGHT 409 * @see #GESTURE_SWIPE_LEFT_AND_DOWN 410 * @see #GESTURE_SWIPE_RIGHT 411 * @see #GESTURE_SWIPE_RIGHT_AND_UP 412 * @see #GESTURE_SWIPE_RIGHT_AND_LEFT 413 * @see #GESTURE_SWIPE_RIGHT_AND_DOWN 414 */ 415 protected boolean onGesture(int gestureId) { 416 return false; 417 } 418 419 /** 420 * Callback that allows an accessibility service to observe the key events 421 * before they are passed to the rest of the system. This means that the events 422 * are first delivered here before they are passed to the device policy, the 423 * input method, or applications. 424 * <p> 425 * <strong>Note:</strong> It is important that key events are handled in such 426 * a way that the event stream that would be passed to the rest of the system 427 * is well-formed. For example, handling the down event but not the up event 428 * and vice versa would generate an inconsistent event stream. 429 * </p> 430 * <p> 431 * <strong>Note:</strong> The key events delivered in this method are copies 432 * and modifying them will have no effect on the events that will be passed 433 * to the system. This method is intended to perform purely filtering 434 * functionality. 435 * <p> 436 * 437 * @param event The event to be processed. 438 * @return If true then the event will be consumed and not delivered to 439 * applications, otherwise it will be delivered as usual. 440 */ 441 protected boolean onKeyEvent(KeyEvent event) { 442 return false; 443 } 444 445 /** 446 * Gets the root node in the currently active window if this service 447 * can retrieve window content. 448 * 449 * @return The root node if this service can retrieve window content. 450 */ 451 public AccessibilityNodeInfo getRootInActiveWindow() { 452 return AccessibilityInteractionClient.getInstance().getRootInActiveWindow(mConnectionId); 453 } 454 455 /** 456 * Performs a global action. Such an action can be performed 457 * at any moment regardless of the current application or user 458 * location in that application. For example going back, going 459 * home, opening recents, etc. 460 * 461 * @param action The action to perform. 462 * @return Whether the action was successfully performed. 463 * 464 * @see #GLOBAL_ACTION_BACK 465 * @see #GLOBAL_ACTION_HOME 466 * @see #GLOBAL_ACTION_NOTIFICATIONS 467 * @see #GLOBAL_ACTION_RECENTS 468 */ 469 public final boolean performGlobalAction(int action) { 470 IAccessibilityServiceConnection connection = 471 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); 472 if (connection != null) { 473 try { 474 return connection.performGlobalAction(action); 475 } catch (RemoteException re) { 476 Log.w(LOG_TAG, "Error while calling performGlobalAction", re); 477 } 478 } 479 return false; 480 } 481 482 /** 483 * Gets the an {@link AccessibilityServiceInfo} describing this 484 * {@link AccessibilityService}. This method is useful if one wants 485 * to change some of the dynamically configurable properties at 486 * runtime. 487 * 488 * @return The accessibility service info. 489 * 490 * @see AccessibilityServiceInfo 491 */ 492 public final AccessibilityServiceInfo getServiceInfo() { 493 IAccessibilityServiceConnection connection = 494 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); 495 if (connection != null) { 496 try { 497 return connection.getServiceInfo(); 498 } catch (RemoteException re) { 499 Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re); 500 } 501 } 502 return null; 503 } 504 505 /** 506 * Sets the {@link AccessibilityServiceInfo} that describes this service. 507 * <p> 508 * Note: You can call this method any time but the info will be picked up after 509 * the system has bound to this service and when this method is called thereafter. 510 * 511 * @param info The info. 512 */ 513 public final void setServiceInfo(AccessibilityServiceInfo info) { 514 mInfo = info; 515 sendServiceInfo(); 516 } 517 518 /** 519 * Sets the {@link AccessibilityServiceInfo} for this service if the latter is 520 * properly set and there is an {@link IAccessibilityServiceConnection} to the 521 * AccessibilityManagerService. 522 */ 523 private void sendServiceInfo() { 524 IAccessibilityServiceConnection connection = 525 AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); 526 if (mInfo != null && connection != null) { 527 try { 528 connection.setServiceInfo(mInfo); 529 mInfo = null; 530 AccessibilityInteractionClient.getInstance().clearCache(); 531 } catch (RemoteException re) { 532 Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re); 533 } 534 } 535 } 536 537 /** 538 * Implement to return the implementation of the internal accessibility 539 * service interface. 540 */ 541 @Override 542 public final IBinder onBind(Intent intent) { 543 return new IAccessibilityServiceClientWrapper(this, getMainLooper(), new Callbacks() { 544 @Override 545 public void onServiceConnected() { 546 AccessibilityService.this.onServiceConnected(); 547 } 548 549 @Override 550 public void onInterrupt() { 551 AccessibilityService.this.onInterrupt(); 552 } 553 554 @Override 555 public void onAccessibilityEvent(AccessibilityEvent event) { 556 AccessibilityService.this.onAccessibilityEvent(event); 557 } 558 559 @Override 560 public void onSetConnectionId( int connectionId) { 561 mConnectionId = connectionId; 562 } 563 564 @Override 565 public boolean onGesture(int gestureId) { 566 return AccessibilityService.this.onGesture(gestureId); 567 } 568 569 @Override 570 public boolean onKeyEvent(KeyEvent event) { 571 return AccessibilityService.this.onKeyEvent(event); 572 } 573 }); 574 } 575 576 /** 577 * Implements the internal {@link IAccessibilityServiceClient} interface to convert 578 * incoming calls to it back to calls on an {@link AccessibilityService}. 579 * 580 * @hide 581 */ 582 public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub 583 implements HandlerCaller.Callback { 584 585 static final int NO_ID = -1; 586 587 private static final int DO_SET_SET_CONNECTION = 10; 588 private static final int DO_ON_INTERRUPT = 20; 589 private static final int DO_ON_ACCESSIBILITY_EVENT = 30; 590 private static final int DO_ON_GESTURE = 40; 591 private static final int DO_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE = 50; 592 private static final int DO_ON_KEY_EVENT = 60; 593 594 private final HandlerCaller mCaller; 595 596 private final Callbacks mCallback; 597 598 private int mConnectionId; 599 600 public IAccessibilityServiceClientWrapper(Context context, Looper looper, 601 Callbacks callback) { 602 mCallback = callback; 603 mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/); 604 } 605 606 public void setConnection(IAccessibilityServiceConnection connection, int connectionId) { 607 Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId, 608 connection); 609 mCaller.sendMessage(message); 610 } 611 612 public void onInterrupt() { 613 Message message = mCaller.obtainMessage(DO_ON_INTERRUPT); 614 mCaller.sendMessage(message); 615 } 616 617 public void onAccessibilityEvent(AccessibilityEvent event) { 618 Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event); 619 mCaller.sendMessage(message); 620 } 621 622 public void onGesture(int gestureId) { 623 Message message = mCaller.obtainMessageI(DO_ON_GESTURE, gestureId); 624 mCaller.sendMessage(message); 625 } 626 627 public void clearAccessibilityNodeInfoCache() { 628 Message message = mCaller.obtainMessage(DO_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE); 629 mCaller.sendMessage(message); 630 } 631 632 @Override 633 public void onKeyEvent(KeyEvent event, int sequence) { 634 Message message = mCaller.obtainMessageIO(DO_ON_KEY_EVENT, sequence, event); 635 mCaller.sendMessage(message); 636 } 637 638 public void executeMessage(Message message) { 639 switch (message.what) { 640 case DO_ON_ACCESSIBILITY_EVENT: { 641 AccessibilityEvent event = (AccessibilityEvent) message.obj; 642 if (event != null) { 643 AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event); 644 mCallback.onAccessibilityEvent(event); 645 event.recycle(); 646 } 647 } return; 648 case DO_ON_INTERRUPT: { 649 mCallback.onInterrupt(); 650 } return; 651 case DO_SET_SET_CONNECTION: { 652 mConnectionId = message.arg1; 653 IAccessibilityServiceConnection connection = 654 (IAccessibilityServiceConnection) message.obj; 655 if (connection != null) { 656 AccessibilityInteractionClient.getInstance().addConnection(mConnectionId, 657 connection); 658 mCallback.onSetConnectionId(mConnectionId); 659 mCallback.onServiceConnected(); 660 } else { 661 AccessibilityInteractionClient.getInstance().removeConnection(mConnectionId); 662 AccessibilityInteractionClient.getInstance().clearCache(); 663 mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID); 664 } 665 } return; 666 case DO_ON_GESTURE: { 667 final int gestureId = message.arg1; 668 mCallback.onGesture(gestureId); 669 } return; 670 case DO_CLEAR_ACCESSIBILITY_NODE_INFO_CACHE: { 671 AccessibilityInteractionClient.getInstance().clearCache(); 672 } return; 673 case DO_ON_KEY_EVENT: { 674 KeyEvent event = (KeyEvent) message.obj; 675 try { 676 IAccessibilityServiceConnection connection = AccessibilityInteractionClient 677 .getInstance().getConnection(mConnectionId); 678 if (connection != null) { 679 final boolean result = mCallback.onKeyEvent(event); 680 final int sequence = message.arg1; 681 try { 682 connection.setOnKeyEventResult(result, sequence); 683 } catch (RemoteException re) { 684 /* ignore */ 685 } 686 } 687 } finally { 688 event.recycle(); 689 } 690 } return; 691 default : 692 Log.w(LOG_TAG, "Unknown message type " + message.what); 693 } 694 } 695 } 696 } 697