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