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 /** {@hide} */ 368 public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; 369 370 /** 371 * The event types an {@link AccessibilityService} is interested in. 372 * <p> 373 * <strong>Can be dynamically set at runtime.</strong> 374 * </p> 375 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED 376 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED 377 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED 378 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED 379 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED 380 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 381 * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED 382 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START 383 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END 384 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER 385 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT 386 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED 387 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED 388 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED 389 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START 390 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END 391 * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT 392 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START 393 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END 394 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED 395 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 396 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 397 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED 398 */ 399 public int eventTypes; 400 401 /** 402 * The package names an {@link AccessibilityService} is interested in. Setting 403 * to <code>null</code> is equivalent to all packages. 404 * <p> 405 * <strong>Can be dynamically set at runtime.</strong> 406 * </p> 407 */ 408 public String[] packageNames; 409 410 411 /** @hide */ 412 @IntDef(flag = true, prefix = { "FEEDBACK_" }, value = { 413 FEEDBACK_AUDIBLE, 414 FEEDBACK_GENERIC, 415 FEEDBACK_HAPTIC, 416 FEEDBACK_SPOKEN, 417 FEEDBACK_VISUAL, 418 FEEDBACK_BRAILLE 419 }) 420 @Retention(RetentionPolicy.SOURCE) 421 public @interface FeedbackType {} 422 423 /** 424 * The feedback type an {@link AccessibilityService} provides. 425 * <p> 426 * <strong>Can be dynamically set at runtime.</strong> 427 * </p> 428 * @see #FEEDBACK_AUDIBLE 429 * @see #FEEDBACK_GENERIC 430 * @see #FEEDBACK_HAPTIC 431 * @see #FEEDBACK_SPOKEN 432 * @see #FEEDBACK_VISUAL 433 * @see #FEEDBACK_BRAILLE 434 */ 435 @FeedbackType 436 public int feedbackType; 437 438 /** 439 * The timeout, in milliseconds, after the most recent event of a given type before an 440 * {@link AccessibilityService} is notified. 441 * <p> 442 * <strong>Can be dynamically set at runtime.</strong> 443 * </p> 444 * <p> 445 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 446 * events to the client too frequently since this is accomplished via an expensive 447 * interprocess call. One can think of the timeout as a criteria to determine when 448 * event generation has settled down. 449 */ 450 public long notificationTimeout; 451 452 /** 453 * This field represents a set of flags used for configuring an 454 * {@link AccessibilityService}. 455 * <p> 456 * <strong>Can be dynamically set at runtime.</strong> 457 * </p> 458 * <p> 459 * <strong>Note:</strong> Accessibility services with targetSdkVersion greater than 460 * {@link Build.VERSION_CODES#Q API 29} cannot dynamically set the 461 * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} at runtime. It must be specified in the 462 * accessibility service metadata file. 463 * </p> 464 * @see #DEFAULT 465 * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 466 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 467 * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY 468 * @see #FLAG_REQUEST_FILTER_KEY_EVENTS 469 * @see #FLAG_REPORT_VIEW_IDS 470 * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS 471 * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME 472 * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON 473 * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK 474 */ 475 public int flags; 476 477 /** 478 * Whether or not the service has crashed and is awaiting restart. Only valid from {@link 479 * android.view.accessibility.AccessibilityManager#getInstalledAccessibilityServiceList()}, 480 * because that is populated from the internal list of running services. 481 * 482 * @hide 483 */ 484 public boolean crashed; 485 486 /** 487 * A recommended timeout in milliseconds for non-interactive controls. 488 */ 489 private int mNonInteractiveUiTimeout; 490 491 /** 492 * A recommended timeout in milliseconds for interactive controls. 493 */ 494 private int mInteractiveUiTimeout; 495 496 /** 497 * The component name the accessibility service. 498 */ 499 private ComponentName mComponentName; 500 501 /** 502 * The Service that implements this accessibility service component. 503 */ 504 private ResolveInfo mResolveInfo; 505 506 /** 507 * The accessibility service setting activity's name, used by the system 508 * settings to launch the setting activity of this accessibility service. 509 */ 510 private String mSettingsActivityName; 511 512 /** 513 * Bit mask with capabilities of this service. 514 */ 515 private int mCapabilities; 516 517 /** 518 * Resource id of the summary of the accessibility service. 519 */ 520 private int mSummaryResId; 521 522 /** 523 * Non-localized summary of the accessibility service. 524 */ 525 private String mNonLocalizedSummary; 526 527 /** 528 * Resource id of the description of the accessibility service. 529 */ 530 private int mDescriptionResId; 531 532 /** 533 * Non localized description of the accessibility service. 534 */ 535 private String mNonLocalizedDescription; 536 537 /** 538 * For accessibility services targeting APIs greater than {@link Build.VERSION_CODES#Q API 29}, 539 * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} must be specified in the accessibility service 540 * metadata file. Otherwise, it will be ignored. 541 */ 542 @ChangeId 543 @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q) 544 private static final long REQUEST_ACCESSIBILITY_BUTTON_CHANGE = 136293963L; 545 546 /** 547 * Resource id of the animated image of the accessibility service. 548 */ 549 private int mAnimatedImageRes; 550 551 /** 552 * Resource id of the html description of the accessibility service. 553 */ 554 private int mHtmlDescriptionRes; 555 556 /** 557 * Creates a new instance. 558 */ AccessibilityServiceInfo()559 public AccessibilityServiceInfo() { 560 /* do nothing */ 561 } 562 563 /** 564 * Creates a new instance. 565 * 566 * @param resolveInfo The service resolve info. 567 * @param context Context for accessing resources. 568 * @throws XmlPullParserException If a XML parsing error occurs. 569 * @throws IOException If a XML parsing error occurs. 570 * 571 * @hide 572 */ AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)573 public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context) 574 throws XmlPullParserException, IOException { 575 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 576 mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name); 577 mResolveInfo = resolveInfo; 578 579 XmlResourceParser parser = null; 580 581 try { 582 PackageManager packageManager = context.getPackageManager(); 583 parser = serviceInfo.loadXmlMetaData(packageManager, 584 AccessibilityService.SERVICE_META_DATA); 585 if (parser == null) { 586 return; 587 } 588 589 int type = 0; 590 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 591 type = parser.next(); 592 } 593 594 String nodeName = parser.getName(); 595 if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) { 596 throw new XmlPullParserException( "Meta-data does not start with" 597 + TAG_ACCESSIBILITY_SERVICE + " tag"); 598 } 599 600 AttributeSet allAttributes = Xml.asAttributeSet(parser); 601 Resources resources = packageManager.getResourcesForApplication( 602 serviceInfo.applicationInfo); 603 TypedArray asAttributes = resources.obtainAttributes(allAttributes, 604 com.android.internal.R.styleable.AccessibilityService); 605 eventTypes = asAttributes.getInt( 606 com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes, 607 0); 608 String packageNamez = asAttributes.getString( 609 com.android.internal.R.styleable.AccessibilityService_packageNames); 610 if (packageNamez != null) { 611 packageNames = packageNamez.split("(\\s)*,(\\s)*"); 612 } 613 feedbackType = asAttributes.getInt( 614 com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType, 615 0); 616 notificationTimeout = asAttributes.getInt( 617 com.android.internal.R.styleable.AccessibilityService_notificationTimeout, 618 0); 619 mNonInteractiveUiTimeout = asAttributes.getInt( 620 com.android.internal.R.styleable.AccessibilityService_nonInteractiveUiTimeout, 621 0); 622 mInteractiveUiTimeout = asAttributes.getInt( 623 com.android.internal.R.styleable.AccessibilityService_interactiveUiTimeout, 624 0); 625 flags = asAttributes.getInt( 626 com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); 627 mSettingsActivityName = asAttributes.getString( 628 com.android.internal.R.styleable.AccessibilityService_settingsActivity); 629 if (asAttributes.getBoolean(com.android.internal.R.styleable 630 .AccessibilityService_canRetrieveWindowContent, false)) { 631 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; 632 } 633 if (asAttributes.getBoolean(com.android.internal.R.styleable 634 .AccessibilityService_canRequestTouchExplorationMode, false)) { 635 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; 636 } 637 if (asAttributes.getBoolean(com.android.internal.R.styleable 638 .AccessibilityService_canRequestFilterKeyEvents, false)) { 639 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; 640 } 641 if (asAttributes.getBoolean(com.android.internal.R.styleable 642 .AccessibilityService_canControlMagnification, false)) { 643 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION; 644 } 645 if (asAttributes.getBoolean(com.android.internal.R.styleable 646 .AccessibilityService_canPerformGestures, false)) { 647 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES; 648 } 649 if (asAttributes.getBoolean(com.android.internal.R.styleable 650 .AccessibilityService_canRequestFingerprintGestures, false)) { 651 mCapabilities |= CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES; 652 } 653 if (asAttributes.getBoolean(com.android.internal.R.styleable 654 .AccessibilityService_canTakeScreenshot, false)) { 655 mCapabilities |= CAPABILITY_CAN_TAKE_SCREENSHOT; 656 } 657 TypedValue peekedValue = asAttributes.peekValue( 658 com.android.internal.R.styleable.AccessibilityService_description); 659 if (peekedValue != null) { 660 mDescriptionResId = peekedValue.resourceId; 661 CharSequence nonLocalizedDescription = peekedValue.coerceToString(); 662 if (nonLocalizedDescription != null) { 663 mNonLocalizedDescription = nonLocalizedDescription.toString().trim(); 664 } 665 } 666 peekedValue = asAttributes.peekValue( 667 com.android.internal.R.styleable.AccessibilityService_summary); 668 if (peekedValue != null) { 669 mSummaryResId = peekedValue.resourceId; 670 CharSequence nonLocalizedSummary = peekedValue.coerceToString(); 671 if (nonLocalizedSummary != null) { 672 mNonLocalizedSummary = nonLocalizedSummary.toString().trim(); 673 } 674 } 675 peekedValue = asAttributes.peekValue( 676 com.android.internal.R.styleable.AccessibilityService_animatedImageDrawable); 677 if (peekedValue != null) { 678 mAnimatedImageRes = peekedValue.resourceId; 679 } 680 peekedValue = asAttributes.peekValue( 681 com.android.internal.R.styleable.AccessibilityService_htmlDescription); 682 if (peekedValue != null) { 683 mHtmlDescriptionRes = peekedValue.resourceId; 684 } 685 asAttributes.recycle(); 686 } catch (NameNotFoundException e) { 687 throw new XmlPullParserException( "Unable to create context for: " 688 + serviceInfo.packageName); 689 } finally { 690 if (parser != null) { 691 parser.close(); 692 } 693 } 694 } 695 696 /** 697 * Updates the properties that an AccessibilityService can change dynamically. 698 * <p> 699 * Note: A11y services targeting APIs > Q, it cannot update flagRequestAccessibilityButton 700 * dynamically. 701 * </p> 702 * 703 * @param platformCompat The platform compat service to check the compatibility change. 704 * @param other The info from which to update the properties. 705 * 706 * @hide 707 */ updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat, AccessibilityServiceInfo other)708 public void updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat, 709 AccessibilityServiceInfo other) { 710 if (isRequestAccessibilityButtonChangeEnabled(platformCompat)) { 711 other.flags &= ~FLAG_REQUEST_ACCESSIBILITY_BUTTON; 712 other.flags |= (flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON); 713 } 714 eventTypes = other.eventTypes; 715 packageNames = other.packageNames; 716 feedbackType = other.feedbackType; 717 notificationTimeout = other.notificationTimeout; 718 mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout; 719 mInteractiveUiTimeout = other.mInteractiveUiTimeout; 720 flags = other.flags; 721 } 722 isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat)723 private boolean isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat) { 724 if (mResolveInfo == null) { 725 return true; 726 } 727 try { 728 if (platformCompat != null) { 729 return platformCompat.isChangeEnabled(REQUEST_ACCESSIBILITY_BUTTON_CHANGE, 730 mResolveInfo.serviceInfo.applicationInfo); 731 } 732 } catch (RemoteException ignore) { 733 } 734 return mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q; 735 } 736 737 /** 738 * @hide 739 */ setComponentName(ComponentName component)740 public void setComponentName(ComponentName component) { 741 mComponentName = component; 742 } 743 744 /** 745 * @hide 746 */ getComponentName()747 public ComponentName getComponentName() { 748 return mComponentName; 749 } 750 751 /** 752 * The accessibility service id. 753 * <p> 754 * <strong>Generated by the system.</strong> 755 * </p> 756 * @return The id. 757 */ getId()758 public String getId() { 759 return mComponentName.flattenToShortString(); 760 } 761 762 /** 763 * The service {@link ResolveInfo}. 764 * <p> 765 * <strong>Generated by the system.</strong> 766 * </p> 767 * @return The info. 768 */ getResolveInfo()769 public ResolveInfo getResolveInfo() { 770 return mResolveInfo; 771 } 772 773 /** 774 * The settings activity name. 775 * <p> 776 * <strong>Statically set from 777 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 778 * </p> 779 * @return The settings activity name. 780 */ getSettingsActivityName()781 public String getSettingsActivityName() { 782 return mSettingsActivityName; 783 } 784 785 /** 786 * Gets the animated image resource id. 787 * 788 * @return The animated image resource id. 789 * 790 * @hide 791 */ getAnimatedImageRes()792 public int getAnimatedImageRes() { 793 return mAnimatedImageRes; 794 } 795 796 /** 797 * The animated image drawable. 798 * <p> 799 * Image can not exceed the screen size. 800 * <strong>Statically set from 801 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 802 * </p> 803 * @return The animated image drawable, or null if the resource is invalid or the image 804 * exceed the screen size. 805 * 806 * @hide 807 */ 808 @Nullable loadAnimatedImage(@onNull Context context)809 public Drawable loadAnimatedImage(@NonNull Context context) { 810 if (mAnimatedImageRes == /* invalid */ 0) { 811 return null; 812 } 813 814 return loadSafeAnimatedImage(context, mResolveInfo.serviceInfo.applicationInfo, 815 mAnimatedImageRes); 816 } 817 818 /** 819 * Whether this service can retrieve the current window's content. 820 * <p> 821 * <strong>Statically set from 822 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 823 * </p> 824 * @return True if window content can be retrieved. 825 * 826 * @deprecated Use {@link #getCapabilities()}. 827 */ getCanRetrieveWindowContent()828 public boolean getCanRetrieveWindowContent() { 829 return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 830 } 831 832 /** 833 * Returns the bit mask of capabilities this accessibility service has such as 834 * being able to retrieve the active window content, etc. 835 * 836 * @return The capability bit mask. 837 * 838 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 839 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 840 * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 841 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 842 * @see #CAPABILITY_CAN_PERFORM_GESTURES 843 * @see #CAPABILITY_CAN_TAKE_SCREENSHOT 844 */ getCapabilities()845 public int getCapabilities() { 846 return mCapabilities; 847 } 848 849 /** 850 * Sets the bit mask of capabilities this accessibility service has such as 851 * being able to retrieve the active window content, etc. 852 * 853 * @param capabilities The capability bit mask. 854 * 855 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 856 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 857 * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 858 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 859 * @see #CAPABILITY_CAN_PERFORM_GESTURES 860 * @see #CAPABILITY_CAN_TAKE_SCREENSHOT 861 * 862 * @hide 863 */ 864 @UnsupportedAppUsage setCapabilities(int capabilities)865 public void setCapabilities(int capabilities) { 866 mCapabilities = capabilities; 867 } 868 869 /** 870 * The localized summary of the accessibility service. 871 * <p> 872 * <strong>Statically set from 873 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 874 * </p> 875 * @return The localized summary if available, and {@code null} if a summary 876 * has not been provided. 877 */ loadSummary(PackageManager packageManager)878 public CharSequence loadSummary(PackageManager packageManager) { 879 if (mSummaryResId == 0) { 880 return mNonLocalizedSummary; 881 } 882 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 883 CharSequence summary = packageManager.getText(serviceInfo.packageName, 884 mSummaryResId, serviceInfo.applicationInfo); 885 if (summary != null) { 886 return summary.toString().trim(); 887 } 888 return null; 889 } 890 891 /** 892 * Gets the non-localized description of the accessibility service. 893 * <p> 894 * <strong>Statically set from 895 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 896 * </p> 897 * @return The description. 898 * 899 * @deprecated Use {@link #loadDescription(PackageManager)}. 900 */ getDescription()901 public String getDescription() { 902 return mNonLocalizedDescription; 903 } 904 905 /** 906 * The localized description of the accessibility service. 907 * <p> 908 * <strong>Statically set from 909 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 910 * </p> 911 * @return The localized description. 912 */ loadDescription(PackageManager packageManager)913 public String loadDescription(PackageManager packageManager) { 914 if (mDescriptionResId == 0) { 915 return mNonLocalizedDescription; 916 } 917 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 918 CharSequence description = packageManager.getText(serviceInfo.packageName, 919 mDescriptionResId, serviceInfo.applicationInfo); 920 if (description != null) { 921 return description.toString().trim(); 922 } 923 return null; 924 } 925 926 /** 927 * The localized and restricted html description of the accessibility service. 928 * <p> 929 * Filters the <img> tag which do not meet the custom specification and the <a> tag. 930 * <strong>Statically set from 931 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 932 * </p> 933 * @return The localized and restricted html description. 934 * 935 * @hide 936 */ 937 @Nullable loadHtmlDescription(@onNull PackageManager packageManager)938 public String loadHtmlDescription(@NonNull PackageManager packageManager) { 939 if (mHtmlDescriptionRes == /* invalid */ 0) { 940 return null; 941 } 942 943 final ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 944 final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName, 945 mHtmlDescriptionRes, serviceInfo.applicationInfo); 946 if (htmlDescription != null) { 947 return getFilteredHtmlText(htmlDescription.toString().trim()); 948 } 949 return null; 950 } 951 952 /** 953 * Set the recommended time that non-interactive controls need to remain on the screen to 954 * support the user. 955 * <p> 956 * <strong>This value can be dynamically set at runtime by 957 * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong> 958 * </p> 959 * 960 * @param timeout The timeout in milliseconds. 961 * 962 * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout 963 */ setNonInteractiveUiTimeoutMillis(@ntRangefrom = 0) int timeout)964 public void setNonInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) { 965 mNonInteractiveUiTimeout = timeout; 966 } 967 968 /** 969 * Get the recommended timeout for non-interactive controls. 970 * 971 * @return The timeout in milliseconds. 972 * 973 * @see #setNonInteractiveUiTimeoutMillis(int) 974 */ getNonInteractiveUiTimeoutMillis()975 public int getNonInteractiveUiTimeoutMillis() { 976 return mNonInteractiveUiTimeout; 977 } 978 979 /** 980 * Set the recommended time that interactive controls need to remain on the screen to 981 * support the user. 982 * <p> 983 * <strong>This value can be dynamically set at runtime by 984 * {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong> 985 * </p> 986 * 987 * @param timeout The timeout in milliseconds. 988 * 989 * @see android.R.styleable#AccessibilityService_interactiveUiTimeout 990 */ setInteractiveUiTimeoutMillis(@ntRangefrom = 0) int timeout)991 public void setInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) { 992 mInteractiveUiTimeout = timeout; 993 } 994 995 /** 996 * Get the recommended timeout for interactive controls. 997 * 998 * @return The timeout in milliseconds. 999 * 1000 * @see #setInteractiveUiTimeoutMillis(int) 1001 */ getInteractiveUiTimeoutMillis()1002 public int getInteractiveUiTimeoutMillis() { 1003 return mInteractiveUiTimeout; 1004 } 1005 1006 /** {@hide} */ isDirectBootAware()1007 public boolean isDirectBootAware() { 1008 return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0) 1009 || mResolveInfo.serviceInfo.directBootAware; 1010 } 1011 1012 /** 1013 * {@inheritDoc} 1014 */ describeContents()1015 public int describeContents() { 1016 return 0; 1017 } 1018 writeToParcel(Parcel parcel, int flagz)1019 public void writeToParcel(Parcel parcel, int flagz) { 1020 parcel.writeInt(eventTypes); 1021 parcel.writeStringArray(packageNames); 1022 parcel.writeInt(feedbackType); 1023 parcel.writeLong(notificationTimeout); 1024 parcel.writeInt(mNonInteractiveUiTimeout); 1025 parcel.writeInt(mInteractiveUiTimeout); 1026 parcel.writeInt(flags); 1027 parcel.writeInt(crashed ? 1 : 0); 1028 parcel.writeParcelable(mComponentName, flagz); 1029 parcel.writeParcelable(mResolveInfo, 0); 1030 parcel.writeString(mSettingsActivityName); 1031 parcel.writeInt(mCapabilities); 1032 parcel.writeInt(mSummaryResId); 1033 parcel.writeString(mNonLocalizedSummary); 1034 parcel.writeInt(mDescriptionResId); 1035 parcel.writeInt(mAnimatedImageRes); 1036 parcel.writeInt(mHtmlDescriptionRes); 1037 parcel.writeString(mNonLocalizedDescription); 1038 } 1039 initFromParcel(Parcel parcel)1040 private void initFromParcel(Parcel parcel) { 1041 eventTypes = parcel.readInt(); 1042 packageNames = parcel.readStringArray(); 1043 feedbackType = parcel.readInt(); 1044 notificationTimeout = parcel.readLong(); 1045 mNonInteractiveUiTimeout = parcel.readInt(); 1046 mInteractiveUiTimeout = parcel.readInt(); 1047 flags = parcel.readInt(); 1048 crashed = parcel.readInt() != 0; 1049 mComponentName = parcel.readParcelable(this.getClass().getClassLoader()); 1050 mResolveInfo = parcel.readParcelable(null); 1051 mSettingsActivityName = parcel.readString(); 1052 mCapabilities = parcel.readInt(); 1053 mSummaryResId = parcel.readInt(); 1054 mNonLocalizedSummary = parcel.readString(); 1055 mDescriptionResId = parcel.readInt(); 1056 mAnimatedImageRes = parcel.readInt(); 1057 mHtmlDescriptionRes = parcel.readInt(); 1058 mNonLocalizedDescription = parcel.readString(); 1059 } 1060 1061 @Override hashCode()1062 public int hashCode() { 1063 return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode()); 1064 } 1065 1066 @Override equals(Object obj)1067 public boolean equals(Object obj) { 1068 if (this == obj) { 1069 return true; 1070 } 1071 if (obj == null) { 1072 return false; 1073 } 1074 if (getClass() != obj.getClass()) { 1075 return false; 1076 } 1077 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 1078 if (mComponentName == null) { 1079 if (other.mComponentName != null) { 1080 return false; 1081 } 1082 } else if (!mComponentName.equals(other.mComponentName)) { 1083 return false; 1084 } 1085 return true; 1086 } 1087 1088 @Override toString()1089 public String toString() { 1090 StringBuilder stringBuilder = new StringBuilder(); 1091 appendEventTypes(stringBuilder, eventTypes); 1092 stringBuilder.append(", "); 1093 appendPackageNames(stringBuilder, packageNames); 1094 stringBuilder.append(", "); 1095 appendFeedbackTypes(stringBuilder, feedbackType); 1096 stringBuilder.append(", "); 1097 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 1098 stringBuilder.append(", "); 1099 stringBuilder.append("nonInteractiveUiTimeout: ").append(mNonInteractiveUiTimeout); 1100 stringBuilder.append(", "); 1101 stringBuilder.append("interactiveUiTimeout: ").append(mInteractiveUiTimeout); 1102 stringBuilder.append(", "); 1103 appendFlags(stringBuilder, flags); 1104 stringBuilder.append(", "); 1105 stringBuilder.append("id: ").append(getId()); 1106 stringBuilder.append(", "); 1107 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 1108 stringBuilder.append(", "); 1109 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 1110 stringBuilder.append(", "); 1111 stringBuilder.append("summary: ").append(mNonLocalizedSummary); 1112 stringBuilder.append(", "); 1113 appendCapabilities(stringBuilder, mCapabilities); 1114 return stringBuilder.toString(); 1115 } 1116 appendFeedbackTypes(StringBuilder stringBuilder, @FeedbackType int feedbackTypes)1117 private static void appendFeedbackTypes(StringBuilder stringBuilder, 1118 @FeedbackType int feedbackTypes) { 1119 stringBuilder.append("feedbackTypes:"); 1120 stringBuilder.append("["); 1121 while (feedbackTypes != 0) { 1122 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 1123 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 1124 feedbackTypes &= ~feedbackTypeBit; 1125 if (feedbackTypes != 0) { 1126 stringBuilder.append(", "); 1127 } 1128 } 1129 stringBuilder.append("]"); 1130 } 1131 appendPackageNames(StringBuilder stringBuilder, String[] packageNames)1132 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 1133 stringBuilder.append("packageNames:"); 1134 stringBuilder.append("["); 1135 if (packageNames != null) { 1136 final int packageNameCount = packageNames.length; 1137 for (int i = 0; i < packageNameCount; i++) { 1138 stringBuilder.append(packageNames[i]); 1139 if (i < packageNameCount - 1) { 1140 stringBuilder.append(", "); 1141 } 1142 } 1143 } 1144 stringBuilder.append("]"); 1145 } 1146 appendEventTypes(StringBuilder stringBuilder, int eventTypes)1147 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 1148 stringBuilder.append("eventTypes:"); 1149 stringBuilder.append("["); 1150 while (eventTypes != 0) { 1151 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 1152 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 1153 eventTypes &= ~eventTypeBit; 1154 if (eventTypes != 0) { 1155 stringBuilder.append(", "); 1156 } 1157 } 1158 stringBuilder.append("]"); 1159 } 1160 appendFlags(StringBuilder stringBuilder, int flags)1161 private static void appendFlags(StringBuilder stringBuilder, int flags) { 1162 stringBuilder.append("flags:"); 1163 stringBuilder.append("["); 1164 while (flags != 0) { 1165 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 1166 stringBuilder.append(flagToString(flagBit)); 1167 flags &= ~flagBit; 1168 if (flags != 0) { 1169 stringBuilder.append(", "); 1170 } 1171 } 1172 stringBuilder.append("]"); 1173 } 1174 appendCapabilities(StringBuilder stringBuilder, int capabilities)1175 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 1176 stringBuilder.append("capabilities:"); 1177 stringBuilder.append("["); 1178 while (capabilities != 0) { 1179 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 1180 stringBuilder.append(capabilityToString(capabilityBit)); 1181 capabilities &= ~capabilityBit; 1182 if (capabilities != 0) { 1183 stringBuilder.append(", "); 1184 } 1185 } 1186 stringBuilder.append("]"); 1187 } 1188 1189 /** 1190 * Returns the string representation of a feedback type. For example, 1191 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 1192 * 1193 * @param feedbackType The feedback type. 1194 * @return The string representation. 1195 */ feedbackTypeToString(int feedbackType)1196 public static String feedbackTypeToString(int feedbackType) { 1197 StringBuilder builder = new StringBuilder(); 1198 builder.append("["); 1199 while (feedbackType != 0) { 1200 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 1201 feedbackType &= ~feedbackTypeFlag; 1202 switch (feedbackTypeFlag) { 1203 case FEEDBACK_AUDIBLE: 1204 if (builder.length() > 1) { 1205 builder.append(", "); 1206 } 1207 builder.append("FEEDBACK_AUDIBLE"); 1208 break; 1209 case FEEDBACK_HAPTIC: 1210 if (builder.length() > 1) { 1211 builder.append(", "); 1212 } 1213 builder.append("FEEDBACK_HAPTIC"); 1214 break; 1215 case FEEDBACK_GENERIC: 1216 if (builder.length() > 1) { 1217 builder.append(", "); 1218 } 1219 builder.append("FEEDBACK_GENERIC"); 1220 break; 1221 case FEEDBACK_SPOKEN: 1222 if (builder.length() > 1) { 1223 builder.append(", "); 1224 } 1225 builder.append("FEEDBACK_SPOKEN"); 1226 break; 1227 case FEEDBACK_VISUAL: 1228 if (builder.length() > 1) { 1229 builder.append(", "); 1230 } 1231 builder.append("FEEDBACK_VISUAL"); 1232 break; 1233 case FEEDBACK_BRAILLE: 1234 if (builder.length() > 1) { 1235 builder.append(", "); 1236 } 1237 builder.append("FEEDBACK_BRAILLE"); 1238 break; 1239 } 1240 } 1241 builder.append("]"); 1242 return builder.toString(); 1243 } 1244 1245 /** 1246 * Returns the string representation of a flag. For example, 1247 * {@link #DEFAULT} is represented by the string DEFAULT. 1248 * 1249 * @param flag The flag. 1250 * @return The string representation. 1251 */ flagToString(int flag)1252 public static String flagToString(int flag) { 1253 switch (flag) { 1254 case DEFAULT: 1255 return "DEFAULT"; 1256 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 1257 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 1258 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 1259 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 1260 case FLAG_SERVICE_HANDLES_DOUBLE_TAP: 1261 return "FLAG_SERVICE_HANDLES_DOUBLE_TAP"; 1262 case FLAG_REQUEST_MULTI_FINGER_GESTURES: 1263 return "FLAG_REQUEST_MULTI_FINGER_GESTURES"; 1264 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 1265 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 1266 case FLAG_REPORT_VIEW_IDS: 1267 return "FLAG_REPORT_VIEW_IDS"; 1268 case FLAG_REQUEST_FILTER_KEY_EVENTS: 1269 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 1270 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 1271 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 1272 case FLAG_ENABLE_ACCESSIBILITY_VOLUME: 1273 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME"; 1274 case FLAG_REQUEST_ACCESSIBILITY_BUTTON: 1275 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON"; 1276 case FLAG_REQUEST_FINGERPRINT_GESTURES: 1277 return "FLAG_REQUEST_FINGERPRINT_GESTURES"; 1278 case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK: 1279 return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK"; 1280 default: 1281 return null; 1282 } 1283 } 1284 1285 /** 1286 * Returns the string representation of a capability. For example, 1287 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 1288 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 1289 * 1290 * @param capability The capability. 1291 * @return The string representation. 1292 */ capabilityToString(int capability)1293 public static String capabilityToString(int capability) { 1294 switch (capability) { 1295 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 1296 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 1297 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 1298 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 1299 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 1300 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 1301 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 1302 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS"; 1303 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 1304 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 1305 case CAPABILITY_CAN_PERFORM_GESTURES: 1306 return "CAPABILITY_CAN_PERFORM_GESTURES"; 1307 case CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES: 1308 return "CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES"; 1309 case CAPABILITY_CAN_TAKE_SCREENSHOT: 1310 return "CAPABILITY_CAN_TAKE_SCREENSHOT"; 1311 default: 1312 return "UNKNOWN"; 1313 } 1314 } 1315 1316 /** 1317 * @hide 1318 * @return The list of {@link CapabilityInfo} objects. 1319 * @deprecated The version that takes a context works better. 1320 */ getCapabilityInfos()1321 public List<CapabilityInfo> getCapabilityInfos() { 1322 return getCapabilityInfos(null); 1323 } 1324 1325 /** 1326 * @hide 1327 * @param context A valid context 1328 * @return The list of {@link CapabilityInfo} objects. 1329 */ getCapabilityInfos(Context context)1330 public List<CapabilityInfo> getCapabilityInfos(Context context) { 1331 if (mCapabilities == 0) { 1332 return Collections.emptyList(); 1333 } 1334 int capabilities = mCapabilities; 1335 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 1336 SparseArray<CapabilityInfo> capabilityInfoSparseArray = 1337 getCapabilityInfoSparseArray(context); 1338 while (capabilities != 0) { 1339 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 1340 capabilities &= ~capabilityBit; 1341 CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit); 1342 if (capabilityInfo != null) { 1343 capabilityInfos.add(capabilityInfo); 1344 } 1345 } 1346 return capabilityInfos; 1347 } 1348 getCapabilityInfoSparseArray(Context context)1349 private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) { 1350 if (sAvailableCapabilityInfos == null) { 1351 sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>(); 1352 sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1353 new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1354 R.string.capability_title_canRetrieveWindowContent, 1355 R.string.capability_desc_canRetrieveWindowContent)); 1356 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1357 new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1358 R.string.capability_title_canRequestTouchExploration, 1359 R.string.capability_desc_canRequestTouchExploration)); 1360 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1361 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1362 R.string.capability_title_canRequestFilterKeyEvents, 1363 R.string.capability_desc_canRequestFilterKeyEvents)); 1364 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1365 new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1366 R.string.capability_title_canControlMagnification, 1367 R.string.capability_desc_canControlMagnification)); 1368 sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES, 1369 new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES, 1370 R.string.capability_title_canPerformGestures, 1371 R.string.capability_desc_canPerformGestures)); 1372 sAvailableCapabilityInfos.put(CAPABILITY_CAN_TAKE_SCREENSHOT, 1373 new CapabilityInfo(CAPABILITY_CAN_TAKE_SCREENSHOT, 1374 R.string.capability_title_canTakeScreenshot, 1375 R.string.capability_desc_canTakeScreenshot)); 1376 if ((context == null) || fingerprintAvailable(context)) { 1377 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES, 1378 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES, 1379 R.string.capability_title_canCaptureFingerprintGestures, 1380 R.string.capability_desc_canCaptureFingerprintGestures)); 1381 } 1382 } 1383 return sAvailableCapabilityInfos; 1384 } 1385 fingerprintAvailable(Context context)1386 private static boolean fingerprintAvailable(Context context) { 1387 return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT) 1388 && context.getSystemService(FingerprintManager.class).isHardwareDetected(); 1389 } 1390 /** 1391 * @hide 1392 */ 1393 public static final class CapabilityInfo { 1394 public final int capability; 1395 public final int titleResId; 1396 public final int descResId; 1397 CapabilityInfo(int capability, int titleResId, int descResId)1398 public CapabilityInfo(int capability, int titleResId, int descResId) { 1399 this.capability = capability; 1400 this.titleResId = titleResId; 1401 this.descResId = descResId; 1402 } 1403 } 1404 1405 /** 1406 * @see Parcelable.Creator 1407 */ 1408 public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 1409 new Parcelable.Creator<AccessibilityServiceInfo>() { 1410 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 1411 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 1412 info.initFromParcel(parcel); 1413 return info; 1414 } 1415 1416 public AccessibilityServiceInfo[] newArray(int size) { 1417 return new AccessibilityServiceInfo[size]; 1418 } 1419 }; 1420 } 1421