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