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