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