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