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