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