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