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