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 static android.accessibilityservice.util.AccessibilityUtils.getFilteredHtmlText; 20 import static android.accessibilityservice.util.AccessibilityUtils.loadSafeAnimatedImage; 21 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; 22 23 import android.annotation.IntDef; 24 import android.annotation.IntRange; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.SystemApi; 28 import android.annotation.TestApi; 29 import android.compat.annotation.ChangeId; 30 import android.compat.annotation.EnabledAfter; 31 import android.compat.annotation.UnsupportedAppUsage; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManager.NameNotFoundException; 36 import android.content.pm.ResolveInfo; 37 import android.content.pm.ServiceInfo; 38 import android.content.res.Resources; 39 import android.content.res.TypedArray; 40 import android.content.res.XmlResourceParser; 41 import android.graphics.drawable.Drawable; 42 import android.hardware.fingerprint.FingerprintManager; 43 import android.os.Build; 44 import android.os.IBinder; 45 import android.os.Parcel; 46 import android.os.Parcelable; 47 import android.os.RemoteException; 48 import android.util.AttributeSet; 49 import android.util.SparseArray; 50 import android.util.TypedValue; 51 import android.util.Xml; 52 import android.view.InputDevice; 53 import android.view.View; 54 import android.view.accessibility.AccessibilityEvent; 55 import android.view.accessibility.AccessibilityNodeInfo; 56 57 import com.android.internal.R; 58 import com.android.internal.compat.IPlatformCompat; 59 60 import org.xmlpull.v1.XmlPullParser; 61 import org.xmlpull.v1.XmlPullParserException; 62 63 import java.io.IOException; 64 import java.lang.annotation.Retention; 65 import java.lang.annotation.RetentionPolicy; 66 import java.util.ArrayList; 67 import java.util.Collections; 68 import java.util.List; 69 70 /** 71 * This class describes an {@link AccessibilityService}. The system notifies an 72 * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s 73 * according to the information encapsulated in this class. 74 * 75 * <div class="special reference"> 76 * <h3>Developer Guides</h3> 77 * <p>For more information about creating AccessibilityServices, read the 78 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 79 * developer guide.</p> 80 * </div> 81 * 82 * @attr ref android.R.styleable#AccessibilityService_accessibilityEventTypes 83 * @attr ref android.R.styleable#AccessibilityService_accessibilityFeedbackType 84 * @attr ref android.R.styleable#AccessibilityService_accessibilityFlags 85 * @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents 86 * @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode 87 * @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent 88 * @attr ref android.R.styleable#AccessibilityService_intro 89 * @attr ref android.R.styleable#AccessibilityService_description 90 * @attr ref android.R.styleable#AccessibilityService_summary 91 * @attr ref android.R.styleable#AccessibilityService_notificationTimeout 92 * @attr ref android.R.styleable#AccessibilityService_packageNames 93 * @attr ref android.R.styleable#AccessibilityService_settingsActivity 94 * @attr ref android.R.styleable#AccessibilityService_tileService 95 * @attr ref android.R.styleable#AccessibilityService_nonInteractiveUiTimeout 96 * @attr ref android.R.styleable#AccessibilityService_interactiveUiTimeout 97 * @attr ref android.R.styleable#AccessibilityService_canTakeScreenshot 98 * @see AccessibilityService 99 * @see android.view.accessibility.AccessibilityEvent 100 * @see android.view.accessibility.AccessibilityManager 101 */ 102 public class AccessibilityServiceInfo implements Parcelable { 103 104 private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service"; 105 106 /** 107 * Capability: This accessibility service can retrieve the active window content. 108 * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent 109 */ 110 public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001; 111 112 /** 113 * Capability: This accessibility service can request touch exploration mode in which 114 * touched items are spoken aloud and the UI can be explored via gestures. 115 * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode 116 */ 117 public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002; 118 119 /** 120 * @deprecated No longer used 121 */ 122 public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004; 123 124 /** 125 * Capability: This accessibility service can request to filter the key event stream. 126 * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents 127 */ 128 public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008; 129 130 /** 131 * Capability: This accessibility service can control display magnification. 132 * @see android.R.styleable#AccessibilityService_canControlMagnification 133 */ 134 public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010; 135 136 /** 137 * Capability: This accessibility service can perform gestures. 138 * @see android.R.styleable#AccessibilityService_canPerformGestures 139 */ 140 public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020; 141 142 /** 143 * Capability: This accessibility service can capture gestures from the fingerprint sensor 144 * @see android.R.styleable#AccessibilityService_canRequestFingerprintGestures 145 */ 146 public static final int CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES = 0x00000040; 147 148 /** 149 * Capability: This accessibility service can take screenshot. 150 * @see android.R.styleable#AccessibilityService_canTakeScreenshot 151 */ 152 public static final int CAPABILITY_CAN_TAKE_SCREENSHOT = 0x00000080; 153 154 private static SparseArray<CapabilityInfo> sAvailableCapabilityInfos; 155 156 /** 157 * Denotes spoken feedback. 158 */ 159 public static final int FEEDBACK_SPOKEN = 0x0000001; 160 161 /** 162 * Denotes haptic feedback. 163 */ 164 public static final int FEEDBACK_HAPTIC = 0x0000002; 165 166 /** 167 * Denotes audible (not spoken) feedback. 168 */ 169 public static final int FEEDBACK_AUDIBLE = 0x0000004; 170 171 /** 172 * Denotes visual feedback. 173 */ 174 public static final int FEEDBACK_VISUAL = 0x0000008; 175 176 /** 177 * Denotes generic feedback. 178 */ 179 public static final int FEEDBACK_GENERIC = 0x0000010; 180 181 /** 182 * Denotes braille feedback. 183 */ 184 public static final int FEEDBACK_BRAILLE = 0x0000020; 185 186 /** 187 * Mask for all feedback types. 188 * 189 * @see #FEEDBACK_SPOKEN 190 * @see #FEEDBACK_HAPTIC 191 * @see #FEEDBACK_AUDIBLE 192 * @see #FEEDBACK_VISUAL 193 * @see #FEEDBACK_GENERIC 194 * @see #FEEDBACK_BRAILLE 195 */ 196 public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF; 197 198 /** 199 * If an {@link AccessibilityService} is the default for a given type. 200 * Default service is invoked only if no package specific one exists. In case of 201 * more than one package specific service only the earlier registered is notified. 202 */ 203 public static final int DEFAULT = 0x0000001; 204 205 /** 206 * If this flag is set the system will regard views that are not important 207 * for accessibility in addition to the ones that are important for accessibility. 208 * That is, views that are marked as not important for accessibility via 209 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or 210 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are 211 * marked as potentially important for accessibility via 212 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined 213 * that are not important for accessibility, are reported while querying the window 214 * content and also the accessibility service will receive accessibility events from 215 * them. 216 * <p> 217 * <strong>Note:</strong> For accessibility services targeting Android 4.1 (API level 16) or 218 * higher, this flag has to be explicitly set for the system to regard views that are not 219 * important for accessibility. For accessibility services targeting Android 4.0.4 (API level 220 * 15) or lower, this flag is ignored and all views are regarded for accessibility purposes. 221 * </p> 222 * <p> 223 * Usually views not important for accessibility are layout managers that do not 224 * react to user actions, do not draw any content, and do not have any special 225 * semantics in the context of the screen content. For example, a three by three 226 * grid can be implemented as three horizontal linear layouts and one vertical, 227 * or three vertical linear layouts and one horizontal, or one grid layout, etc. 228 * In this context, the actual layout managers used to achieve the grid configuration 229 * are not important; rather it is important that there are nine evenly distributed 230 * elements. 231 * </p> 232 */ 233 public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002; 234 235 /** 236 * This flag requests that the system gets into touch exploration mode. 237 * In this mode a single finger moving on the screen behaves as a mouse 238 * pointer hovering over the user interface. The system will also detect 239 * certain gestures performed on the touch screen and notify this service. 240 * The system will enable touch exploration mode if there is at least one 241 * accessibility service that has this flag set. Hence, clearing this 242 * flag does not guarantee that the device will not be in touch exploration 243 * mode since there may be another enabled service that requested it. 244 * <p> 245 * For accessibility services targeting Android 4.3 (API level 18) or higher 246 * that want to set this flag have to declare this capability in their 247 * meta-data by setting the attribute 248 * {@link android.R.attr#canRequestTouchExplorationMode 249 * canRequestTouchExplorationMode} to true. Otherwise, this flag will 250 * be ignored. For how to declare the meta-data of a service refer to 251 * {@value AccessibilityService#SERVICE_META_DATA}. 252 * </p> 253 * <p> 254 * Services targeting Android 4.2.2 (API level 17) or lower will work 255 * normally. In other words, the first time they are run, if this flag is 256 * specified, a dialog is shown to the user to confirm enabling explore by 257 * touch. 258 * </p> 259 * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode 260 */ 261 public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004; 262 263 /** 264 * @deprecated No longer used 265 */ 266 public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008; 267 268 /** 269 * This flag requests that the {@link AccessibilityNodeInfo}s obtained 270 * by an {@link AccessibilityService} contain the id of the source view. 271 * The source view id will be a fully qualified resource name of the 272 * form "package:id/name", for example "foo.bar:id/my_list", and it is 273 * useful for UI test automation. This flag is not set by default. 274 */ 275 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010; 276 277 /** 278 * This flag requests from the system to filter key events. If this flag 279 * is set the accessibility service will receive the key events before 280 * applications allowing it implement global shortcuts. 281 * <p> 282 * Services that want to set this flag have to declare this capability 283 * in their meta-data by setting the attribute {@link android.R.attr 284 * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true, 285 * otherwise this flag will be ignored. For how to declare the meta-data 286 * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. 287 * </p> 288 * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents 289 */ 290 public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020; 291 292 /** 293 * This flag indicates to the system that the accessibility service wants 294 * to access content of all interactive windows. An interactive window is a 295 * window that has input focus or can be touched by a sighted user when explore 296 * by touch is not enabled. If this flag is not set your service will not receive 297 * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED} 298 * events, calling AccessibilityService{@link AccessibilityService#getWindows() 299 * AccessibilityService.getWindows()} will return an empty list, and {@link 300 * AccessibilityNodeInfo#getWindow() AccessibilityNodeInfo.getWindow()} will 301 * return null. 302 * <p> 303 * Services that want to set this flag have to declare the capability 304 * to retrieve window content in their meta-data by setting the attribute 305 * {@link android.R.attr#canRetrieveWindowContent canRetrieveWindowContent} to 306 * true, otherwise this flag will be ignored. For how to declare the meta-data 307 * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. 308 * </p> 309 * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent 310 */ 311 public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040; 312 313 /** 314 * This flag requests that all audio tracks system-wide with 315 * {@link android.media.AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY} be controlled by the 316 * {@link android.media.AudioManager#STREAM_ACCESSIBILITY} volume. 317 */ 318 public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080; 319 320 /** 321 * This flag indicates to the system that the accessibility service requests that an 322 * accessibility button be shown within the system's navigation area, if available. 323 * <p> 324 * <strong>Note:</strong> For accessibility services targeting APIs greater than 325 * {@link Build.VERSION_CODES#Q API 29}, this flag must be specified in the 326 * accessibility service metadata file. Otherwise, it will be ignored. 327 * </p> 328 */ 329 public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100; 330 331 /** 332 * This flag requests that all fingerprint gestures be sent to the accessibility service. 333 * <p> 334 * Services that want to set this flag have to declare the capability 335 * to retrieve window content in their meta-data by setting the attribute 336 * {@link android.R.attr#canRequestFingerprintGestures} to 337 * true, otherwise this flag will be ignored. For how to declare the meta-data 338 * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. 339 * </p> 340 * 341 * @see android.R.styleable#AccessibilityService_canRequestFingerprintGestures 342 * @see AccessibilityService#getFingerprintGestureController() 343 */ 344 public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 0x00000200; 345 346 /** 347 * This flag requests that accessibility shortcut warning dialog has spoken feedback when 348 * dialog is shown. 349 */ 350 public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400; 351 352 /** 353 * This flag requests that when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, 354 * double tap and double tap and hold gestures are dispatched to the service rather than being 355 * handled by the framework. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this 356 * flag has no effect. 357 * 358 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 359 */ 360 public static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x0000800; 361 362 /** 363 * This flag requests that when when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, 364 * multi-finger gestures are also enabled. As a consequence, two-finger bypass gestures will be 365 * disabled. If {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this flag has no 366 * effect. 367 * 368 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 369 */ 370 public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000; 371 372 /** 373 * This flag requests that when when {@link #FLAG_REQUEST_MULTI_FINGER_GESTURES} is enabled, 374 * two-finger passthrough gestures are re-enabled. Two-finger swipe gestures are not detected, 375 * but instead passed through as one-finger gestures. In addition, three-finger swipes from the 376 * bottom of the screen are not detected, and instead are passed through unchanged. If {@link 377 * #FLAG_REQUEST_MULTI_FINGER_GESTURES} is disabled this flag has no effect. 378 * 379 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 380 */ 381 public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000; 382 383 /** 384 * This flag requests that when when {@link #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is enabled, a 385 * service will receive the motion events for each successfully-detected gesture. The service 386 * will also receive an AccessibilityGestureEvent of type GESTURE_INVALID for each cancelled 387 * gesture along with its motion events. A service will receive a gesture of type 388 * GESTURE_PASSTHROUGH and accompanying motion events for every passthrough gesture that does 389 * not start gesture detection. This information can be used to collect instances of improper 390 * gesture detection behavior and relay that information to framework developers. If {@link 391 * #FLAG_REQUEST_TOUCH_EXPLORATION_MODE} is disabled this flag has no effect. 392 * 393 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 394 */ 395 public static final int FLAG_SEND_MOTION_EVENTS = 0x0004000; 396 397 /** 398 * This flag makes the AccessibilityService an input method editor with a subset of input 399 * method editor capabilities: get the {@link android.view.inputmethod.InputConnection} and get 400 * text selection change notifications. 401 * 402 * @see AccessibilityService#getInputMethod() 403 */ 404 public static final int FLAG_INPUT_METHOD_EDITOR = 0x0008000; 405 406 /** {@hide} */ 407 public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; 408 409 /** 410 * The event types an {@link AccessibilityService} is interested in. 411 * <p> 412 * <strong>Can be dynamically set at runtime.</strong> 413 * </p> 414 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED 415 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED 416 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED 417 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED 418 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED 419 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 420 * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED 421 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START 422 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END 423 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER 424 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT 425 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED 426 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED 427 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED 428 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START 429 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END 430 * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT 431 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START 432 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END 433 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED 434 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 435 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 436 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED 437 */ 438 public int eventTypes; 439 440 /** 441 * The package names an {@link AccessibilityService} is interested in. Setting 442 * to <code>null</code> is equivalent to all packages. 443 * <p> 444 * <strong>Can be dynamically set at runtime.</strong> 445 * </p> 446 */ 447 public String[] packageNames; 448 449 450 /** @hide */ 451 @IntDef(flag = true, prefix = { "FEEDBACK_" }, value = { 452 FEEDBACK_AUDIBLE, 453 FEEDBACK_GENERIC, 454 FEEDBACK_HAPTIC, 455 FEEDBACK_SPOKEN, 456 FEEDBACK_VISUAL, 457 FEEDBACK_BRAILLE 458 }) 459 @Retention(RetentionPolicy.SOURCE) 460 public @interface FeedbackType {} 461 462 /** 463 * The feedback type an {@link AccessibilityService} provides. 464 * <p> 465 * <strong>Can be dynamically set at runtime.</strong> 466 * </p> 467 * @see #FEEDBACK_AUDIBLE 468 * @see #FEEDBACK_GENERIC 469 * @see #FEEDBACK_HAPTIC 470 * @see #FEEDBACK_SPOKEN 471 * @see #FEEDBACK_VISUAL 472 * @see #FEEDBACK_BRAILLE 473 */ 474 @FeedbackType 475 public int feedbackType; 476 477 /** 478 * The timeout, in milliseconds, after the most recent event of a given type before an 479 * {@link AccessibilityService} is notified. 480 * <p> 481 * <strong>Can be dynamically set at runtime.</strong> 482 * </p> 483 * <p> 484 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 485 * events to the client too frequently since this is accomplished via an expensive 486 * interprocess call. One can think of the timeout as a criteria to determine when 487 * event generation has settled down. 488 */ 489 public long notificationTimeout; 490 491 /** 492 * This field represents a set of flags used for configuring an 493 * {@link AccessibilityService}. 494 * <p> 495 * <strong>Can be dynamically set at runtime.</strong> 496 * </p> 497 * <p> 498 * <strong>Note:</strong> Accessibility services with targetSdkVersion greater than 499 * {@link Build.VERSION_CODES#Q API 29} cannot dynamically set the 500 * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} at runtime. It must be specified in the 501 * accessibility service metadata file. 502 * </p> 503 * @see #DEFAULT 504 * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 505 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 506 * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY 507 * @see #FLAG_REQUEST_FILTER_KEY_EVENTS 508 * @see #FLAG_REPORT_VIEW_IDS 509 * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS 510 * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME 511 * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON 512 * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK 513 * @see #FLAG_INPUT_METHOD_EDITOR 514 */ 515 public int flags; 516 517 /** 518 * Whether or not the service has crashed and is awaiting restart. Only valid from {@link 519 * android.view.accessibility.AccessibilityManager#getInstalledAccessibilityServiceList()}, 520 * because that is populated from the internal list of running services. 521 * 522 * @hide 523 */ 524 public boolean crashed; 525 526 /** 527 * A recommended timeout in milliseconds for non-interactive controls. 528 */ 529 private int mNonInteractiveUiTimeout; 530 531 /** 532 * A recommended timeout in milliseconds for interactive controls. 533 */ 534 private int mInteractiveUiTimeout; 535 536 /** 537 * The component name the accessibility service. 538 */ 539 @NonNull 540 private ComponentName mComponentName; 541 542 /** 543 * The Service that implements this accessibility service component. 544 */ 545 private ResolveInfo mResolveInfo; 546 547 /** 548 * The accessibility service setting activity's name, used by the system 549 * settings to launch the setting activity of this accessibility service. 550 */ 551 private String mSettingsActivityName; 552 553 /** 554 * The name of {@link android.service.quicksettings.TileService} is associated with this 555 * accessibility service for one to one mapping. It is used by system settings to remind users 556 * this accessibility service has a {@link android.service.quicksettings.TileService}. 557 */ 558 private String mTileServiceName; 559 560 /** 561 * Bit mask with capabilities of this service. 562 */ 563 private int mCapabilities; 564 565 /** 566 * Resource id of the summary of the accessibility service. 567 */ 568 private int mSummaryResId; 569 570 /** 571 * Non-localized summary of the accessibility service. 572 */ 573 private String mNonLocalizedSummary; 574 575 /** 576 * Resource id of the intro of the accessibility service. 577 */ 578 private int mIntroResId; 579 580 /** 581 * Resource id of the description of the accessibility service. 582 */ 583 private int mDescriptionResId; 584 585 /** 586 * Non localized description of the accessibility service. 587 */ 588 private String mNonLocalizedDescription; 589 590 /** 591 * For accessibility services targeting APIs greater than {@link Build.VERSION_CODES#Q API 29}, 592 * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} must be specified in the accessibility service 593 * metadata file. Otherwise, it will be ignored. 594 */ 595 @ChangeId 596 @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) 597 private static final long REQUEST_ACCESSIBILITY_BUTTON_CHANGE = 136293963L; 598 599 /** 600 * Resource id of the animated image of the accessibility service. 601 */ 602 private int mAnimatedImageRes; 603 604 /** 605 * Resource id of the html description of the accessibility service. 606 */ 607 private int mHtmlDescriptionRes; 608 609 /** 610 * Whether the service is for accessibility. 611 * 612 * @hide 613 */ 614 private boolean mIsAccessibilityTool = false; 615 616 /** 617 * {@link InputDevice} sources which may send {@link android.view.MotionEvent}s. 618 * @see #setMotionEventSources(int) 619 * @hide 620 */ 621 @IntDef(flag = true, prefix = { "SOURCE_" }, value = { 622 InputDevice.SOURCE_MOUSE, 623 InputDevice.SOURCE_STYLUS, 624 InputDevice.SOURCE_BLUETOOTH_STYLUS, 625 InputDevice.SOURCE_TRACKBALL, 626 InputDevice.SOURCE_MOUSE_RELATIVE, 627 InputDevice.SOURCE_TOUCHPAD, 628 InputDevice.SOURCE_TOUCH_NAVIGATION, 629 InputDevice.SOURCE_ROTARY_ENCODER, 630 InputDevice.SOURCE_JOYSTICK, 631 InputDevice.SOURCE_SENSOR 632 }) 633 public @interface MotionEventSources {} 634 635 /** 636 * The bit mask of {@link android.view.InputDevice} sources that the accessibility 637 * service wants to listen to for generic {@link android.view.MotionEvent}s. 638 */ 639 @MotionEventSources 640 private int mMotionEventSources = 0; 641 642 /** 643 * Creates a new instance. 644 */ AccessibilityServiceInfo()645 public AccessibilityServiceInfo() { 646 /* do nothing */ 647 } 648 649 /** 650 * Creates a new instance. 651 * 652 * @param resolveInfo The service resolve info. 653 * @param context Context for accessing resources. 654 * @throws XmlPullParserException If a XML parsing error occurs. 655 * @throws IOException If a XML parsing error occurs. 656 * 657 * @hide 658 */ AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)659 public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context) 660 throws XmlPullParserException, IOException { 661 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 662 mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name); 663 mResolveInfo = resolveInfo; 664 665 XmlResourceParser parser = null; 666 667 try { 668 PackageManager packageManager = context.getPackageManager(); 669 parser = serviceInfo.loadXmlMetaData(packageManager, 670 AccessibilityService.SERVICE_META_DATA); 671 if (parser == null) { 672 return; 673 } 674 675 int type = 0; 676 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 677 type = parser.next(); 678 } 679 680 String nodeName = parser.getName(); 681 if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) { 682 throw new XmlPullParserException( "Meta-data does not start with" 683 + TAG_ACCESSIBILITY_SERVICE + " tag"); 684 } 685 686 AttributeSet allAttributes = Xml.asAttributeSet(parser); 687 Resources resources = packageManager.getResourcesForApplication( 688 serviceInfo.applicationInfo); 689 TypedArray asAttributes = resources.obtainAttributes(allAttributes, 690 com.android.internal.R.styleable.AccessibilityService); 691 eventTypes = asAttributes.getInt( 692 com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes, 693 0); 694 String packageNamez = asAttributes.getString( 695 com.android.internal.R.styleable.AccessibilityService_packageNames); 696 if (packageNamez != null) { 697 packageNames = packageNamez.split("(\\s)*,(\\s)*"); 698 } 699 feedbackType = asAttributes.getInt( 700 com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType, 701 0); 702 notificationTimeout = asAttributes.getInt( 703 com.android.internal.R.styleable.AccessibilityService_notificationTimeout, 704 0); 705 mNonInteractiveUiTimeout = asAttributes.getInt( 706 com.android.internal.R.styleable.AccessibilityService_nonInteractiveUiTimeout, 707 0); 708 mInteractiveUiTimeout = asAttributes.getInt( 709 com.android.internal.R.styleable.AccessibilityService_interactiveUiTimeout, 710 0); 711 flags = asAttributes.getInt( 712 com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); 713 mSettingsActivityName = asAttributes.getString( 714 com.android.internal.R.styleable.AccessibilityService_settingsActivity); 715 if (asAttributes.getBoolean(com.android.internal.R.styleable 716 .AccessibilityService_canRetrieveWindowContent, false)) { 717 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; 718 } 719 if (asAttributes.getBoolean(com.android.internal.R.styleable 720 .AccessibilityService_canRequestTouchExplorationMode, false)) { 721 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; 722 } 723 if (asAttributes.getBoolean(com.android.internal.R.styleable 724 .AccessibilityService_canRequestFilterKeyEvents, false)) { 725 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; 726 } 727 if (asAttributes.getBoolean(com.android.internal.R.styleable 728 .AccessibilityService_canControlMagnification, false)) { 729 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION; 730 } 731 if (asAttributes.getBoolean(com.android.internal.R.styleable 732 .AccessibilityService_canPerformGestures, false)) { 733 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES; 734 } 735 if (asAttributes.getBoolean(com.android.internal.R.styleable 736 .AccessibilityService_canRequestFingerprintGestures, false)) { 737 mCapabilities |= CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES; 738 } 739 if (asAttributes.getBoolean(com.android.internal.R.styleable 740 .AccessibilityService_canTakeScreenshot, false)) { 741 mCapabilities |= CAPABILITY_CAN_TAKE_SCREENSHOT; 742 } 743 TypedValue peekedValue = asAttributes.peekValue( 744 com.android.internal.R.styleable.AccessibilityService_description); 745 if (peekedValue != null) { 746 mDescriptionResId = peekedValue.resourceId; 747 CharSequence nonLocalizedDescription = peekedValue.coerceToString(); 748 if (nonLocalizedDescription != null) { 749 mNonLocalizedDescription = nonLocalizedDescription.toString().trim(); 750 } 751 } 752 peekedValue = asAttributes.peekValue( 753 com.android.internal.R.styleable.AccessibilityService_summary); 754 if (peekedValue != null) { 755 mSummaryResId = peekedValue.resourceId; 756 CharSequence nonLocalizedSummary = peekedValue.coerceToString(); 757 if (nonLocalizedSummary != null) { 758 mNonLocalizedSummary = nonLocalizedSummary.toString().trim(); 759 } 760 } 761 peekedValue = asAttributes.peekValue( 762 com.android.internal.R.styleable.AccessibilityService_animatedImageDrawable); 763 if (peekedValue != null) { 764 mAnimatedImageRes = peekedValue.resourceId; 765 } 766 peekedValue = asAttributes.peekValue( 767 com.android.internal.R.styleable.AccessibilityService_htmlDescription); 768 if (peekedValue != null) { 769 mHtmlDescriptionRes = peekedValue.resourceId; 770 } 771 mIsAccessibilityTool = asAttributes.getBoolean( 772 R.styleable.AccessibilityService_isAccessibilityTool, false); 773 mTileServiceName = asAttributes.getString( 774 com.android.internal.R.styleable.AccessibilityService_tileService); 775 peekedValue = asAttributes.peekValue( 776 com.android.internal.R.styleable.AccessibilityService_intro); 777 if (peekedValue != null) { 778 mIntroResId = peekedValue.resourceId; 779 } 780 asAttributes.recycle(); 781 } catch (NameNotFoundException e) { 782 throw new XmlPullParserException( "Unable to create context for: " 783 + serviceInfo.packageName); 784 } finally { 785 if (parser != null) { 786 parser.close(); 787 } 788 } 789 } 790 791 /** 792 * Updates the properties that an AccessibilityService can change dynamically. 793 * <p> 794 * Note: A11y services targeting APIs > Q, it cannot update flagRequestAccessibilityButton 795 * dynamically. 796 * </p> 797 * 798 * @param platformCompat The platform compat service to check the compatibility change. 799 * @param other The info from which to update the properties. 800 * 801 * @hide 802 */ updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat, AccessibilityServiceInfo other)803 public void updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat, 804 AccessibilityServiceInfo other) { 805 if (isRequestAccessibilityButtonChangeEnabled(platformCompat)) { 806 other.flags &= ~FLAG_REQUEST_ACCESSIBILITY_BUTTON; 807 other.flags |= (flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON); 808 } 809 eventTypes = other.eventTypes; 810 packageNames = other.packageNames; 811 feedbackType = other.feedbackType; 812 notificationTimeout = other.notificationTimeout; 813 mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout; 814 mInteractiveUiTimeout = other.mInteractiveUiTimeout; 815 flags = other.flags; 816 mMotionEventSources = other.mMotionEventSources; 817 // NOTE: Ensure that only properties that are safe to be modified by the service itself 818 // are included here (regardless of hidden setters, etc.). 819 } 820 isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat)821 private boolean isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat) { 822 if (mResolveInfo == null) { 823 return true; 824 } 825 try { 826 if (platformCompat != null) { 827 return platformCompat.isChangeEnabled(REQUEST_ACCESSIBILITY_BUTTON_CHANGE, 828 mResolveInfo.serviceInfo.applicationInfo); 829 } 830 } catch (RemoteException ignore) { 831 } 832 return mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q; 833 } 834 835 /** 836 * @hide 837 */ setComponentName(@onNull ComponentName component)838 public void setComponentName(@NonNull ComponentName component) { 839 mComponentName = component; 840 } 841 842 /** 843 * @hide 844 */ setResolveInfo(@onNull ResolveInfo resolveInfo)845 public void setResolveInfo(@NonNull ResolveInfo resolveInfo) { 846 mResolveInfo = resolveInfo; 847 } 848 849 /** 850 * @hide 851 */ 852 @TestApi 853 @NonNull getComponentName()854 public ComponentName getComponentName() { 855 return mComponentName; 856 } 857 858 /** 859 * The accessibility service id. 860 * <p> 861 * <strong>Generated by the system.</strong> 862 * </p> 863 * @return The id (or {@code null} if the component is not set yet). 864 */ getId()865 public String getId() { 866 return mComponentName == null ? null : mComponentName.flattenToShortString(); 867 } 868 869 /** 870 * The service {@link ResolveInfo}. 871 * <p> 872 * <strong>Generated by the system.</strong> 873 * </p> 874 * @return The info. 875 */ getResolveInfo()876 public ResolveInfo getResolveInfo() { 877 return mResolveInfo; 878 } 879 880 /** 881 * The settings activity name. 882 * <p> 883 * <strong>Statically set from 884 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 885 * </p> 886 * @return The settings activity name. 887 */ getSettingsActivityName()888 public String getSettingsActivityName() { 889 return mSettingsActivityName; 890 } 891 892 /** 893 * Gets the name of {@link android.service.quicksettings.TileService} is associated with 894 * this accessibility service. 895 * 896 * @return The name of {@link android.service.quicksettings.TileService}. 897 */ 898 @Nullable getTileServiceName()899 public String getTileServiceName() { 900 return mTileServiceName; 901 } 902 903 /** 904 * Gets the animated image resource id. 905 * 906 * @return The animated image resource id. 907 * 908 * @hide 909 */ getAnimatedImageRes()910 public int getAnimatedImageRes() { 911 return mAnimatedImageRes; 912 } 913 914 /** 915 * The animated image drawable. 916 * <p> 917 * Image can not exceed the screen size. 918 * <strong>Statically set from 919 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 920 * </p> 921 * @return The animated image drawable, or null if the resource is invalid or the image 922 * exceed the screen size. 923 * 924 * @hide 925 */ 926 @Nullable loadAnimatedImage(@onNull Context context)927 public Drawable loadAnimatedImage(@NonNull Context context) { 928 if (mAnimatedImageRes == /* invalid */ 0) { 929 return null; 930 } 931 932 return loadSafeAnimatedImage(context, mResolveInfo.serviceInfo.applicationInfo, 933 mAnimatedImageRes); 934 } 935 936 /** 937 * Whether this service can retrieve the current window's content. 938 * <p> 939 * <strong>Statically set from 940 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 941 * </p> 942 * @return True if window content can be retrieved. 943 * 944 * @deprecated Use {@link #getCapabilities()}. 945 */ getCanRetrieveWindowContent()946 public boolean getCanRetrieveWindowContent() { 947 return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 948 } 949 950 /** 951 * Returns the bit mask of capabilities this accessibility service has such as 952 * being able to retrieve the active window content, etc. 953 * 954 * @return The capability bit mask. 955 * 956 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 957 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 958 * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 959 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 960 * @see #CAPABILITY_CAN_PERFORM_GESTURES 961 * @see #CAPABILITY_CAN_TAKE_SCREENSHOT 962 */ getCapabilities()963 public int getCapabilities() { 964 return mCapabilities; 965 } 966 967 /** 968 * Sets the bit mask of capabilities this accessibility service has such as 969 * being able to retrieve the active window content, etc. 970 * 971 * @param capabilities The capability bit mask. 972 * 973 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 974 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 975 * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 976 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 977 * @see #CAPABILITY_CAN_PERFORM_GESTURES 978 * @see #CAPABILITY_CAN_TAKE_SCREENSHOT 979 * 980 * @hide 981 */ 982 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setCapabilities(int capabilities)983 public void setCapabilities(int capabilities) { 984 mCapabilities = capabilities; 985 } 986 987 /** 988 * Returns the bit mask of {@link android.view.InputDevice} sources that the accessibility 989 * service wants to listen to for generic {@link android.view.MotionEvent}s. 990 */ 991 @MotionEventSources getMotionEventSources()992 public int getMotionEventSources() { 993 return mMotionEventSources; 994 } 995 996 /** 997 * Sets the bit mask of {@link android.view.InputDevice} sources that the accessibility 998 * service wants to listen to for generic {@link android.view.MotionEvent}s. 999 * 1000 * <p> 1001 * Including an {@link android.view.InputDevice} source that does not send 1002 * {@link android.view.MotionEvent}s is effectively a no-op for that source, since you will 1003 * not receive any events from that source. 1004 * </p> 1005 * 1006 * <p> 1007 * See {@link android.view.InputDevice} for complete source definitions. 1008 * Many input devices send {@link android.view.InputEvent}s from more than one type of source so 1009 * you may need to include multiple {@link android.view.MotionEvent} sources here, in addition 1010 * to using {@link AccessibilityService#onKeyEvent} to listen to {@link android.view.KeyEvent}s. 1011 * </p> 1012 * 1013 * <p> 1014 * <strong>Note:</strong> {@link android.view.InputDevice} sources contain source class bits 1015 * that complicate bitwise flag removal operations. To remove a specific source you should 1016 * rebuild the entire value using bitwise OR operations on the individual source constants. 1017 * </p> 1018 * 1019 * @param motionEventSources A bit mask of {@link android.view.InputDevice} sources. 1020 * @see AccessibilityService#onMotionEvent 1021 * @see #MotionEventSources 1022 */ setMotionEventSources(@otionEventSources int motionEventSources)1023 public void setMotionEventSources(@MotionEventSources int motionEventSources) { 1024 mMotionEventSources = motionEventSources; 1025 } 1026 1027 /** 1028 * The localized summary of the accessibility service. 1029 * <p> 1030 * <strong>Statically set from 1031 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 1032 * </p> 1033 * @return The localized summary if available, and {@code null} if a summary 1034 * has not been provided. 1035 */ loadSummary(PackageManager packageManager)1036 public CharSequence loadSummary(PackageManager packageManager) { 1037 if (mSummaryResId == 0) { 1038 return mNonLocalizedSummary; 1039 } 1040 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 1041 CharSequence summary = packageManager.getText(serviceInfo.packageName, 1042 mSummaryResId, serviceInfo.applicationInfo); 1043 if (summary != null) { 1044 return summary.toString().trim(); 1045 } 1046 return null; 1047 } 1048 1049 /** 1050 * The localized intro of the accessibility service. 1051 * <p> 1052 * <strong>Statically set from 1053 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 1054 * </p> 1055 * @return The localized intro if available, and {@code null} if a intro 1056 * has not been provided. 1057 */ 1058 @Nullable loadIntro(@onNull PackageManager packageManager)1059 public CharSequence loadIntro(@NonNull PackageManager packageManager) { 1060 if (mIntroResId == /* invalid */ 0) { 1061 return null; 1062 } 1063 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 1064 CharSequence intro = packageManager.getText(serviceInfo.packageName, 1065 mIntroResId, serviceInfo.applicationInfo); 1066 if (intro != null) { 1067 return intro.toString().trim(); 1068 } 1069 return null; 1070 } 1071 1072 /** 1073 * Gets the non-localized description of the accessibility service. 1074 * <p> 1075 * <strong>Statically set from 1076 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 1077 * </p> 1078 * @return The description. 1079 * 1080 * @deprecated Use {@link #loadDescription(PackageManager)}. 1081 */ getDescription()1082 public String getDescription() { 1083 return mNonLocalizedDescription; 1084 } 1085 1086 /** 1087 * The localized description of the accessibility service. 1088 * <p> 1089 * <strong>Statically set from 1090 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 1091 * </p> 1092 * @return The localized description. 1093 */ loadDescription(PackageManager packageManager)1094 public String loadDescription(PackageManager packageManager) { 1095 if (mDescriptionResId == 0) { 1096 return mNonLocalizedDescription; 1097 } 1098 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 1099 CharSequence description = packageManager.getText(serviceInfo.packageName, 1100 mDescriptionResId, serviceInfo.applicationInfo); 1101 if (description != null) { 1102 return description.toString().trim(); 1103 } 1104 return null; 1105 } 1106 1107 /** 1108 * The localized and restricted html description of the accessibility service. 1109 * <p> 1110 * Filters the <img> tag which do not meet the custom specification and the <a> tag. 1111 * <strong>Statically set from 1112 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 1113 * </p> 1114 * @return The localized and restricted html description. 1115 * 1116 * @hide 1117 */ 1118 @Nullable loadHtmlDescription(@onNull PackageManager packageManager)1119 public String loadHtmlDescription(@NonNull PackageManager packageManager) { 1120 if (mHtmlDescriptionRes == /* invalid */ 0) { 1121 return null; 1122 } 1123 1124 final ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 1125 final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName, 1126 mHtmlDescriptionRes, serviceInfo.applicationInfo); 1127 if (htmlDescription != null) { 1128 return getFilteredHtmlText(htmlDescription.toString().trim()); 1129 } 1130 return null; 1131 } 1132 1133 /** 1134 * Set the recommended time that non-interactive controls need to remain on the screen to 1135 * support the user. 1136 * <p> 1137 * <strong>This value can be dynamically set at runtime by 1138 * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong> 1139 * </p> 1140 * 1141 * @param timeout The timeout in milliseconds. 1142 * 1143 * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout 1144 */ setNonInteractiveUiTimeoutMillis(@ntRangefrom = 0) int timeout)1145 public void setNonInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) { 1146 mNonInteractiveUiTimeout = timeout; 1147 } 1148 1149 /** 1150 * Get the recommended timeout for non-interactive controls. 1151 * 1152 * @return The timeout in milliseconds. 1153 * 1154 * @see #setNonInteractiveUiTimeoutMillis(int) 1155 */ getNonInteractiveUiTimeoutMillis()1156 public int getNonInteractiveUiTimeoutMillis() { 1157 return mNonInteractiveUiTimeout; 1158 } 1159 1160 /** 1161 * Set the recommended time that interactive controls need to remain on the screen to 1162 * support the user. 1163 * <p> 1164 * <strong>This value can be dynamically set at runtime by 1165 * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong> 1166 * </p> 1167 * 1168 * @param timeout The timeout in milliseconds. 1169 * 1170 * @see android.R.styleable#AccessibilityService_interactiveUiTimeout 1171 */ setInteractiveUiTimeoutMillis(@ntRangefrom = 0) int timeout)1172 public void setInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) { 1173 mInteractiveUiTimeout = timeout; 1174 } 1175 1176 /** 1177 * Get the recommended timeout for interactive controls. 1178 * 1179 * @return The timeout in milliseconds. 1180 * 1181 * @see #setInteractiveUiTimeoutMillis(int) 1182 */ getInteractiveUiTimeoutMillis()1183 public int getInteractiveUiTimeoutMillis() { 1184 return mInteractiveUiTimeout; 1185 } 1186 1187 /** {@hide} */ isDirectBootAware()1188 public boolean isDirectBootAware() { 1189 return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0) 1190 || mResolveInfo.serviceInfo.directBootAware; 1191 } 1192 1193 /** 1194 * Sets whether the service is used to assist users with disabilities. 1195 * 1196 * <p> 1197 * This property is normally provided in the service's {@link #mResolveInfo ResolveInfo}. 1198 * </p> 1199 * 1200 * <p> 1201 * This method is helpful for unit testing. However, this property is not dynamically 1202 * configurable by a standard {@link AccessibilityService} so it's not possible to update the 1203 * copy held by the system with this method. 1204 * </p> 1205 * 1206 * @hide 1207 */ 1208 @SystemApi setAccessibilityTool(boolean isAccessibilityTool)1209 public void setAccessibilityTool(boolean isAccessibilityTool) { 1210 mIsAccessibilityTool = isAccessibilityTool; 1211 } 1212 1213 /** 1214 * Indicates if the service is used to assist users with disabilities. 1215 * 1216 * @return {@code true} if the property is set to true. 1217 */ isAccessibilityTool()1218 public boolean isAccessibilityTool() { 1219 return mIsAccessibilityTool; 1220 } 1221 1222 /** 1223 * {@inheritDoc} 1224 */ describeContents()1225 public int describeContents() { 1226 return 0; 1227 } 1228 1229 /** @hide */ isWithinParcelableSize()1230 public final boolean isWithinParcelableSize() { 1231 final Parcel parcel = Parcel.obtain(); 1232 writeToParcel(parcel, 0); 1233 final boolean result = parcel.dataSize() <= IBinder.MAX_IPC_SIZE; 1234 parcel.recycle(); 1235 return result; 1236 } 1237 writeToParcel(Parcel parcel, int flagz)1238 public void writeToParcel(Parcel parcel, int flagz) { 1239 parcel.writeInt(eventTypes); 1240 parcel.writeStringArray(packageNames); 1241 parcel.writeInt(feedbackType); 1242 parcel.writeLong(notificationTimeout); 1243 parcel.writeInt(mNonInteractiveUiTimeout); 1244 parcel.writeInt(mInteractiveUiTimeout); 1245 parcel.writeInt(flags); 1246 parcel.writeInt(crashed ? 1 : 0); 1247 parcel.writeParcelable(mComponentName, flagz); 1248 parcel.writeParcelable(mResolveInfo, 0); 1249 parcel.writeString(mSettingsActivityName); 1250 parcel.writeInt(mCapabilities); 1251 parcel.writeInt(mSummaryResId); 1252 parcel.writeString(mNonLocalizedSummary); 1253 parcel.writeInt(mDescriptionResId); 1254 parcel.writeInt(mAnimatedImageRes); 1255 parcel.writeInt(mHtmlDescriptionRes); 1256 parcel.writeString(mNonLocalizedDescription); 1257 parcel.writeBoolean(mIsAccessibilityTool); 1258 parcel.writeString(mTileServiceName); 1259 parcel.writeInt(mIntroResId); 1260 parcel.writeInt(mMotionEventSources); 1261 } 1262 initFromParcel(Parcel parcel)1263 private void initFromParcel(Parcel parcel) { 1264 eventTypes = parcel.readInt(); 1265 packageNames = parcel.readStringArray(); 1266 feedbackType = parcel.readInt(); 1267 notificationTimeout = parcel.readLong(); 1268 mNonInteractiveUiTimeout = parcel.readInt(); 1269 mInteractiveUiTimeout = parcel.readInt(); 1270 flags = parcel.readInt(); 1271 crashed = parcel.readInt() != 0; 1272 mComponentName = parcel.readParcelable(this.getClass().getClassLoader(), android.content.ComponentName.class); 1273 mResolveInfo = parcel.readParcelable(null, android.content.pm.ResolveInfo.class); 1274 mSettingsActivityName = parcel.readString(); 1275 mCapabilities = parcel.readInt(); 1276 mSummaryResId = parcel.readInt(); 1277 mNonLocalizedSummary = parcel.readString(); 1278 mDescriptionResId = parcel.readInt(); 1279 mAnimatedImageRes = parcel.readInt(); 1280 mHtmlDescriptionRes = parcel.readInt(); 1281 mNonLocalizedDescription = parcel.readString(); 1282 mIsAccessibilityTool = parcel.readBoolean(); 1283 mTileServiceName = parcel.readString(); 1284 mIntroResId = parcel.readInt(); 1285 mMotionEventSources = parcel.readInt(); 1286 } 1287 1288 @Override hashCode()1289 public int hashCode() { 1290 return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode()); 1291 } 1292 1293 @Override equals(@ullable Object obj)1294 public boolean equals(@Nullable Object obj) { 1295 if (this == obj) { 1296 return true; 1297 } 1298 if (obj == null) { 1299 return false; 1300 } 1301 if (getClass() != obj.getClass()) { 1302 return false; 1303 } 1304 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 1305 if (mComponentName == null) { 1306 if (other.mComponentName != null) { 1307 return false; 1308 } 1309 } else if (!mComponentName.equals(other.mComponentName)) { 1310 return false; 1311 } 1312 return true; 1313 } 1314 1315 @Override toString()1316 public String toString() { 1317 StringBuilder stringBuilder = new StringBuilder(); 1318 appendEventTypes(stringBuilder, eventTypes); 1319 stringBuilder.append(", "); 1320 appendPackageNames(stringBuilder, packageNames); 1321 stringBuilder.append(", "); 1322 appendFeedbackTypes(stringBuilder, feedbackType); 1323 stringBuilder.append(", "); 1324 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 1325 stringBuilder.append(", "); 1326 stringBuilder.append("nonInteractiveUiTimeout: ").append(mNonInteractiveUiTimeout); 1327 stringBuilder.append(", "); 1328 stringBuilder.append("interactiveUiTimeout: ").append(mInteractiveUiTimeout); 1329 stringBuilder.append(", "); 1330 appendFlags(stringBuilder, flags); 1331 stringBuilder.append(", "); 1332 stringBuilder.append("id: ").append(getId()); 1333 stringBuilder.append(", "); 1334 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 1335 stringBuilder.append(", "); 1336 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 1337 stringBuilder.append(", "); 1338 stringBuilder.append("tileServiceName: ").append(mTileServiceName); 1339 stringBuilder.append(", "); 1340 stringBuilder.append("summary: ").append(mNonLocalizedSummary); 1341 stringBuilder.append(", "); 1342 stringBuilder.append("isAccessibilityTool: ").append(mIsAccessibilityTool); 1343 stringBuilder.append(", "); 1344 appendCapabilities(stringBuilder, mCapabilities); 1345 return stringBuilder.toString(); 1346 } 1347 appendFeedbackTypes(StringBuilder stringBuilder, @FeedbackType int feedbackTypes)1348 private static void appendFeedbackTypes(StringBuilder stringBuilder, 1349 @FeedbackType int feedbackTypes) { 1350 stringBuilder.append("feedbackTypes:"); 1351 stringBuilder.append("["); 1352 while (feedbackTypes != 0) { 1353 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 1354 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 1355 feedbackTypes &= ~feedbackTypeBit; 1356 if (feedbackTypes != 0) { 1357 stringBuilder.append(", "); 1358 } 1359 } 1360 stringBuilder.append("]"); 1361 } 1362 appendPackageNames(StringBuilder stringBuilder, String[] packageNames)1363 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 1364 stringBuilder.append("packageNames:"); 1365 stringBuilder.append("["); 1366 if (packageNames != null) { 1367 final int packageNameCount = packageNames.length; 1368 for (int i = 0; i < packageNameCount; i++) { 1369 stringBuilder.append(packageNames[i]); 1370 if (i < packageNameCount - 1) { 1371 stringBuilder.append(", "); 1372 } 1373 } 1374 } 1375 stringBuilder.append("]"); 1376 } 1377 appendEventTypes(StringBuilder stringBuilder, int eventTypes)1378 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 1379 stringBuilder.append("eventTypes:"); 1380 stringBuilder.append("["); 1381 while (eventTypes != 0) { 1382 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 1383 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 1384 eventTypes &= ~eventTypeBit; 1385 if (eventTypes != 0) { 1386 stringBuilder.append(", "); 1387 } 1388 } 1389 stringBuilder.append("]"); 1390 } 1391 appendFlags(StringBuilder stringBuilder, int flags)1392 private static void appendFlags(StringBuilder stringBuilder, int flags) { 1393 stringBuilder.append("flags:"); 1394 stringBuilder.append("["); 1395 while (flags != 0) { 1396 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 1397 stringBuilder.append(flagToString(flagBit)); 1398 flags &= ~flagBit; 1399 if (flags != 0) { 1400 stringBuilder.append(", "); 1401 } 1402 } 1403 stringBuilder.append("]"); 1404 } 1405 appendCapabilities(StringBuilder stringBuilder, int capabilities)1406 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 1407 stringBuilder.append("capabilities:"); 1408 stringBuilder.append("["); 1409 while (capabilities != 0) { 1410 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 1411 stringBuilder.append(capabilityToString(capabilityBit)); 1412 capabilities &= ~capabilityBit; 1413 if (capabilities != 0) { 1414 stringBuilder.append(", "); 1415 } 1416 } 1417 stringBuilder.append("]"); 1418 } 1419 1420 /** 1421 * Returns the string representation of a feedback type. For example, 1422 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 1423 * 1424 * @param feedbackType The feedback type. 1425 * @return The string representation. 1426 */ feedbackTypeToString(int feedbackType)1427 public static String feedbackTypeToString(int feedbackType) { 1428 StringBuilder builder = new StringBuilder(); 1429 builder.append("["); 1430 while (feedbackType != 0) { 1431 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 1432 feedbackType &= ~feedbackTypeFlag; 1433 switch (feedbackTypeFlag) { 1434 case FEEDBACK_AUDIBLE: 1435 if (builder.length() > 1) { 1436 builder.append(", "); 1437 } 1438 builder.append("FEEDBACK_AUDIBLE"); 1439 break; 1440 case FEEDBACK_HAPTIC: 1441 if (builder.length() > 1) { 1442 builder.append(", "); 1443 } 1444 builder.append("FEEDBACK_HAPTIC"); 1445 break; 1446 case FEEDBACK_GENERIC: 1447 if (builder.length() > 1) { 1448 builder.append(", "); 1449 } 1450 builder.append("FEEDBACK_GENERIC"); 1451 break; 1452 case FEEDBACK_SPOKEN: 1453 if (builder.length() > 1) { 1454 builder.append(", "); 1455 } 1456 builder.append("FEEDBACK_SPOKEN"); 1457 break; 1458 case FEEDBACK_VISUAL: 1459 if (builder.length() > 1) { 1460 builder.append(", "); 1461 } 1462 builder.append("FEEDBACK_VISUAL"); 1463 break; 1464 case FEEDBACK_BRAILLE: 1465 if (builder.length() > 1) { 1466 builder.append(", "); 1467 } 1468 builder.append("FEEDBACK_BRAILLE"); 1469 break; 1470 } 1471 } 1472 builder.append("]"); 1473 return builder.toString(); 1474 } 1475 1476 /** 1477 * Returns the string representation of a flag. For example, 1478 * {@link #DEFAULT} is represented by the string DEFAULT. 1479 * 1480 * @param flag The flag. 1481 * @return The string representation. 1482 */ flagToString(int flag)1483 public static String flagToString(int flag) { 1484 switch (flag) { 1485 case DEFAULT: 1486 return "DEFAULT"; 1487 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 1488 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 1489 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 1490 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 1491 case FLAG_SERVICE_HANDLES_DOUBLE_TAP: 1492 return "FLAG_SERVICE_HANDLES_DOUBLE_TAP"; 1493 case FLAG_REQUEST_MULTI_FINGER_GESTURES: 1494 return "FLAG_REQUEST_MULTI_FINGER_GESTURES"; 1495 case FLAG_REQUEST_2_FINGER_PASSTHROUGH: 1496 return "FLAG_REQUEST_2_FINGER_PASSTHROUGH"; 1497 case FLAG_SEND_MOTION_EVENTS: 1498 return "FLAG_SEND_MOTION_EVENTS"; 1499 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 1500 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 1501 case FLAG_REPORT_VIEW_IDS: 1502 return "FLAG_REPORT_VIEW_IDS"; 1503 case FLAG_REQUEST_FILTER_KEY_EVENTS: 1504 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 1505 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 1506 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 1507 case FLAG_ENABLE_ACCESSIBILITY_VOLUME: 1508 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME"; 1509 case FLAG_REQUEST_ACCESSIBILITY_BUTTON: 1510 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON"; 1511 case FLAG_REQUEST_FINGERPRINT_GESTURES: 1512 return "FLAG_REQUEST_FINGERPRINT_GESTURES"; 1513 case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK: 1514 return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK"; 1515 case FLAG_INPUT_METHOD_EDITOR: 1516 return "FLAG_INPUT_METHOD_EDITOR"; 1517 default: 1518 return null; 1519 } 1520 } 1521 1522 /** 1523 * Returns the string representation of a capability. For example, 1524 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 1525 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 1526 * 1527 * @param capability The capability. 1528 * @return The string representation. 1529 */ capabilityToString(int capability)1530 public static String capabilityToString(int capability) { 1531 switch (capability) { 1532 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 1533 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 1534 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 1535 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 1536 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 1537 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS"; 1538 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 1539 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 1540 case CAPABILITY_CAN_PERFORM_GESTURES: 1541 return "CAPABILITY_CAN_PERFORM_GESTURES"; 1542 case CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES: 1543 return "CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES"; 1544 case CAPABILITY_CAN_TAKE_SCREENSHOT: 1545 return "CAPABILITY_CAN_TAKE_SCREENSHOT"; 1546 default: 1547 return "UNKNOWN"; 1548 } 1549 } 1550 1551 /** 1552 * @hide 1553 * @return The list of {@link CapabilityInfo} objects. 1554 * @deprecated The version that takes a context works better. 1555 */ getCapabilityInfos()1556 public List<CapabilityInfo> getCapabilityInfos() { 1557 return getCapabilityInfos(null); 1558 } 1559 1560 /** 1561 * @hide 1562 * @param context A valid context 1563 * @return The list of {@link CapabilityInfo} objects. 1564 */ getCapabilityInfos(Context context)1565 public List<CapabilityInfo> getCapabilityInfos(Context context) { 1566 if (mCapabilities == 0) { 1567 return Collections.emptyList(); 1568 } 1569 int capabilities = mCapabilities; 1570 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 1571 SparseArray<CapabilityInfo> capabilityInfoSparseArray = 1572 getCapabilityInfoSparseArray(context); 1573 while (capabilities != 0) { 1574 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 1575 capabilities &= ~capabilityBit; 1576 CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit); 1577 if (capabilityInfo != null) { 1578 capabilityInfos.add(capabilityInfo); 1579 } 1580 } 1581 return capabilityInfos; 1582 } 1583 getCapabilityInfoSparseArray(Context context)1584 private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) { 1585 if (sAvailableCapabilityInfos == null) { 1586 sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>(); 1587 sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1588 new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1589 R.string.capability_title_canRetrieveWindowContent, 1590 R.string.capability_desc_canRetrieveWindowContent)); 1591 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1592 new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1593 R.string.capability_title_canRequestTouchExploration, 1594 R.string.capability_desc_canRequestTouchExploration)); 1595 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1596 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1597 R.string.capability_title_canRequestFilterKeyEvents, 1598 R.string.capability_desc_canRequestFilterKeyEvents)); 1599 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1600 new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1601 R.string.capability_title_canControlMagnification, 1602 R.string.capability_desc_canControlMagnification)); 1603 sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES, 1604 new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES, 1605 R.string.capability_title_canPerformGestures, 1606 R.string.capability_desc_canPerformGestures)); 1607 sAvailableCapabilityInfos.put(CAPABILITY_CAN_TAKE_SCREENSHOT, 1608 new CapabilityInfo(CAPABILITY_CAN_TAKE_SCREENSHOT, 1609 R.string.capability_title_canTakeScreenshot, 1610 R.string.capability_desc_canTakeScreenshot)); 1611 if ((context == null) || fingerprintAvailable(context)) { 1612 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES, 1613 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES, 1614 R.string.capability_title_canCaptureFingerprintGestures, 1615 R.string.capability_desc_canCaptureFingerprintGestures)); 1616 } 1617 } 1618 return sAvailableCapabilityInfos; 1619 } 1620 fingerprintAvailable(Context context)1621 private static boolean fingerprintAvailable(Context context) { 1622 return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT) 1623 && context.getSystemService(FingerprintManager.class).isHardwareDetected(); 1624 } 1625 /** 1626 * @hide 1627 */ 1628 public static final class CapabilityInfo { 1629 public final int capability; 1630 public final int titleResId; 1631 public final int descResId; 1632 CapabilityInfo(int capability, int titleResId, int descResId)1633 public CapabilityInfo(int capability, int titleResId, int descResId) { 1634 this.capability = capability; 1635 this.titleResId = titleResId; 1636 this.descResId = descResId; 1637 } 1638 } 1639 1640 /** 1641 * @see Parcelable.Creator 1642 */ 1643 public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 1644 new Parcelable.Creator<AccessibilityServiceInfo>() { 1645 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 1646 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 1647 info.initFromParcel(parcel); 1648 return info; 1649 } 1650 1651 public AccessibilityServiceInfo[] newArray(int size) { 1652 return new AccessibilityServiceInfo[size]; 1653 } 1654 }; 1655 } 1656