AccessibilityServiceInfo.java revision 7917a2f020b95a6372dd3c506183ea345ab5ae24
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_notificationTimeout 73 * @attr ref android.R.styleable#AccessibilityService_packageNames 74 * @attr ref android.R.styleable#AccessibilityService_settingsActivity 75 * 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 description of the accessibility service. 435 */ 436 private int mDescriptionResId; 437 438 /** 439 * Non localized description of the accessibility service. 440 */ 441 private String mNonLocalizedDescription; 442 443 /** 444 * Creates a new instance. 445 */ 446 public AccessibilityServiceInfo() { 447 /* do nothing */ 448 } 449 450 /** 451 * Creates a new instance. 452 * 453 * @param resolveInfo The service resolve info. 454 * @param context Context for accessing resources. 455 * @throws XmlPullParserException If a XML parsing error occurs. 456 * @throws IOException If a XML parsing error occurs. 457 * 458 * @hide 459 */ 460 public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context) 461 throws XmlPullParserException, IOException { 462 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 463 mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name); 464 mResolveInfo = resolveInfo; 465 466 XmlResourceParser parser = null; 467 468 try { 469 PackageManager packageManager = context.getPackageManager(); 470 parser = serviceInfo.loadXmlMetaData(packageManager, 471 AccessibilityService.SERVICE_META_DATA); 472 if (parser == null) { 473 return; 474 } 475 476 int type = 0; 477 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 478 type = parser.next(); 479 } 480 481 String nodeName = parser.getName(); 482 if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) { 483 throw new XmlPullParserException( "Meta-data does not start with" 484 + TAG_ACCESSIBILITY_SERVICE + " tag"); 485 } 486 487 AttributeSet allAttributes = Xml.asAttributeSet(parser); 488 Resources resources = packageManager.getResourcesForApplication( 489 serviceInfo.applicationInfo); 490 TypedArray asAttributes = resources.obtainAttributes(allAttributes, 491 com.android.internal.R.styleable.AccessibilityService); 492 eventTypes = asAttributes.getInt( 493 com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes, 494 0); 495 String packageNamez = asAttributes.getString( 496 com.android.internal.R.styleable.AccessibilityService_packageNames); 497 if (packageNamez != null) { 498 packageNames = packageNamez.split("(\\s)*,(\\s)*"); 499 } 500 feedbackType = asAttributes.getInt( 501 com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType, 502 0); 503 notificationTimeout = asAttributes.getInt( 504 com.android.internal.R.styleable.AccessibilityService_notificationTimeout, 505 0); 506 flags = asAttributes.getInt( 507 com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); 508 mSettingsActivityName = asAttributes.getString( 509 com.android.internal.R.styleable.AccessibilityService_settingsActivity); 510 if (asAttributes.getBoolean(com.android.internal.R.styleable 511 .AccessibilityService_canRetrieveWindowContent, false)) { 512 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; 513 } 514 if (asAttributes.getBoolean(com.android.internal.R.styleable 515 .AccessibilityService_canRequestTouchExplorationMode, false)) { 516 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; 517 } 518 if (asAttributes.getBoolean(com.android.internal.R.styleable 519 .AccessibilityService_canRequestEnhancedWebAccessibility, false)) { 520 mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY; 521 } 522 if (asAttributes.getBoolean(com.android.internal.R.styleable 523 .AccessibilityService_canRequestFilterKeyEvents, false)) { 524 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; 525 } 526 if (asAttributes.getBoolean(com.android.internal.R.styleable 527 .AccessibilityService_canControlMagnification, false)) { 528 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION; 529 } 530 if (asAttributes.getBoolean(com.android.internal.R.styleable 531 .AccessibilityService_canPerformGestures, false)) { 532 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES; 533 } 534 if (asAttributes.getBoolean(com.android.internal.R.styleable 535 .AccessibilityService_canCaptureFingerprintGestures, false)) { 536 mCapabilities |= CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES; 537 } 538 TypedValue peekedValue = asAttributes.peekValue( 539 com.android.internal.R.styleable.AccessibilityService_description); 540 if (peekedValue != null) { 541 mDescriptionResId = peekedValue.resourceId; 542 CharSequence nonLocalizedDescription = peekedValue.coerceToString(); 543 if (nonLocalizedDescription != null) { 544 mNonLocalizedDescription = nonLocalizedDescription.toString().trim(); 545 } 546 } 547 asAttributes.recycle(); 548 } catch (NameNotFoundException e) { 549 throw new XmlPullParserException( "Unable to create context for: " 550 + serviceInfo.packageName); 551 } finally { 552 if (parser != null) { 553 parser.close(); 554 } 555 } 556 } 557 558 /** 559 * Updates the properties that an AccessibilitySerivice can change dynamically. 560 * 561 * @param other The info from which to update the properties. 562 * 563 * @hide 564 */ 565 public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) { 566 eventTypes = other.eventTypes; 567 packageNames = other.packageNames; 568 feedbackType = other.feedbackType; 569 notificationTimeout = other.notificationTimeout; 570 flags = other.flags; 571 } 572 573 /** 574 * @hide 575 */ 576 public void setComponentName(ComponentName component) { 577 mComponentName = component; 578 } 579 580 /** 581 * @hide 582 */ 583 public ComponentName getComponentName() { 584 return mComponentName; 585 } 586 587 /** 588 * The accessibility service id. 589 * <p> 590 * <strong>Generated by the system.</strong> 591 * </p> 592 * @return The id. 593 */ 594 public String getId() { 595 return mComponentName.flattenToShortString(); 596 } 597 598 /** 599 * The service {@link ResolveInfo}. 600 * <p> 601 * <strong>Generated by the system.</strong> 602 * </p> 603 * @return The info. 604 */ 605 public ResolveInfo getResolveInfo() { 606 return mResolveInfo; 607 } 608 609 /** 610 * The settings activity name. 611 * <p> 612 * <strong>Statically set from 613 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 614 * </p> 615 * @return The settings activity name. 616 */ 617 public String getSettingsActivityName() { 618 return mSettingsActivityName; 619 } 620 621 /** 622 * Whether this service can retrieve the current window's content. 623 * <p> 624 * <strong>Statically set from 625 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 626 * </p> 627 * @return True if window content can be retrieved. 628 * 629 * @deprecated Use {@link #getCapabilities()}. 630 */ 631 public boolean getCanRetrieveWindowContent() { 632 return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 633 } 634 635 /** 636 * Returns the bit mask of capabilities this accessibility service has such as 637 * being able to retrieve the active window content, etc. 638 * 639 * @return The capability bit mask. 640 * 641 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 642 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 643 * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY 644 * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 645 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 646 * @see #CAPABILITY_CAN_PERFORM_GESTURES 647 */ 648 public int getCapabilities() { 649 return mCapabilities; 650 } 651 652 /** 653 * Sets the bit mask of capabilities this accessibility service has such as 654 * being able to retrieve the active window content, etc. 655 * 656 * @param capabilities The capability bit mask. 657 * 658 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 659 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 660 * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY 661 * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS 662 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 663 * @see #CAPABILITY_CAN_PERFORM_GESTURES 664 * 665 * @hide 666 */ 667 public void setCapabilities(int capabilities) { 668 mCapabilities = capabilities; 669 } 670 671 /** 672 * Gets the non-localized description of the accessibility service. 673 * <p> 674 * <strong>Statically set from 675 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 676 * </p> 677 * @return The description. 678 * 679 * @deprecated Use {@link #loadDescription(PackageManager)}. 680 */ 681 public String getDescription() { 682 return mNonLocalizedDescription; 683 } 684 685 /** 686 * The localized description of the accessibility service. 687 * <p> 688 * <strong>Statically set from 689 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 690 * </p> 691 * @return The localized description. 692 */ 693 public String loadDescription(PackageManager packageManager) { 694 if (mDescriptionResId == 0) { 695 return mNonLocalizedDescription; 696 } 697 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 698 CharSequence description = packageManager.getText(serviceInfo.packageName, 699 mDescriptionResId, serviceInfo.applicationInfo); 700 if (description != null) { 701 return description.toString().trim(); 702 } 703 return null; 704 } 705 706 /** {@hide} */ 707 public boolean isDirectBootAware() { 708 return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0) 709 || mResolveInfo.serviceInfo.directBootAware; 710 } 711 712 /** 713 * {@inheritDoc} 714 */ 715 public int describeContents() { 716 return 0; 717 } 718 719 public void writeToParcel(Parcel parcel, int flagz) { 720 parcel.writeInt(eventTypes); 721 parcel.writeStringArray(packageNames); 722 parcel.writeInt(feedbackType); 723 parcel.writeLong(notificationTimeout); 724 parcel.writeInt(flags); 725 parcel.writeParcelable(mComponentName, flagz); 726 parcel.writeParcelable(mResolveInfo, 0); 727 parcel.writeString(mSettingsActivityName); 728 parcel.writeInt(mCapabilities); 729 parcel.writeInt(mDescriptionResId); 730 parcel.writeString(mNonLocalizedDescription); 731 } 732 733 private void initFromParcel(Parcel parcel) { 734 eventTypes = parcel.readInt(); 735 packageNames = parcel.readStringArray(); 736 feedbackType = parcel.readInt(); 737 notificationTimeout = parcel.readLong(); 738 flags = parcel.readInt(); 739 mComponentName = parcel.readParcelable(this.getClass().getClassLoader()); 740 mResolveInfo = parcel.readParcelable(null); 741 mSettingsActivityName = parcel.readString(); 742 mCapabilities = parcel.readInt(); 743 mDescriptionResId = parcel.readInt(); 744 mNonLocalizedDescription = parcel.readString(); 745 } 746 747 @Override 748 public int hashCode() { 749 return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode()); 750 } 751 752 @Override 753 public boolean equals(Object obj) { 754 if (this == obj) { 755 return true; 756 } 757 if (obj == null) { 758 return false; 759 } 760 if (getClass() != obj.getClass()) { 761 return false; 762 } 763 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 764 if (mComponentName == null) { 765 if (other.mComponentName != null) { 766 return false; 767 } 768 } else if (!mComponentName.equals(other.mComponentName)) { 769 return false; 770 } 771 return true; 772 } 773 774 @Override 775 public String toString() { 776 StringBuilder stringBuilder = new StringBuilder(); 777 appendEventTypes(stringBuilder, eventTypes); 778 stringBuilder.append(", "); 779 appendPackageNames(stringBuilder, packageNames); 780 stringBuilder.append(", "); 781 appendFeedbackTypes(stringBuilder, feedbackType); 782 stringBuilder.append(", "); 783 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 784 stringBuilder.append(", "); 785 appendFlags(stringBuilder, flags); 786 stringBuilder.append(", "); 787 stringBuilder.append("id: ").append(getId()); 788 stringBuilder.append(", "); 789 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 790 stringBuilder.append(", "); 791 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 792 stringBuilder.append(", "); 793 appendCapabilities(stringBuilder, mCapabilities); 794 return stringBuilder.toString(); 795 } 796 797 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 798 stringBuilder.append("feedbackTypes:"); 799 stringBuilder.append("["); 800 while (feedbackTypes != 0) { 801 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 802 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 803 feedbackTypes &= ~feedbackTypeBit; 804 if (feedbackTypes != 0) { 805 stringBuilder.append(", "); 806 } 807 } 808 stringBuilder.append("]"); 809 } 810 811 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 812 stringBuilder.append("packageNames:"); 813 stringBuilder.append("["); 814 if (packageNames != null) { 815 final int packageNameCount = packageNames.length; 816 for (int i = 0; i < packageNameCount; i++) { 817 stringBuilder.append(packageNames[i]); 818 if (i < packageNameCount - 1) { 819 stringBuilder.append(", "); 820 } 821 } 822 } 823 stringBuilder.append("]"); 824 } 825 826 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 827 stringBuilder.append("eventTypes:"); 828 stringBuilder.append("["); 829 while (eventTypes != 0) { 830 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 831 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 832 eventTypes &= ~eventTypeBit; 833 if (eventTypes != 0) { 834 stringBuilder.append(", "); 835 } 836 } 837 stringBuilder.append("]"); 838 } 839 840 private static void appendFlags(StringBuilder stringBuilder, int flags) { 841 stringBuilder.append("flags:"); 842 stringBuilder.append("["); 843 while (flags != 0) { 844 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 845 stringBuilder.append(flagToString(flagBit)); 846 flags &= ~flagBit; 847 if (flags != 0) { 848 stringBuilder.append(", "); 849 } 850 } 851 stringBuilder.append("]"); 852 } 853 854 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 855 stringBuilder.append("capabilities:"); 856 stringBuilder.append("["); 857 while (capabilities != 0) { 858 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 859 stringBuilder.append(capabilityToString(capabilityBit)); 860 capabilities &= ~capabilityBit; 861 if (capabilities != 0) { 862 stringBuilder.append(", "); 863 } 864 } 865 stringBuilder.append("]"); 866 } 867 868 /** 869 * Returns the string representation of a feedback type. For example, 870 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 871 * 872 * @param feedbackType The feedback type. 873 * @return The string representation. 874 */ 875 public static String feedbackTypeToString(int feedbackType) { 876 StringBuilder builder = new StringBuilder(); 877 builder.append("["); 878 while (feedbackType != 0) { 879 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 880 feedbackType &= ~feedbackTypeFlag; 881 switch (feedbackTypeFlag) { 882 case FEEDBACK_AUDIBLE: 883 if (builder.length() > 1) { 884 builder.append(", "); 885 } 886 builder.append("FEEDBACK_AUDIBLE"); 887 break; 888 case FEEDBACK_HAPTIC: 889 if (builder.length() > 1) { 890 builder.append(", "); 891 } 892 builder.append("FEEDBACK_HAPTIC"); 893 break; 894 case FEEDBACK_GENERIC: 895 if (builder.length() > 1) { 896 builder.append(", "); 897 } 898 builder.append("FEEDBACK_GENERIC"); 899 break; 900 case FEEDBACK_SPOKEN: 901 if (builder.length() > 1) { 902 builder.append(", "); 903 } 904 builder.append("FEEDBACK_SPOKEN"); 905 break; 906 case FEEDBACK_VISUAL: 907 if (builder.length() > 1) { 908 builder.append(", "); 909 } 910 builder.append("FEEDBACK_VISUAL"); 911 break; 912 case FEEDBACK_BRAILLE: 913 if (builder.length() > 1) { 914 builder.append(", "); 915 } 916 builder.append("FEEDBACK_BRAILLE"); 917 break; 918 } 919 } 920 builder.append("]"); 921 return builder.toString(); 922 } 923 924 /** 925 * Returns the string representation of a flag. For example, 926 * {@link #DEFAULT} is represented by the string DEFAULT. 927 * 928 * @param flag The flag. 929 * @return The string representation. 930 */ 931 public static String flagToString(int flag) { 932 switch (flag) { 933 case DEFAULT: 934 return "DEFAULT"; 935 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 936 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 937 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 938 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 939 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 940 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 941 case FLAG_REPORT_VIEW_IDS: 942 return "FLAG_REPORT_VIEW_IDS"; 943 case FLAG_REQUEST_FILTER_KEY_EVENTS: 944 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 945 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 946 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 947 case FLAG_ENABLE_ACCESSIBILITY_VOLUME: 948 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME"; 949 case FLAG_REQUEST_ACCESSIBILITY_BUTTON: 950 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON"; 951 case FLAG_CAPTURE_FINGERPRINT_GESTURES: 952 return "FLAG_CAPTURE_FINGERPRINT_GESTURES"; 953 default: 954 return null; 955 } 956 } 957 958 /** 959 * Returns the string representation of a capability. For example, 960 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 961 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 962 * 963 * @param capability The capability. 964 * @return The string representation. 965 */ 966 public static String capabilityToString(int capability) { 967 switch (capability) { 968 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 969 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 970 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 971 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 972 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 973 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 974 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 975 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS"; 976 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 977 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 978 case CAPABILITY_CAN_PERFORM_GESTURES: 979 return "CAPABILITY_CAN_PERFORM_GESTURES"; 980 case CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES: 981 return "CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES"; 982 default: 983 return "UNKNOWN"; 984 } 985 } 986 987 /** 988 * @hide 989 * @return The list of {@link CapabilityInfo} objects. 990 * @deprecated The version that takes a context works better. 991 */ 992 public List<CapabilityInfo> getCapabilityInfos() { 993 return getCapabilityInfos(null); 994 } 995 996 /** 997 * @hide 998 * @param context A valid context 999 * @return The list of {@link CapabilityInfo} objects. 1000 */ 1001 public List<CapabilityInfo> getCapabilityInfos(Context context) { 1002 if (mCapabilities == 0) { 1003 return Collections.emptyList(); 1004 } 1005 int capabilities = mCapabilities; 1006 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 1007 SparseArray<CapabilityInfo> capabilityInfoSparseArray = 1008 getCapabilityInfoSparseArray(context); 1009 while (capabilities != 0) { 1010 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 1011 capabilities &= ~capabilityBit; 1012 CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit); 1013 if (capabilityInfo != null) { 1014 capabilityInfos.add(capabilityInfo); 1015 } 1016 } 1017 return capabilityInfos; 1018 } 1019 1020 private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) { 1021 if (sAvailableCapabilityInfos == null) { 1022 sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>(); 1023 sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1024 new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 1025 R.string.capability_title_canRetrieveWindowContent, 1026 R.string.capability_desc_canRetrieveWindowContent)); 1027 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1028 new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 1029 R.string.capability_title_canRequestTouchExploration, 1030 R.string.capability_desc_canRequestTouchExploration)); 1031 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, 1032 new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, 1033 R.string.capability_title_canRequestEnhancedWebAccessibility, 1034 R.string.capability_desc_canRequestEnhancedWebAccessibility)); 1035 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1036 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 1037 R.string.capability_title_canRequestFilterKeyEvents, 1038 R.string.capability_desc_canRequestFilterKeyEvents)); 1039 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1040 new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 1041 R.string.capability_title_canControlMagnification, 1042 R.string.capability_desc_canControlMagnification)); 1043 sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES, 1044 new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES, 1045 R.string.capability_title_canPerformGestures, 1046 R.string.capability_desc_canPerformGestures)); 1047 if ((context == null) || fingerprintAvailable(context)) { 1048 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES, 1049 new CapabilityInfo(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES, 1050 R.string.capability_title_canCaptureFingerprintGestures, 1051 R.string.capability_desc_canCaptureFingerprintGestures)); 1052 } 1053 } 1054 return sAvailableCapabilityInfos; 1055 } 1056 1057 private static boolean fingerprintAvailable(Context context) { 1058 return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT) 1059 && context.getSystemService(FingerprintManager.class).isHardwareDetected(); 1060 } 1061 /** 1062 * @hide 1063 */ 1064 public static final class CapabilityInfo { 1065 public final int capability; 1066 public final int titleResId; 1067 public final int descResId; 1068 1069 public CapabilityInfo(int capability, int titleResId, int descResId) { 1070 this.capability = capability; 1071 this.titleResId = titleResId; 1072 this.descResId = descResId; 1073 } 1074 } 1075 1076 /** 1077 * @see Parcelable.Creator 1078 */ 1079 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 1080 new Parcelable.Creator<AccessibilityServiceInfo>() { 1081 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 1082 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 1083 info.initFromParcel(parcel); 1084 return info; 1085 } 1086 1087 public AccessibilityServiceInfo[] newArray(int size) { 1088 return new AccessibilityServiceInfo[size]; 1089 } 1090 }; 1091} 1092