AccessibilityServiceInfo.java revision 447d94684ee73046d769649d8247aacd581bd6e3
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 Google. 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 * The accessibility service id. 403 * <p> 404 * <strong>Generated by the system.</strong> 405 * </p> 406 * @return The id. 407 */ 408 public String getId() { 409 return mId; 410 } 411 412 /** 413 * The service {@link ResolveInfo}. 414 * <p> 415 * <strong>Generated by the system.</strong> 416 * </p> 417 * @return The info. 418 */ 419 public ResolveInfo getResolveInfo() { 420 return mResolveInfo; 421 } 422 423 /** 424 * The settings activity name. 425 * <p> 426 * <strong>Statically set from 427 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 428 * </p> 429 * @return The settings activity name. 430 */ 431 public String getSettingsActivityName() { 432 return mSettingsActivityName; 433 } 434 435 /** 436 * Whether this service can retrieve the current window's content. 437 * <p> 438 * <strong>Statically set from 439 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 440 * </p> 441 * @return True if window content can be retrieved. 442 */ 443 public boolean getCanRetrieveWindowContent() { 444 return mCanRetrieveWindowContent; 445 } 446 447 /** 448 * Gets the non-localized description of the accessibility service. 449 * <p> 450 * <strong>Statically set from 451 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 452 * </p> 453 * @return The description. 454 * 455 * @deprecated Use {@link #loadDescription(PackageManager)}. 456 */ 457 public String getDescription() { 458 return mNonLocalizedDescription; 459 } 460 461 /** 462 * The localized description of the accessibility service. 463 * <p> 464 * <strong>Statically set from 465 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 466 * </p> 467 * @return The localized description. 468 */ 469 public String loadDescription(PackageManager packageManager) { 470 if (mDescriptionResId == 0) { 471 return mNonLocalizedDescription; 472 } 473 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 474 CharSequence description = packageManager.getText(serviceInfo.packageName, 475 mDescriptionResId, serviceInfo.applicationInfo); 476 if (description != null) { 477 return description.toString().trim(); 478 } 479 return null; 480 } 481 482 /** 483 * {@inheritDoc} 484 */ 485 public int describeContents() { 486 return 0; 487 } 488 489 public void writeToParcel(Parcel parcel, int flagz) { 490 parcel.writeInt(eventTypes); 491 parcel.writeStringArray(packageNames); 492 parcel.writeInt(feedbackType); 493 parcel.writeLong(notificationTimeout); 494 parcel.writeInt(flags); 495 parcel.writeString(mId); 496 parcel.writeParcelable(mResolveInfo, 0); 497 parcel.writeString(mSettingsActivityName); 498 parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0); 499 parcel.writeInt(mDescriptionResId); 500 parcel.writeString(mNonLocalizedDescription); 501 } 502 503 private void initFromParcel(Parcel parcel) { 504 eventTypes = parcel.readInt(); 505 packageNames = parcel.readStringArray(); 506 feedbackType = parcel.readInt(); 507 notificationTimeout = parcel.readLong(); 508 flags = parcel.readInt(); 509 mId = parcel.readString(); 510 mResolveInfo = parcel.readParcelable(null); 511 mSettingsActivityName = parcel.readString(); 512 mCanRetrieveWindowContent = (parcel.readInt() == 1); 513 mDescriptionResId = parcel.readInt(); 514 mNonLocalizedDescription = parcel.readString(); 515 } 516 517 @Override 518 public String toString() { 519 StringBuilder stringBuilder = new StringBuilder(); 520 appendEventTypes(stringBuilder, eventTypes); 521 stringBuilder.append(", "); 522 appendPackageNames(stringBuilder, packageNames); 523 stringBuilder.append(", "); 524 appendFeedbackTypes(stringBuilder, feedbackType); 525 stringBuilder.append(", "); 526 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 527 stringBuilder.append(", "); 528 appendFlags(stringBuilder, flags); 529 stringBuilder.append(", "); 530 stringBuilder.append("id: ").append(mId); 531 stringBuilder.append(", "); 532 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 533 stringBuilder.append(", "); 534 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 535 stringBuilder.append(", "); 536 stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent); 537 return stringBuilder.toString(); 538 } 539 540 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 541 stringBuilder.append("feedbackTypes:"); 542 stringBuilder.append("["); 543 while (feedbackTypes != 0) { 544 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 545 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 546 feedbackTypes &= ~feedbackTypeBit; 547 if (feedbackTypes != 0) { 548 stringBuilder.append(", "); 549 } 550 } 551 stringBuilder.append("]"); 552 } 553 554 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 555 stringBuilder.append("packageNames:"); 556 stringBuilder.append("["); 557 if (packageNames != null) { 558 final int packageNameCount = packageNames.length; 559 for (int i = 0; i < packageNameCount; i++) { 560 stringBuilder.append(packageNames[i]); 561 if (i < packageNameCount - 1) { 562 stringBuilder.append(", "); 563 } 564 } 565 } 566 stringBuilder.append("]"); 567 } 568 569 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 570 stringBuilder.append("eventTypes:"); 571 stringBuilder.append("["); 572 while (eventTypes != 0) { 573 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 574 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 575 eventTypes &= ~eventTypeBit; 576 if (eventTypes != 0) { 577 stringBuilder.append(", "); 578 } 579 } 580 stringBuilder.append("]"); 581 } 582 583 private static void appendFlags(StringBuilder stringBuilder, int flags) { 584 stringBuilder.append("flags:"); 585 stringBuilder.append("["); 586 while (flags != 0) { 587 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 588 stringBuilder.append(flagToString(flagBit)); 589 flags &= ~flagBit; 590 if (flags != 0) { 591 stringBuilder.append(", "); 592 } 593 } 594 stringBuilder.append("]"); 595 } 596 597 /** 598 * Returns the string representation of a feedback type. For example, 599 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 600 * 601 * @param feedbackType The feedback type. 602 * @return The string representation. 603 */ 604 public static String feedbackTypeToString(int feedbackType) { 605 StringBuilder builder = new StringBuilder(); 606 builder.append("["); 607 while (feedbackType != 0) { 608 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 609 feedbackType &= ~feedbackTypeFlag; 610 switch (feedbackTypeFlag) { 611 case FEEDBACK_AUDIBLE: 612 if (builder.length() > 1) { 613 builder.append(", "); 614 } 615 builder.append("FEEDBACK_AUDIBLE"); 616 break; 617 case FEEDBACK_HAPTIC: 618 if (builder.length() > 1) { 619 builder.append(", "); 620 } 621 builder.append("FEEDBACK_HAPTIC"); 622 break; 623 case FEEDBACK_GENERIC: 624 if (builder.length() > 1) { 625 builder.append(", "); 626 } 627 builder.append("FEEDBACK_GENERIC"); 628 break; 629 case FEEDBACK_SPOKEN: 630 if (builder.length() > 1) { 631 builder.append(", "); 632 } 633 builder.append("FEEDBACK_SPOKEN"); 634 break; 635 case FEEDBACK_VISUAL: 636 if (builder.length() > 1) { 637 builder.append(", "); 638 } 639 builder.append("FEEDBACK_VISUAL"); 640 break; 641 case FEEDBACK_BRAILLE: 642 if (builder.length() > 1) { 643 builder.append(", "); 644 } 645 builder.append("FEEDBACK_BRAILLE"); 646 break; 647 } 648 } 649 builder.append("]"); 650 return builder.toString(); 651 } 652 653 /** 654 * Returns the string representation of a flag. For example, 655 * {@link #DEFAULT} is represented by the string DEFAULT. 656 * 657 * @param flag The flag. 658 * @return The string representation. 659 */ 660 public static String flagToString(int flag) { 661 switch (flag) { 662 case DEFAULT: 663 return "DEFAULT"; 664 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 665 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 666 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 667 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 668 default: 669 return null; 670 } 671 } 672 673 /** 674 * @see Parcelable.Creator 675 */ 676 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 677 new Parcelable.Creator<AccessibilityServiceInfo>() { 678 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 679 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 680 info.initFromParcel(parcel); 681 return info; 682 } 683 684 public AccessibilityServiceInfo[] newArray(int size) { 685 return new AccessibilityServiceInfo[size]; 686 } 687 }; 688} 689