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