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