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