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