AccessibilityServiceInfo.java revision 08c41bcf5fab665cebc820ea813be52f6ecc3154
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. 697 */ 698 public String loadSummary(PackageManager packageManager) { 699 if (mSummaryResId == 0) { 700 return mNonLocalizedSummary; 701 } 702 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 703 CharSequence summary = packageManager.getText(serviceInfo.packageName, 704 mSummaryResId, serviceInfo.applicationInfo); 705 if (summary != null) { 706 return summary.toString().trim(); 707 } 708 return null; 709 } 710 711 /** 712 * Gets the non-localized description of the accessibility service. 713 * <p> 714 * <strong>Statically set from 715 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 716 * </p> 717 * @return The description. 718 * 719 * @deprecated Use {@link #loadDescription(PackageManager)}. 720 */ 721 public String getDescription() { 722 return mNonLocalizedDescription; 723 } 724 725 /** 726 * The localized description of the accessibility service. 727 * <p> 728 * <strong>Statically set from 729 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 730 * </p> 731 * @return The localized description. 732 */ 733 public String loadDescription(PackageManager packageManager) { 734 if (mDescriptionResId == 0) { 735 return mNonLocalizedDescription; 736 } 737 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 738 CharSequence description = packageManager.getText(serviceInfo.packageName, 739 mDescriptionResId, serviceInfo.applicationInfo); 740 if (description != null) { 741 return description.toString().trim(); 742 } 743 return null; 744 } 745 746 /** {@hide} */ 747 public boolean isDirectBootAware() { 748 return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0) 749 || mResolveInfo.serviceInfo.directBootAware; 750 } 751 752 /** 753 * {@inheritDoc} 754 */ 755 public int describeContents() { 756 return 0; 757 } 758 759 public void writeToParcel(Parcel parcel, int flagz) { 760 parcel.writeInt(eventTypes); 761 parcel.writeStringArray(packageNames); 762 parcel.writeInt(feedbackType); 763 parcel.writeLong(notificationTimeout); 764 parcel.writeInt(flags); 765 parcel.writeParcelable(mComponentName, flagz); 766 parcel.writeParcelable(mResolveInfo, 0); 767 parcel.writeString(mSettingsActivityName); 768 parcel.writeInt(mCapabilities); 769 parcel.writeInt(mSummaryResId); 770 parcel.writeString(mNonLocalizedSummary); 771 parcel.writeInt(mDescriptionResId); 772 parcel.writeString(mNonLocalizedDescription); 773 } 774 775 private void initFromParcel(Parcel parcel) { 776 eventTypes = parcel.readInt(); 777 packageNames = parcel.readStringArray(); 778 feedbackType = parcel.readInt(); 779 notificationTimeout = parcel.readLong(); 780 flags = parcel.readInt(); 781 mComponentName = parcel.readParcelable(this.getClass().getClassLoader()); 782 mResolveInfo = parcel.readParcelable(null); 783 mSettingsActivityName = parcel.readString(); 784 mCapabilities = parcel.readInt(); 785 mSummaryResId = parcel.readInt(); 786 mNonLocalizedSummary = parcel.readString(); 787 mDescriptionResId = parcel.readInt(); 788 mNonLocalizedDescription = parcel.readString(); 789 } 790 791 @Override 792 public int hashCode() { 793 return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode()); 794 } 795 796 @Override 797 public boolean equals(Object obj) { 798 if (this == obj) { 799 return true; 800 } 801 if (obj == null) { 802 return false; 803 } 804 if (getClass() != obj.getClass()) { 805 return false; 806 } 807 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 808 if (mComponentName == null) { 809 if (other.mComponentName != null) { 810 return false; 811 } 812 } else if (!mComponentName.equals(other.mComponentName)) { 813 return false; 814 } 815 return true; 816 } 817 818 @Override 819 public String toString() { 820 StringBuilder stringBuilder = new StringBuilder(); 821 appendEventTypes(stringBuilder, eventTypes); 822 stringBuilder.append(", "); 823 appendPackageNames(stringBuilder, packageNames); 824 stringBuilder.append(", "); 825 appendFeedbackTypes(stringBuilder, feedbackType); 826 stringBuilder.append(", "); 827 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 828 stringBuilder.append(", "); 829 appendFlags(stringBuilder, flags); 830 stringBuilder.append(", "); 831 stringBuilder.append("id: ").append(getId()); 832 stringBuilder.append(", "); 833 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 834 stringBuilder.append(", "); 835 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 836 stringBuilder.append(", "); 837 stringBuilder.append("summary: ").append(mNonLocalizedSummary); 838 stringBuilder.append(", "); 839 appendCapabilities(stringBuilder, mCapabilities); 840 return stringBuilder.toString(); 841 } 842 843 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 844 stringBuilder.append("feedbackTypes:"); 845 stringBuilder.append("["); 846 while (feedbackTypes != 0) { 847 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 848 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 849 feedbackTypes &= ~feedbackTypeBit; 850 if (feedbackTypes != 0) { 851 stringBuilder.append(", "); 852 } 853 } 854 stringBuilder.append("]"); 855 } 856 857 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 858 stringBuilder.append("packageNames:"); 859 stringBuilder.append("["); 860 if (packageNames != null) { 861 final int packageNameCount = packageNames.length; 862 for (int i = 0; i < packageNameCount; i++) { 863 stringBuilder.append(packageNames[i]); 864 if (i < packageNameCount - 1) { 865 stringBuilder.append(", "); 866 } 867 } 868 } 869 stringBuilder.append("]"); 870 } 871 872 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 873 stringBuilder.append("eventTypes:"); 874 stringBuilder.append("["); 875 while (eventTypes != 0) { 876 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 877 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 878 eventTypes &= ~eventTypeBit; 879 if (eventTypes != 0) { 880 stringBuilder.append(", "); 881 } 882 } 883 stringBuilder.append("]"); 884 } 885 886 private static void appendFlags(StringBuilder stringBuilder, int flags) { 887 stringBuilder.append("flags:"); 888 stringBuilder.append("["); 889 while (flags != 0) { 890 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 891 stringBuilder.append(flagToString(flagBit)); 892 flags &= ~flagBit; 893 if (flags != 0) { 894 stringBuilder.append(", "); 895 } 896 } 897 stringBuilder.append("]"); 898 } 899 900 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 901 stringBuilder.append("capabilities:"); 902 stringBuilder.append("["); 903 while (capabilities != 0) { 904 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 905 stringBuilder.append(capabilityToString(capabilityBit)); 906 capabilities &= ~capabilityBit; 907 if (capabilities != 0) { 908 stringBuilder.append(", "); 909 } 910 } 911 stringBuilder.append("]"); 912 } 913 914 /** 915 * Returns the string representation of a feedback type. For example, 916 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 917 * 918 * @param feedbackType The feedback type. 919 * @return The string representation. 920 */ 921 public static String feedbackTypeToString(int feedbackType) { 922 StringBuilder builder = new StringBuilder(); 923 builder.append("["); 924 while (feedbackType != 0) { 925 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 926 feedbackType &= ~feedbackTypeFlag; 927 switch (feedbackTypeFlag) { 928 case FEEDBACK_AUDIBLE: 929 if (builder.length() > 1) { 930 builder.append(", "); 931 } 932 builder.append("FEEDBACK_AUDIBLE"); 933 break; 934 case FEEDBACK_HAPTIC: 935 if (builder.length() > 1) { 936 builder.append(", "); 937 } 938 builder.append("FEEDBACK_HAPTIC"); 939 break; 940 case FEEDBACK_GENERIC: 941 if (builder.length() > 1) { 942 builder.append(", "); 943 } 944 builder.append("FEEDBACK_GENERIC"); 945 break; 946 case FEEDBACK_SPOKEN: 947 if (builder.length() > 1) { 948 builder.append(", "); 949 } 950 builder.append("FEEDBACK_SPOKEN"); 951 break; 952 case FEEDBACK_VISUAL: 953 if (builder.length() > 1) { 954 builder.append(", "); 955 } 956 builder.append("FEEDBACK_VISUAL"); 957 break; 958 case FEEDBACK_BRAILLE: 959 if (builder.length() > 1) { 960 builder.append(", "); 961 } 962 builder.append("FEEDBACK_BRAILLE"); 963 break; 964 } 965 } 966 builder.append("]"); 967 return builder.toString(); 968 } 969 970 /** 971 * Returns the string representation of a flag. For example, 972 * {@link #DEFAULT} is represented by the string DEFAULT. 973 * 974 * @param flag The flag. 975 * @return The string representation. 976 */ 977 public static String flagToString(int flag) { 978 switch (flag) { 979 case DEFAULT: 980 return "DEFAULT"; 981 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 982 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 983 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 984 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 985 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 986 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 987 case FLAG_REPORT_VIEW_IDS: 988 return "FLAG_REPORT_VIEW_IDS"; 989 case FLAG_REQUEST_FILTER_KEY_EVENTS: 990 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 991 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 992 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 993 case FLAG_ENABLE_ACCESSIBILITY_VOLUME: 994 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME"; 995 case FLAG_REQUEST_ACCESSIBILITY_BUTTON: 996 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON"; 997 case FLAG_CAPTURE_FINGERPRINT_GESTURES: 998 return "FLAG_CAPTURE_FINGERPRINT_GESTURES"; 999 default: 1000 return null; 1001 } 1002 } 1003 1004 /** 1005 * Returns the string representation of a capability. For example, 1006 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 1007 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 1008 * 1009 * @param capability The capability. 1010 * @return The string representation. 1011 */ 1012 public static String capabilityToString(int capability) { 1013 switch (capability) { 1014 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 1015 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 1016 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 1017 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 1018 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 1019 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 1020 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 1021 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS"; 1022 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 1023 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 1024 case CAPABILITY_CAN_PERFORM_GESTURES: 1025 return "CAPABILITY_CAN_PERFORM_GESTURES"; 1026 case CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES: 1027 return "CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES"; 1028 default: 1029 return "UNKNOWN"; 1030 } 1031 } 1032 1033 /** 1034 * @hide 1035 * @return The list of {@link CapabilityInfo} objects. 1036 * @deprecated The version that takes a context works better. 1037 */ 1038 public List<CapabilityInfo> getCapabilityInfos() { 1039 return getCapabilityInfos(null); 1040 } 1041 1042 /** 1043 * @hide 1044 * @param context A valid context 1045 * @return The list of {@link CapabilityInfo} objects. 1046 */ 1047 public List<CapabilityInfo> getCapabilityInfos(Context context) { 1048 if (mCapabilities == 0) { 1049 return Collections.emptyList(); 1050 } 1051 int capabilities = mCapabilities; 1052 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 1053 SparseArray<CapabilityInfo> capabilityInfoSparseArray = 1054 getCapabilityInfoSparseArray(context); 1055 while (capabilities != 0) { 1056 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 1057 capabilities &= ~capabilityBit; 1058 CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit); 1059 if (capabilityInfo != null) { 1060 capabilityInfos.add(capabilityInfo); 1061 } 1062 } 1063 return capabilityInfos; 1064 } 1065 1066 private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) { 1067 if (sAvailableCapabilityInfos == null) { 1068 sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>(); 1069 sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1070 new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1071 R.string.capability_title_canRetrieveWindowContent, 1072 R.string.capability_desc_canRetrieveWindowContent)); 1073 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1074 new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1075 R.string.capability_title_canRequestTouchExploration, 1076 R.string.capability_desc_canRequestTouchExploration)); 1077 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, 1078 new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, 1079 R.string.capability_title_canRequestEnhancedWebAccessibility, 1080 R.string.capability_desc_canRequestEnhancedWebAccessibility)); 1081 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1082 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1083 R.string.capability_title_canRequestFilterKeyEvents, 1084 R.string.capability_desc_canRequestFilterKeyEvents)); 1085 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1086 new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1087 R.string.capability_title_canControlMagnification, 1088 R.string.capability_desc_canControlMagnification)); 1089 sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES, 1090 new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES, 1091 R.string.capability_title_canPerformGestures, 1092 R.string.capability_desc_canPerformGestures)); 1093 if ((context == null) || fingerprintAvailable(context)) { 1094 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES, 1095 new CapabilityInfo(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES, 1096 R.string.capability_title_canCaptureFingerprintGestures, 1097 R.string.capability_desc_canCaptureFingerprintGestures)); 1098 } 1099 } 1100 return sAvailableCapabilityInfos; 1101 } 1102 1103 private static boolean fingerprintAvailable(Context context) { 1104 return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT) 1105 && context.getSystemService(FingerprintManager.class).isHardwareDetected(); 1106 } 1107 /** 1108 * @hide 1109 */ 1110 public static final class CapabilityInfo { 1111 public final int capability; 1112 public final int titleResId; 1113 public final int descResId; 1114 1115 public CapabilityInfo(int capability, int titleResId, int descResId) { 1116 this.capability = capability; 1117 this.titleResId = titleResId; 1118 this.descResId = descResId; 1119 } 1120 } 1121 1122 /** 1123 * @see Parcelable.Creator 1124 */ 1125 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 1126 new Parcelable.Creator<AccessibilityServiceInfo>() { 1127 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 1128 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 1129 info.initFromParcel(parcel); 1130 return info; 1131 } 1132 1133 public AccessibilityServiceInfo[] newArray(int size) { 1134 return new AccessibilityServiceInfo[size]; 1135 } 1136 }; 1137} 1138