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