AccessibilityServiceInfo.java revision 3822896e226567c6cd3ef84518d318abd33a7624
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 */ 153 public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE= 0x0000004; 154 155 /** 156 * This flag requests from the system to enable web accessibility enhancing 157 * extensions. Such extensions aim to provide improved accessibility support 158 * for content presented in a {@link android.webkit.WebView}. An example of such 159 * an extension is injecting JavaScript from Google. The system will enable 160 * enhanced web accessibility if there is at least one accessibility service 161 * that has this flag set. Hence, clearing this flag does not guarantee that the 162 * device will not have enhanced web accessibility enabled since there may be 163 * another enabled service that requested it. 164 */ 165 public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008; 166 167 /** 168 * This flag requests that the {@link AccessibilityNodeInfo}s obtained 169 * by an {@link AccessibilityService} contain the id of the source view. 170 * The source view id will be a fully qualified resource name of the 171 * form "package:id/name", for example "foo.bar:id/my_list", and it is 172 * useful for UI test automation. This flag is not set by default. 173 */ 174 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010; 175 176 /** 177 * The event types an {@link AccessibilityService} is interested in. 178 * <p> 179 * <strong>Can be dynamically set at runtime.</strong> 180 * </p> 181 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED 182 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED 183 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED 184 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED 185 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED 186 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 187 * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED 188 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START 189 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END 190 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER 191 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT 192 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED 193 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED 194 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED 195 */ 196 public int eventTypes; 197 198 /** 199 * The package names an {@link AccessibilityService} is interested in. Setting 200 * to <code>null</code> is equivalent to all packages. 201 * <p> 202 * <strong>Can be dynamically set at runtime.</strong> 203 * </p> 204 */ 205 public String[] packageNames; 206 207 /** 208 * The feedback type an {@link AccessibilityService} provides. 209 * <p> 210 * <strong>Can be dynamically set at runtime.</strong> 211 * </p> 212 * @see #FEEDBACK_AUDIBLE 213 * @see #FEEDBACK_GENERIC 214 * @see #FEEDBACK_HAPTIC 215 * @see #FEEDBACK_SPOKEN 216 * @see #FEEDBACK_VISUAL 217 * @see #FEEDBACK_BRAILLE 218 */ 219 public int feedbackType; 220 221 /** 222 * The timeout after the most recent event of a given type before an 223 * {@link AccessibilityService} is notified. 224 * <p> 225 * <strong>Can be dynamically set at runtime.</strong>. 226 * </p> 227 * <p> 228 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 229 * events to the client too frequently since this is accomplished via an expensive 230 * interprocess call. One can think of the timeout as a criteria to determine when 231 * event generation has settled down. 232 */ 233 public long notificationTimeout; 234 235 /** 236 * This field represents a set of flags used for configuring an 237 * {@link AccessibilityService}. 238 * <p> 239 * <strong>Can be dynamically set at runtime.</strong> 240 * </p> 241 * @see #DEFAULT 242 * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 243 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 244 */ 245 public int flags; 246 247 /** 248 * The unique string Id to identify the accessibility service. 249 */ 250 private String mId; 251 252 /** 253 * The Service that implements this accessibility service component. 254 */ 255 private ResolveInfo mResolveInfo; 256 257 /** 258 * The accessibility service setting activity's name, used by the system 259 * settings to launch the setting activity of this accessibility service. 260 */ 261 private String mSettingsActivityName; 262 263 /** 264 * Flag whether this accessibility service can retrieve window content. 265 */ 266 private boolean mCanRetrieveWindowContent; 267 268 /** 269 * Resource id of the description of the accessibility service. 270 */ 271 private int mDescriptionResId; 272 273 /** 274 * Non localized description of the accessibility service. 275 */ 276 private String mNonLocalizedDescription; 277 278 /** 279 * Creates a new instance. 280 */ 281 public AccessibilityServiceInfo() { 282 /* do nothing */ 283 } 284 285 /** 286 * Creates a new instance. 287 * 288 * @param resolveInfo The service resolve info. 289 * @param context Context for accessing resources. 290 * @throws XmlPullParserException If a XML parsing error occurs. 291 * @throws IOException If a XML parsing error occurs. 292 * 293 * @hide 294 */ 295 public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context) 296 throws XmlPullParserException, IOException { 297 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 298 mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString(); 299 mResolveInfo = resolveInfo; 300 301 XmlResourceParser parser = null; 302 303 try { 304 PackageManager packageManager = context.getPackageManager(); 305 parser = serviceInfo.loadXmlMetaData(packageManager, 306 AccessibilityService.SERVICE_META_DATA); 307 if (parser == null) { 308 return; 309 } 310 311 int type = 0; 312 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 313 type = parser.next(); 314 } 315 316 String nodeName = parser.getName(); 317 if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) { 318 throw new XmlPullParserException( "Meta-data does not start with" 319 + TAG_ACCESSIBILITY_SERVICE + " tag"); 320 } 321 322 AttributeSet allAttributes = Xml.asAttributeSet(parser); 323 Resources resources = packageManager.getResourcesForApplication( 324 serviceInfo.applicationInfo); 325 TypedArray asAttributes = resources.obtainAttributes(allAttributes, 326 com.android.internal.R.styleable.AccessibilityService); 327 eventTypes = asAttributes.getInt( 328 com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes, 329 0); 330 String packageNamez = asAttributes.getString( 331 com.android.internal.R.styleable.AccessibilityService_packageNames); 332 if (packageNamez != null) { 333 packageNames = packageNamez.split("(\\s)*,(\\s)*"); 334 } 335 feedbackType = asAttributes.getInt( 336 com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType, 337 0); 338 notificationTimeout = asAttributes.getInt( 339 com.android.internal.R.styleable.AccessibilityService_notificationTimeout, 340 0); 341 flags = asAttributes.getInt( 342 com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); 343 mSettingsActivityName = asAttributes.getString( 344 com.android.internal.R.styleable.AccessibilityService_settingsActivity); 345 mCanRetrieveWindowContent = asAttributes.getBoolean( 346 com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent, 347 false); 348 TypedValue peekedValue = asAttributes.peekValue( 349 com.android.internal.R.styleable.AccessibilityService_description); 350 if (peekedValue != null) { 351 mDescriptionResId = peekedValue.resourceId; 352 CharSequence nonLocalizedDescription = peekedValue.coerceToString(); 353 if (nonLocalizedDescription != null) { 354 mNonLocalizedDescription = nonLocalizedDescription.toString().trim(); 355 } 356 } 357 asAttributes.recycle(); 358 } catch (NameNotFoundException e) { 359 throw new XmlPullParserException( "Unable to create context for: " 360 + serviceInfo.packageName); 361 } finally { 362 if (parser != null) { 363 parser.close(); 364 } 365 } 366 } 367 368 /** 369 * Updates the properties that an AccessibilitySerivice can change dynamically. 370 * 371 * @param other The info from which to update the properties. 372 * 373 * @hide 374 */ 375 public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) { 376 eventTypes = other.eventTypes; 377 packageNames = other.packageNames; 378 feedbackType = other.feedbackType; 379 notificationTimeout = other.notificationTimeout; 380 flags = other.flags; 381 } 382 383 /** 384 * The accessibility service id. 385 * <p> 386 * <strong>Generated by the system.</strong> 387 * </p> 388 * @return The id. 389 */ 390 public String getId() { 391 return mId; 392 } 393 394 /** 395 * The service {@link ResolveInfo}. 396 * <p> 397 * <strong>Generated by the system.</strong> 398 * </p> 399 * @return The info. 400 */ 401 public ResolveInfo getResolveInfo() { 402 return mResolveInfo; 403 } 404 405 /** 406 * The settings activity name. 407 * <p> 408 * <strong>Statically set from 409 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 410 * </p> 411 * @return The settings activity name. 412 */ 413 public String getSettingsActivityName() { 414 return mSettingsActivityName; 415 } 416 417 /** 418 * Whether this service can retrieve the current window's content. 419 * <p> 420 * <strong>Statically set from 421 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 422 * </p> 423 * @return True if window content can be retrieved. 424 */ 425 public boolean getCanRetrieveWindowContent() { 426 return mCanRetrieveWindowContent; 427 } 428 429 /** 430 * Gets the non-localized description of the accessibility service. 431 * <p> 432 * <strong>Statically set from 433 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 434 * </p> 435 * @return The description. 436 * 437 * @deprecated Use {@link #loadDescription(PackageManager)}. 438 */ 439 public String getDescription() { 440 return mNonLocalizedDescription; 441 } 442 443 /** 444 * The localized description of the accessibility service. 445 * <p> 446 * <strong>Statically set from 447 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 448 * </p> 449 * @return The localized description. 450 */ 451 public String loadDescription(PackageManager packageManager) { 452 if (mDescriptionResId == 0) { 453 return mNonLocalizedDescription; 454 } 455 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 456 CharSequence description = packageManager.getText(serviceInfo.packageName, 457 mDescriptionResId, serviceInfo.applicationInfo); 458 if (description != null) { 459 return description.toString().trim(); 460 } 461 return null; 462 } 463 464 /** 465 * {@inheritDoc} 466 */ 467 public int describeContents() { 468 return 0; 469 } 470 471 public void writeToParcel(Parcel parcel, int flagz) { 472 parcel.writeInt(eventTypes); 473 parcel.writeStringArray(packageNames); 474 parcel.writeInt(feedbackType); 475 parcel.writeLong(notificationTimeout); 476 parcel.writeInt(flags); 477 parcel.writeString(mId); 478 parcel.writeParcelable(mResolveInfo, 0); 479 parcel.writeString(mSettingsActivityName); 480 parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0); 481 parcel.writeInt(mDescriptionResId); 482 parcel.writeString(mNonLocalizedDescription); 483 } 484 485 private void initFromParcel(Parcel parcel) { 486 eventTypes = parcel.readInt(); 487 packageNames = parcel.readStringArray(); 488 feedbackType = parcel.readInt(); 489 notificationTimeout = parcel.readLong(); 490 flags = parcel.readInt(); 491 mId = parcel.readString(); 492 mResolveInfo = parcel.readParcelable(null); 493 mSettingsActivityName = parcel.readString(); 494 mCanRetrieveWindowContent = (parcel.readInt() == 1); 495 mDescriptionResId = parcel.readInt(); 496 mNonLocalizedDescription = parcel.readString(); 497 } 498 499 @Override 500 public String toString() { 501 StringBuilder stringBuilder = new StringBuilder(); 502 appendEventTypes(stringBuilder, eventTypes); 503 stringBuilder.append(", "); 504 appendPackageNames(stringBuilder, packageNames); 505 stringBuilder.append(", "); 506 appendFeedbackTypes(stringBuilder, feedbackType); 507 stringBuilder.append(", "); 508 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 509 stringBuilder.append(", "); 510 appendFlags(stringBuilder, flags); 511 stringBuilder.append(", "); 512 stringBuilder.append("id: ").append(mId); 513 stringBuilder.append(", "); 514 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 515 stringBuilder.append(", "); 516 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 517 stringBuilder.append(", "); 518 stringBuilder.append("retrieveScreenContent: ").append(mCanRetrieveWindowContent); 519 return stringBuilder.toString(); 520 } 521 522 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 523 stringBuilder.append("feedbackTypes:"); 524 stringBuilder.append("["); 525 while (feedbackTypes != 0) { 526 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 527 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 528 feedbackTypes &= ~feedbackTypeBit; 529 if (feedbackTypes != 0) { 530 stringBuilder.append(", "); 531 } 532 } 533 stringBuilder.append("]"); 534 } 535 536 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 537 stringBuilder.append("packageNames:"); 538 stringBuilder.append("["); 539 if (packageNames != null) { 540 final int packageNameCount = packageNames.length; 541 for (int i = 0; i < packageNameCount; i++) { 542 stringBuilder.append(packageNames[i]); 543 if (i < packageNameCount - 1) { 544 stringBuilder.append(", "); 545 } 546 } 547 } 548 stringBuilder.append("]"); 549 } 550 551 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 552 stringBuilder.append("eventTypes:"); 553 stringBuilder.append("["); 554 while (eventTypes != 0) { 555 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 556 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 557 eventTypes &= ~eventTypeBit; 558 if (eventTypes != 0) { 559 stringBuilder.append(", "); 560 } 561 } 562 stringBuilder.append("]"); 563 } 564 565 private static void appendFlags(StringBuilder stringBuilder, int flags) { 566 stringBuilder.append("flags:"); 567 stringBuilder.append("["); 568 while (flags != 0) { 569 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 570 stringBuilder.append(flagToString(flagBit)); 571 flags &= ~flagBit; 572 if (flags != 0) { 573 stringBuilder.append(", "); 574 } 575 } 576 stringBuilder.append("]"); 577 } 578 579 /** 580 * Returns the string representation of a feedback type. For example, 581 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 582 * 583 * @param feedbackType The feedback type. 584 * @return The string representation. 585 */ 586 public static String feedbackTypeToString(int feedbackType) { 587 StringBuilder builder = new StringBuilder(); 588 builder.append("["); 589 while (feedbackType != 0) { 590 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 591 feedbackType &= ~feedbackTypeFlag; 592 switch (feedbackTypeFlag) { 593 case FEEDBACK_AUDIBLE: 594 if (builder.length() > 1) { 595 builder.append(", "); 596 } 597 builder.append("FEEDBACK_AUDIBLE"); 598 break; 599 case FEEDBACK_HAPTIC: 600 if (builder.length() > 1) { 601 builder.append(", "); 602 } 603 builder.append("FEEDBACK_HAPTIC"); 604 break; 605 case FEEDBACK_GENERIC: 606 if (builder.length() > 1) { 607 builder.append(", "); 608 } 609 builder.append("FEEDBACK_GENERIC"); 610 break; 611 case FEEDBACK_SPOKEN: 612 if (builder.length() > 1) { 613 builder.append(", "); 614 } 615 builder.append("FEEDBACK_SPOKEN"); 616 break; 617 case FEEDBACK_VISUAL: 618 if (builder.length() > 1) { 619 builder.append(", "); 620 } 621 builder.append("FEEDBACK_VISUAL"); 622 break; 623 case FEEDBACK_BRAILLE: 624 if (builder.length() > 1) { 625 builder.append(", "); 626 } 627 builder.append("FEEDBACK_BRAILLE"); 628 break; 629 } 630 } 631 builder.append("]"); 632 return builder.toString(); 633 } 634 635 /** 636 * Returns the string representation of a flag. For example, 637 * {@link #DEFAULT} is represented by the string DEFAULT. 638 * 639 * @param flag The flag. 640 * @return The string representation. 641 */ 642 public static String flagToString(int flag) { 643 switch (flag) { 644 case DEFAULT: 645 return "DEFAULT"; 646 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 647 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 648 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 649 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 650 default: 651 return null; 652 } 653 } 654 655 /** 656 * @see Parcelable.Creator 657 */ 658 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 659 new Parcelable.Creator<AccessibilityServiceInfo>() { 660 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 661 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 662 info.initFromParcel(parcel); 663 return info; 664 } 665 666 public AccessibilityServiceInfo[] newArray(int size) { 667 return new AccessibilityServiceInfo[size]; 668 } 669 }; 670} 671