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