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