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