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