AccessibilityServiceInfo.java revision 688a6977cf7673ed0542ab3d839053c4e38a4dbd
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.os.Build; 29import android.os.Parcel; 30import android.os.Parcelable; 31import android.util.AttributeSet; 32import android.util.SparseArray; 33import android.util.TypedValue; 34import android.util.Xml; 35import android.view.View; 36import android.view.accessibility.AccessibilityEvent; 37import android.view.accessibility.AccessibilityNodeInfo; 38 39import org.xmlpull.v1.XmlPullParser; 40import org.xmlpull.v1.XmlPullParserException; 41 42import com.android.internal.R; 43 44import java.io.IOException; 45import java.util.ArrayList; 46import java.util.Collections; 47import 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 */ 65public 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 { 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)); 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)); 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)); 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 555 public int getCapabilities() { 556 return mCapabilities; 557 } 558 559 /** 560 * Gets the non-localized description of the accessibility service. 561 * <p> 562 * <strong>Statically set from 563 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 564 * </p> 565 * @return The description. 566 * 567 * @deprecated Use {@link #loadDescription(PackageManager)}. 568 */ 569 public String getDescription() { 570 return mNonLocalizedDescription; 571 } 572 573 /** 574 * The localized description of the accessibility service. 575 * <p> 576 * <strong>Statically set from 577 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 578 * </p> 579 * @return The localized description. 580 */ 581 public String loadDescription(PackageManager packageManager) { 582 if (mDescriptionResId == 0) { 583 return mNonLocalizedDescription; 584 } 585 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 586 CharSequence description = packageManager.getText(serviceInfo.packageName, 587 mDescriptionResId, serviceInfo.applicationInfo); 588 if (description != null) { 589 return description.toString().trim(); 590 } 591 return null; 592 } 593 594 /** 595 * {@inheritDoc} 596 */ 597 public int describeContents() { 598 return 0; 599 } 600 601 public void writeToParcel(Parcel parcel, int flagz) { 602 parcel.writeInt(eventTypes); 603 parcel.writeStringArray(packageNames); 604 parcel.writeInt(feedbackType); 605 parcel.writeLong(notificationTimeout); 606 parcel.writeInt(flags); 607 parcel.writeString(mId); 608 parcel.writeParcelable(mResolveInfo, 0); 609 parcel.writeString(mSettingsActivityName); 610 parcel.writeInt(mCapabilities); 611 parcel.writeInt(mDescriptionResId); 612 parcel.writeString(mNonLocalizedDescription); 613 } 614 615 private void initFromParcel(Parcel parcel) { 616 eventTypes = parcel.readInt(); 617 packageNames = parcel.readStringArray(); 618 feedbackType = parcel.readInt(); 619 notificationTimeout = parcel.readLong(); 620 flags = parcel.readInt(); 621 mId = parcel.readString(); 622 mResolveInfo = parcel.readParcelable(null); 623 mSettingsActivityName = parcel.readString(); 624 mCapabilities = parcel.readInt(); 625 mDescriptionResId = parcel.readInt(); 626 mNonLocalizedDescription = parcel.readString(); 627 } 628 629 @Override 630 public int hashCode() { 631 return 31 * 1 + ((mId == null) ? 0 : mId.hashCode()); 632 } 633 634 @Override 635 public boolean equals(Object obj) { 636 if (this == obj) { 637 return true; 638 } 639 if (obj == null) { 640 return false; 641 } 642 if (getClass() != obj.getClass()) { 643 return false; 644 } 645 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 646 if (mId == null) { 647 if (other.mId != null) { 648 return false; 649 } 650 } else if (!mId.equals(other.mId)) { 651 return false; 652 } 653 return true; 654 } 655 656 @Override 657 public String toString() { 658 StringBuilder stringBuilder = new StringBuilder(); 659 appendEventTypes(stringBuilder, eventTypes); 660 stringBuilder.append(", "); 661 appendPackageNames(stringBuilder, packageNames); 662 stringBuilder.append(", "); 663 appendFeedbackTypes(stringBuilder, feedbackType); 664 stringBuilder.append(", "); 665 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 666 stringBuilder.append(", "); 667 appendFlags(stringBuilder, flags); 668 stringBuilder.append(", "); 669 stringBuilder.append("id: ").append(mId); 670 stringBuilder.append(", "); 671 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 672 stringBuilder.append(", "); 673 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 674 stringBuilder.append(", "); 675 appendCapabilities(stringBuilder, mCapabilities); 676 return stringBuilder.toString(); 677 } 678 679 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 680 stringBuilder.append("feedbackTypes:"); 681 stringBuilder.append("["); 682 while (feedbackTypes != 0) { 683 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 684 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 685 feedbackTypes &= ~feedbackTypeBit; 686 if (feedbackTypes != 0) { 687 stringBuilder.append(", "); 688 } 689 } 690 stringBuilder.append("]"); 691 } 692 693 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 694 stringBuilder.append("packageNames:"); 695 stringBuilder.append("["); 696 if (packageNames != null) { 697 final int packageNameCount = packageNames.length; 698 for (int i = 0; i < packageNameCount; i++) { 699 stringBuilder.append(packageNames[i]); 700 if (i < packageNameCount - 1) { 701 stringBuilder.append(", "); 702 } 703 } 704 } 705 stringBuilder.append("]"); 706 } 707 708 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 709 stringBuilder.append("eventTypes:"); 710 stringBuilder.append("["); 711 while (eventTypes != 0) { 712 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 713 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 714 eventTypes &= ~eventTypeBit; 715 if (eventTypes != 0) { 716 stringBuilder.append(", "); 717 } 718 } 719 stringBuilder.append("]"); 720 } 721 722 private static void appendFlags(StringBuilder stringBuilder, int flags) { 723 stringBuilder.append("flags:"); 724 stringBuilder.append("["); 725 while (flags != 0) { 726 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 727 stringBuilder.append(flagToString(flagBit)); 728 flags &= ~flagBit; 729 if (flags != 0) { 730 stringBuilder.append(", "); 731 } 732 } 733 stringBuilder.append("]"); 734 } 735 736 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 737 stringBuilder.append("capabilities:"); 738 stringBuilder.append("["); 739 while (capabilities != 0) { 740 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 741 stringBuilder.append(capabilityToString(capabilityBit)); 742 capabilities &= ~capabilityBit; 743 if (capabilities != 0) { 744 stringBuilder.append(", "); 745 } 746 } 747 stringBuilder.append("]"); 748 } 749 750 /** 751 * Returns the string representation of a feedback type. For example, 752 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 753 * 754 * @param feedbackType The feedback type. 755 * @return The string representation. 756 */ 757 public static String feedbackTypeToString(int feedbackType) { 758 StringBuilder builder = new StringBuilder(); 759 builder.append("["); 760 while (feedbackType != 0) { 761 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 762 feedbackType &= ~feedbackTypeFlag; 763 switch (feedbackTypeFlag) { 764 case FEEDBACK_AUDIBLE: 765 if (builder.length() > 1) { 766 builder.append(", "); 767 } 768 builder.append("FEEDBACK_AUDIBLE"); 769 break; 770 case FEEDBACK_HAPTIC: 771 if (builder.length() > 1) { 772 builder.append(", "); 773 } 774 builder.append("FEEDBACK_HAPTIC"); 775 break; 776 case FEEDBACK_GENERIC: 777 if (builder.length() > 1) { 778 builder.append(", "); 779 } 780 builder.append("FEEDBACK_GENERIC"); 781 break; 782 case FEEDBACK_SPOKEN: 783 if (builder.length() > 1) { 784 builder.append(", "); 785 } 786 builder.append("FEEDBACK_SPOKEN"); 787 break; 788 case FEEDBACK_VISUAL: 789 if (builder.length() > 1) { 790 builder.append(", "); 791 } 792 builder.append("FEEDBACK_VISUAL"); 793 break; 794 case FEEDBACK_BRAILLE: 795 if (builder.length() > 1) { 796 builder.append(", "); 797 } 798 builder.append("FEEDBACK_BRAILLE"); 799 break; 800 } 801 } 802 builder.append("]"); 803 return builder.toString(); 804 } 805 806 /** 807 * Returns the string representation of a flag. For example, 808 * {@link #DEFAULT} is represented by the string DEFAULT. 809 * 810 * @param flag The flag. 811 * @return The string representation. 812 */ 813 public static String flagToString(int flag) { 814 switch (flag) { 815 case DEFAULT: 816 return "DEFAULT"; 817 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 818 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 819 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 820 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 821 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 822 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 823 case FLAG_REPORT_VIEW_IDS: 824 return "FLAG_REPORT_VIEW_IDS"; 825 case FLAG_REQUEST_FILTER_KEY_EVENTS: 826 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 827 default: 828 return null; 829 } 830 } 831 832 /** 833 * Returns the string representation of a capability. For example, 834 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 835 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 836 * 837 * @param capability The capability. 838 * @return The string representation. 839 */ 840 public static String capabilityToString(int capability) { 841 switch (capability) { 842 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 843 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 844 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 845 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 846 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 847 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 848 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 849 return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; 850 default: 851 return "UNKNOWN"; 852 } 853 } 854 855 /** 856 * @hide 857 * @return The list of {@link CapabilityInfo} objects. 858 */ 859 public List<CapabilityInfo> getCapabilityInfos() { 860 if (mCapabilities == 0) { 861 return Collections.emptyList(); 862 } 863 int capabilities = mCapabilities; 864 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 865 while (capabilities != 0) { 866 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 867 capabilities &= ~capabilityBit; 868 CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit); 869 if (capabilityInfo != null) { 870 capabilityInfos.add(capabilityInfo); 871 } 872 } 873 return capabilityInfos; 874 } 875 876 /** 877 * @hide 878 */ 879 public static final class CapabilityInfo { 880 public final int capability; 881 public final int titleResId; 882 public final int descResId; 883 884 public CapabilityInfo(int capability, int titleResId, int descResId) { 885 this.capability = capability; 886 this.titleResId = titleResId; 887 this.descResId = descResId; 888 } 889 } 890 891 /** 892 * @see Parcelable.Creator 893 */ 894 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 895 new Parcelable.Creator<AccessibilityServiceInfo>() { 896 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 897 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 898 info.initFromParcel(parcel); 899 return info; 900 } 901 902 public AccessibilityServiceInfo[] newArray(int size) { 903 return new AccessibilityServiceInfo[size]; 904 } 905 }; 906} 907