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