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.hardware.fingerprint.FingerprintManager;
     29 import android.os.Build;
     30 import android.os.Parcel;
     31 import android.os.Parcelable;
     32 import android.util.AttributeSet;
     33 import android.util.SparseArray;
     34 import android.util.TypedValue;
     35 import android.util.Xml;
     36 import android.view.View;
     37 import android.view.accessibility.AccessibilityEvent;
     38 import android.view.accessibility.AccessibilityNodeInfo;
     39 
     40 import com.android.internal.R;
     41 
     42 import org.xmlpull.v1.XmlPullParser;
     43 import org.xmlpull.v1.XmlPullParserException;
     44 
     45 import java.io.IOException;
     46 import java.util.ArrayList;
     47 import java.util.Collections;
     48 import java.util.List;
     49 
     50 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
     51 
     52 /**
     53  * This class describes an {@link AccessibilityService}. The system notifies an
     54  * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s
     55  * according to the information encapsulated in this class.
     56  *
     57  * <div class="special reference">
     58  * <h3>Developer Guides</h3>
     59  * <p>For more information about creating AccessibilityServices, read the
     60  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     61  * developer guide.</p>
     62  * </div>
     63  *
     64  * @attr ref android.R.styleable#AccessibilityService_accessibilityEventTypes
     65  * @attr ref android.R.styleable#AccessibilityService_accessibilityFeedbackType
     66  * @attr ref android.R.styleable#AccessibilityService_accessibilityFlags
     67  * @attr ref android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
     68  * @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
     69  * @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
     70  * @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
     71  * @attr ref android.R.styleable#AccessibilityService_description
     72  * @attr ref android.R.styleable#AccessibilityService_summary
     73  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
     74  * @attr ref android.R.styleable#AccessibilityService_packageNames
     75  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
     76  * @see AccessibilityService
     77  * @see android.view.accessibility.AccessibilityEvent
     78  * @see android.view.accessibility.AccessibilityManager
     79  */
     80 public class AccessibilityServiceInfo implements Parcelable {
     81 
     82     private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";
     83 
     84     /**
     85      * Capability: This accessibility service can retrieve the active window content.
     86      * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
     87      */
     88     public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
     89 
     90     /**
     91      * Capability: This accessibility service can request touch exploration mode in which
     92      * touched items are spoken aloud and the UI can be explored via gestures.
     93      * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
     94      */
     95     public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
     96 
     97     /**
     98      * @deprecated No longer used
     99      */
    100     public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
    101 
    102     /**
    103      * Capability: This accessibility service can request to filter the key event stream.
    104      * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
    105      */
    106     public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
    107 
    108     /**
    109      * Capability: This accessibility service can control display magnification.
    110      * @see android.R.styleable#AccessibilityService_canControlMagnification
    111      */
    112     public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010;
    113 
    114     /**
    115      * Capability: This accessibility service can perform gestures.
    116      * @see android.R.styleable#AccessibilityService_canPerformGestures
    117      */
    118     public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020;
    119 
    120     /**
    121      * Capability: This accessibility service can capture gestures from the fingerprint sensor
    122      * @see android.R.styleable#AccessibilityService_canRequestFingerprintGestures
    123      */
    124     public static final int CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES = 0x00000040;
    125 
    126     private static SparseArray<CapabilityInfo> sAvailableCapabilityInfos;
    127 
    128     /**
    129      * Denotes spoken feedback.
    130      */
    131     public static final int FEEDBACK_SPOKEN = 0x0000001;
    132 
    133     /**
    134      * Denotes haptic feedback.
    135      */
    136     public static final int FEEDBACK_HAPTIC =  0x0000002;
    137 
    138     /**
    139      * Denotes audible (not spoken) feedback.
    140      */
    141     public static final int FEEDBACK_AUDIBLE = 0x0000004;
    142 
    143     /**
    144      * Denotes visual feedback.
    145      */
    146     public static final int FEEDBACK_VISUAL = 0x0000008;
    147 
    148     /**
    149      * Denotes generic feedback.
    150      */
    151     public static final int FEEDBACK_GENERIC = 0x0000010;
    152 
    153     /**
    154      * Denotes braille feedback.
    155      */
    156     public static final int FEEDBACK_BRAILLE = 0x0000020;
    157 
    158     /**
    159      * Mask for all feedback types.
    160      *
    161      * @see #FEEDBACK_SPOKEN
    162      * @see #FEEDBACK_HAPTIC
    163      * @see #FEEDBACK_AUDIBLE
    164      * @see #FEEDBACK_VISUAL
    165      * @see #FEEDBACK_GENERIC
    166      * @see #FEEDBACK_BRAILLE
    167      */
    168     public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
    169 
    170     /**
    171      * If an {@link AccessibilityService} is the default for a given type.
    172      * Default service is invoked only if no package specific one exists. In case of
    173      * more than one package specific service only the earlier registered is notified.
    174      */
    175     public static final int DEFAULT = 0x0000001;
    176 
    177     /**
    178      * If this flag is set the system will regard views that are not important
    179      * for accessibility in addition to the ones that are important for accessibility.
    180      * That is, views that are marked as not important for accessibility via
    181      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or
    182      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are
    183      * marked as potentially important for accessibility via
    184      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
    185      * that are not important for accessibility, are reported while querying the window
    186      * content and also the accessibility service will receive accessibility events from
    187      * them.
    188      * <p>
    189      * <strong>Note:</strong> For accessibility services targeting API version
    190      * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
    191      * set for the system to regard views that are not important for accessibility. For
    192      * accessibility services targeting API version lower than
    193      * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
    194      * regarded for accessibility purposes.
    195      * </p>
    196      * <p>
    197      * Usually views not important for accessibility are layout managers that do not
    198      * react to user actions, do not draw any content, and do not have any special
    199      * semantics in the context of the screen content. For example, a three by three
    200      * grid can be implemented as three horizontal linear layouts and one vertical,
    201      * or three vertical linear layouts and one horizontal, or one grid layout, etc.
    202      * In this context the actual layout mangers used to achieve the grid configuration
    203      * are not important, rather it is important that there are nine evenly distributed
    204      * elements.
    205      * </p>
    206      */
    207     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
    208 
    209     /**
    210      * This flag requests that the system gets into touch exploration mode.
    211      * In this mode a single finger moving on the screen behaves as a mouse
    212      * pointer hovering over the user interface. The system will also detect
    213      * certain gestures performed on the touch screen and notify this service.
    214      * The system will enable touch exploration mode if there is at least one
    215      * accessibility service that has this flag set. Hence, clearing this
    216      * flag does not guarantee that the device will not be in touch exploration
    217      * mode since there may be another enabled service that requested it.
    218      * <p>
    219      * For accessibility services targeting API version higher than
    220      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
    221      * this flag have to declare this capability in their meta-data by setting
    222      * the attribute {@link android.R.attr#canRequestTouchExplorationMode
    223      * canRequestTouchExplorationMode} to true, otherwise this flag will
    224      * be ignored. For how to declare the meta-data of a service refer to
    225      * {@value AccessibilityService#SERVICE_META_DATA}.
    226      * </p>
    227      * <p>
    228      * Services targeting API version equal to or lower than
    229      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
    230      * the first time they are run, if this flag is specified, a dialog is
    231      * shown to the user to confirm enabling explore by touch.
    232      * </p>
    233      * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
    234      */
    235     public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
    236 
    237     /**
    238      * @deprecated No longer used
    239      */
    240     public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
    241 
    242     /**
    243      * This flag requests that the {@link AccessibilityNodeInfo}s obtained
    244      * by an {@link AccessibilityService} contain the id of the source view.
    245      * The source view id will be a fully qualified resource name of the
    246      * form "package:id/name", for example "foo.bar:id/my_list", and it is
    247      * useful for UI test automation. This flag is not set by default.
    248      */
    249     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
    250 
    251     /**
    252      * This flag requests from the system to filter key events. If this flag
    253      * is set the accessibility service will receive the key events before
    254      * applications allowing it implement global shortcuts.
    255      * <p>
    256      * Services that want to set this flag have to declare this capability
    257      * in their meta-data by setting the attribute {@link android.R.attr
    258      * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
    259      * otherwise this flag will be ignored. For how to declare the meta-data
    260      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
    261      * </p>
    262      * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
    263      */
    264     public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
    265 
    266     /**
    267      * This flag indicates to the system that the accessibility service wants
    268      * to access content of all interactive windows. An interactive window is a
    269      * window that has input focus or can be touched by a sighted user when explore
    270      * by touch is not enabled. If this flag is not set your service will not receive
    271      * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
    272      * events, calling AccessibilityService{@link AccessibilityService#getWindows()
    273      * AccessibilityService.getWindows()} will return an empty list, and {@link
    274      * AccessibilityNodeInfo#getWindow() AccessibilityNodeInfo.getWindow()} will
    275      * return null.
    276      * <p>
    277      * Services that want to set this flag have to declare the capability
    278      * to retrieve window content in their meta-data by setting the attribute
    279      * {@link android.R.attr#canRetrieveWindowContent canRetrieveWindowContent} to
    280      * true, otherwise this flag will be ignored. For how to declare the meta-data
    281      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
    282      * </p>
    283      * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
    284      */
    285     public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
    286 
    287     /**
    288      * This flag requests that all audio tracks system-wide with
    289      * {@link android.media.AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY} be controlled by the
    290      * {@link android.media.AudioManager#STREAM_ACCESSIBILITY} volume.
    291      */
    292     public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080;
    293 
    294      /**
    295      * This flag indicates to the system that the accessibility service requests that an
    296      * accessibility button be shown within the system's navigation area, if available.
    297      */
    298     public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100;
    299 
    300     /**
    301      * This flag requests that all fingerprint gestures be sent to the accessibility service.
    302      * It is handled in {@link FingerprintGestureController}
    303      */
    304     public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 0x00000200;
    305 
    306     /** {@hide} */
    307     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
    308 
    309     /**
    310      * The event types an {@link AccessibilityService} is interested in.
    311      * <p>
    312      *   <strong>Can be dynamically set at runtime.</strong>
    313      * </p>
    314      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
    315      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
    316      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
    317      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
    318      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
    319      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
    320      * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
    321      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
    322      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
    323      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
    324      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
    325      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
    326      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
    327      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
    328      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
    329      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
    330      * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT
    331      * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START
    332      * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END
    333      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
    334      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
    335      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
    336      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED
    337      */
    338     public int eventTypes;
    339 
    340     /**
    341      * The package names an {@link AccessibilityService} is interested in. Setting
    342      * to <code>null</code> is equivalent to all packages.
    343      * <p>
    344      *   <strong>Can be dynamically set at runtime.</strong>
    345      * </p>
    346      */
    347     public String[] packageNames;
    348 
    349     /**
    350      * The feedback type an {@link AccessibilityService} provides.
    351      * <p>
    352      *   <strong>Can be dynamically set at runtime.</strong>
    353      * </p>
    354      * @see #FEEDBACK_AUDIBLE
    355      * @see #FEEDBACK_GENERIC
    356      * @see #FEEDBACK_HAPTIC
    357      * @see #FEEDBACK_SPOKEN
    358      * @see #FEEDBACK_VISUAL
    359      * @see #FEEDBACK_BRAILLE
    360      */
    361     public int feedbackType;
    362 
    363     /**
    364      * The timeout after the most recent event of a given type before an
    365      * {@link AccessibilityService} is notified.
    366      * <p>
    367      *   <strong>Can be dynamically set at runtime.</strong>.
    368      * </p>
    369      * <p>
    370      * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
    371      *       events to the client too frequently since this is accomplished via an expensive
    372      *       interprocess call. One can think of the timeout as a criteria to determine when
    373      *       event generation has settled down.
    374      */
    375     public long notificationTimeout;
    376 
    377     /**
    378      * This field represents a set of flags used for configuring an
    379      * {@link AccessibilityService}.
    380      * <p>
    381      *   <strong>Can be dynamically set at runtime.</strong>
    382      * </p>
    383      * @see #DEFAULT
    384      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
    385      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
    386      * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    387      * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
    388      * @see #FLAG_REPORT_VIEW_IDS
    389      * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
    390      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
    391      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
    392      */
    393     public int flags;
    394 
    395     /**
    396      * The component name the accessibility service.
    397      */
    398     private ComponentName mComponentName;
    399 
    400     /**
    401      * The Service that implements this accessibility service component.
    402      */
    403     private ResolveInfo mResolveInfo;
    404 
    405     /**
    406      * The accessibility service setting activity's name, used by the system
    407      * settings to launch the setting activity of this accessibility service.
    408      */
    409     private String mSettingsActivityName;
    410 
    411     /**
    412      * Bit mask with capabilities of this service.
    413      */
    414     private int mCapabilities;
    415 
    416     /**
    417      * Resource id of the summary of the accessibility service.
    418      */
    419     private int mSummaryResId;
    420 
    421     /**
    422      * Non-localized summary of the accessibility service.
    423      */
    424     private String mNonLocalizedSummary;
    425 
    426     /**
    427      * Resource id of the description of the accessibility service.
    428      */
    429     private int mDescriptionResId;
    430 
    431     /**
    432      * Non localized description of the accessibility service.
    433      */
    434     private String mNonLocalizedDescription;
    435 
    436     /**
    437      * Creates a new instance.
    438      */
    439     public AccessibilityServiceInfo() {
    440         /* do nothing */
    441     }
    442 
    443     /**
    444      * Creates a new instance.
    445      *
    446      * @param resolveInfo The service resolve info.
    447      * @param context Context for accessing resources.
    448      * @throws XmlPullParserException If a XML parsing error occurs.
    449      * @throws IOException If a XML parsing error occurs.
    450      *
    451      * @hide
    452      */
    453     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
    454             throws XmlPullParserException, IOException {
    455         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    456         mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
    457         mResolveInfo = resolveInfo;
    458 
    459         XmlResourceParser parser = null;
    460 
    461         try {
    462             PackageManager packageManager = context.getPackageManager();
    463             parser = serviceInfo.loadXmlMetaData(packageManager,
    464                     AccessibilityService.SERVICE_META_DATA);
    465             if (parser == null) {
    466                 return;
    467             }
    468 
    469             int type = 0;
    470             while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
    471                 type = parser.next();
    472             }
    473 
    474             String nodeName = parser.getName();
    475             if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) {
    476                 throw new XmlPullParserException( "Meta-data does not start with"
    477                         + TAG_ACCESSIBILITY_SERVICE + " tag");
    478             }
    479 
    480             AttributeSet allAttributes = Xml.asAttributeSet(parser);
    481             Resources resources = packageManager.getResourcesForApplication(
    482                     serviceInfo.applicationInfo);
    483             TypedArray asAttributes = resources.obtainAttributes(allAttributes,
    484                     com.android.internal.R.styleable.AccessibilityService);
    485             eventTypes = asAttributes.getInt(
    486                     com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes,
    487                     0);
    488             String packageNamez = asAttributes.getString(
    489                     com.android.internal.R.styleable.AccessibilityService_packageNames);
    490             if (packageNamez != null) {
    491                 packageNames = packageNamez.split("(\\s)*,(\\s)*");
    492             }
    493             feedbackType = asAttributes.getInt(
    494                     com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType,
    495                     0);
    496             notificationTimeout = asAttributes.getInt(
    497                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
    498                     0);
    499             flags = asAttributes.getInt(
    500                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
    501             mSettingsActivityName = asAttributes.getString(
    502                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
    503             if (asAttributes.getBoolean(com.android.internal.R.styleable
    504                     .AccessibilityService_canRetrieveWindowContent, false)) {
    505                 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
    506             }
    507             if (asAttributes.getBoolean(com.android.internal.R.styleable
    508                     .AccessibilityService_canRequestTouchExplorationMode, false)) {
    509                 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
    510             }
    511             if (asAttributes.getBoolean(com.android.internal.R.styleable
    512                     .AccessibilityService_canRequestFilterKeyEvents, false)) {
    513                 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
    514             }
    515             if (asAttributes.getBoolean(com.android.internal.R.styleable
    516                     .AccessibilityService_canControlMagnification, false)) {
    517                 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION;
    518             }
    519             if (asAttributes.getBoolean(com.android.internal.R.styleable
    520                     .AccessibilityService_canPerformGestures, false)) {
    521                 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
    522             }
    523             if (asAttributes.getBoolean(com.android.internal.R.styleable
    524                     .AccessibilityService_canRequestFingerprintGestures, false)) {
    525                 mCapabilities |= CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES;
    526             }
    527             TypedValue peekedValue = asAttributes.peekValue(
    528                     com.android.internal.R.styleable.AccessibilityService_description);
    529             if (peekedValue != null) {
    530                 mDescriptionResId = peekedValue.resourceId;
    531                 CharSequence nonLocalizedDescription = peekedValue.coerceToString();
    532                 if (nonLocalizedDescription != null) {
    533                     mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
    534                 }
    535             }
    536             peekedValue = asAttributes.peekValue(
    537                 com.android.internal.R.styleable.AccessibilityService_summary);
    538             if (peekedValue != null) {
    539                 mSummaryResId = peekedValue.resourceId;
    540                 CharSequence nonLocalizedSummary = peekedValue.coerceToString();
    541                 if (nonLocalizedSummary != null) {
    542                     mNonLocalizedSummary = nonLocalizedSummary.toString().trim();
    543                 }
    544             }
    545             asAttributes.recycle();
    546         } catch (NameNotFoundException e) {
    547             throw new XmlPullParserException( "Unable to create context for: "
    548                     + serviceInfo.packageName);
    549         } finally {
    550             if (parser != null) {
    551                 parser.close();
    552             }
    553         }
    554     }
    555 
    556     /**
    557      * Updates the properties that an AccessibilitySerivice can change dynamically.
    558      *
    559      * @param other The info from which to update the properties.
    560      *
    561      * @hide
    562      */
    563     public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) {
    564         eventTypes = other.eventTypes;
    565         packageNames = other.packageNames;
    566         feedbackType = other.feedbackType;
    567         notificationTimeout = other.notificationTimeout;
    568         flags = other.flags;
    569     }
    570 
    571     /**
    572      * @hide
    573      */
    574     public void setComponentName(ComponentName component) {
    575         mComponentName = component;
    576     }
    577 
    578     /**
    579      * @hide
    580      */
    581     public ComponentName getComponentName() {
    582         return mComponentName;
    583     }
    584 
    585     /**
    586      * The accessibility service id.
    587      * <p>
    588      *   <strong>Generated by the system.</strong>
    589      * </p>
    590      * @return The id.
    591      */
    592     public String getId() {
    593         return mComponentName.flattenToShortString();
    594     }
    595 
    596     /**
    597      * The service {@link ResolveInfo}.
    598      * <p>
    599      *   <strong>Generated by the system.</strong>
    600      * </p>
    601      * @return The info.
    602      */
    603     public ResolveInfo getResolveInfo() {
    604         return mResolveInfo;
    605     }
    606 
    607     /**
    608      * The settings activity name.
    609      * <p>
    610      *    <strong>Statically set from
    611      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    612      * </p>
    613      * @return The settings activity name.
    614      */
    615     public String getSettingsActivityName() {
    616         return mSettingsActivityName;
    617     }
    618 
    619     /**
    620      * Whether this service can retrieve the current window's content.
    621      * <p>
    622      *    <strong>Statically set from
    623      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    624      * </p>
    625      * @return True if window content can be retrieved.
    626      *
    627      * @deprecated Use {@link #getCapabilities()}.
    628      */
    629     public boolean getCanRetrieveWindowContent() {
    630         return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
    631     }
    632 
    633     /**
    634      * Returns the bit mask of capabilities this accessibility service has such as
    635      * being able to retrieve the active window content, etc.
    636      *
    637      * @return The capability bit mask.
    638      *
    639      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
    640      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
    641      * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
    642      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
    643      * @see #CAPABILITY_CAN_PERFORM_GESTURES
    644      */
    645     public int getCapabilities() {
    646         return mCapabilities;
    647     }
    648 
    649     /**
    650      * Sets the bit mask of capabilities this accessibility service has such as
    651      * being able to retrieve the active window content, etc.
    652      *
    653      * @param capabilities The capability bit mask.
    654      *
    655      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
    656      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
    657      * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
    658      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
    659      * @see #CAPABILITY_CAN_PERFORM_GESTURES
    660      *
    661      * @hide
    662      */
    663     public void setCapabilities(int capabilities) {
    664         mCapabilities = capabilities;
    665     }
    666 
    667     /**
    668      * The localized summary of the accessibility service.
    669      * <p>
    670      *    <strong>Statically set from
    671      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    672      * </p>
    673      * @return The localized summary if available, and {@code null} if a summary
    674      * has not been provided.
    675      */
    676     public CharSequence loadSummary(PackageManager packageManager) {
    677         if (mSummaryResId == 0) {
    678             return mNonLocalizedSummary;
    679         }
    680         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
    681         CharSequence summary = packageManager.getText(serviceInfo.packageName,
    682                 mSummaryResId, serviceInfo.applicationInfo);
    683         if (summary != null) {
    684             return summary.toString().trim();
    685         }
    686         return null;
    687     }
    688 
    689     /**
    690      * Gets the non-localized description of the accessibility service.
    691      * <p>
    692      *    <strong>Statically set from
    693      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    694      * </p>
    695      * @return The description.
    696      *
    697      * @deprecated Use {@link #loadDescription(PackageManager)}.
    698      */
    699     public String getDescription() {
    700         return mNonLocalizedDescription;
    701     }
    702 
    703     /**
    704      * The localized description of the accessibility service.
    705      * <p>
    706      *    <strong>Statically set from
    707      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    708      * </p>
    709      * @return The localized description.
    710      */
    711     public String loadDescription(PackageManager packageManager) {
    712         if (mDescriptionResId == 0) {
    713             return mNonLocalizedDescription;
    714         }
    715         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
    716         CharSequence description = packageManager.getText(serviceInfo.packageName,
    717                 mDescriptionResId, serviceInfo.applicationInfo);
    718         if (description != null) {
    719             return description.toString().trim();
    720         }
    721         return null;
    722     }
    723 
    724     /** {@hide} */
    725     public boolean isDirectBootAware() {
    726         return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
    727                 || mResolveInfo.serviceInfo.directBootAware;
    728     }
    729 
    730     /**
    731      * {@inheritDoc}
    732      */
    733     public int describeContents() {
    734         return 0;
    735     }
    736 
    737     public void writeToParcel(Parcel parcel, int flagz) {
    738         parcel.writeInt(eventTypes);
    739         parcel.writeStringArray(packageNames);
    740         parcel.writeInt(feedbackType);
    741         parcel.writeLong(notificationTimeout);
    742         parcel.writeInt(flags);
    743         parcel.writeParcelable(mComponentName, flagz);
    744         parcel.writeParcelable(mResolveInfo, 0);
    745         parcel.writeString(mSettingsActivityName);
    746         parcel.writeInt(mCapabilities);
    747         parcel.writeInt(mSummaryResId);
    748         parcel.writeString(mNonLocalizedSummary);
    749         parcel.writeInt(mDescriptionResId);
    750         parcel.writeString(mNonLocalizedDescription);
    751     }
    752 
    753     private void initFromParcel(Parcel parcel) {
    754         eventTypes = parcel.readInt();
    755         packageNames = parcel.readStringArray();
    756         feedbackType = parcel.readInt();
    757         notificationTimeout = parcel.readLong();
    758         flags = parcel.readInt();
    759         mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
    760         mResolveInfo = parcel.readParcelable(null);
    761         mSettingsActivityName = parcel.readString();
    762         mCapabilities = parcel.readInt();
    763         mSummaryResId = parcel.readInt();
    764         mNonLocalizedSummary = parcel.readString();
    765         mDescriptionResId = parcel.readInt();
    766         mNonLocalizedDescription = parcel.readString();
    767     }
    768 
    769     @Override
    770     public int hashCode() {
    771         return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
    772     }
    773 
    774     @Override
    775     public boolean equals(Object obj) {
    776         if (this == obj) {
    777             return true;
    778         }
    779         if (obj == null) {
    780             return false;
    781         }
    782         if (getClass() != obj.getClass()) {
    783             return false;
    784         }
    785         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
    786         if (mComponentName == null) {
    787             if (other.mComponentName != null) {
    788                 return false;
    789             }
    790         } else if (!mComponentName.equals(other.mComponentName)) {
    791             return false;
    792         }
    793         return true;
    794     }
    795 
    796     @Override
    797     public String toString() {
    798         StringBuilder stringBuilder = new StringBuilder();
    799         appendEventTypes(stringBuilder, eventTypes);
    800         stringBuilder.append(", ");
    801         appendPackageNames(stringBuilder, packageNames);
    802         stringBuilder.append(", ");
    803         appendFeedbackTypes(stringBuilder, feedbackType);
    804         stringBuilder.append(", ");
    805         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
    806         stringBuilder.append(", ");
    807         appendFlags(stringBuilder, flags);
    808         stringBuilder.append(", ");
    809         stringBuilder.append("id: ").append(getId());
    810         stringBuilder.append(", ");
    811         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
    812         stringBuilder.append(", ");
    813         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
    814         stringBuilder.append(", ");
    815         stringBuilder.append("summary: ").append(mNonLocalizedSummary);
    816         stringBuilder.append(", ");
    817         appendCapabilities(stringBuilder, mCapabilities);
    818         return stringBuilder.toString();
    819     }
    820 
    821     private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) {
    822         stringBuilder.append("feedbackTypes:");
    823         stringBuilder.append("[");
    824         while (feedbackTypes != 0) {
    825             final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes));
    826             stringBuilder.append(feedbackTypeToString(feedbackTypeBit));
    827             feedbackTypes &= ~feedbackTypeBit;
    828             if (feedbackTypes != 0) {
    829                 stringBuilder.append(", ");
    830             }
    831         }
    832         stringBuilder.append("]");
    833     }
    834 
    835     private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) {
    836         stringBuilder.append("packageNames:");
    837         stringBuilder.append("[");
    838         if (packageNames != null) {
    839             final int packageNameCount = packageNames.length;
    840             for (int i = 0; i < packageNameCount; i++) {
    841                 stringBuilder.append(packageNames[i]);
    842                 if (i < packageNameCount - 1) {
    843                     stringBuilder.append(", ");
    844                 }
    845             }
    846         }
    847         stringBuilder.append("]");
    848     }
    849 
    850     private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) {
    851         stringBuilder.append("eventTypes:");
    852         stringBuilder.append("[");
    853         while (eventTypes != 0) {
    854             final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes));
    855             stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit));
    856             eventTypes &= ~eventTypeBit;
    857             if (eventTypes != 0) {
    858                 stringBuilder.append(", ");
    859             }
    860         }
    861         stringBuilder.append("]");
    862     }
    863 
    864     private static void appendFlags(StringBuilder stringBuilder, int flags) {
    865         stringBuilder.append("flags:");
    866         stringBuilder.append("[");
    867         while (flags != 0) {
    868             final int flagBit = (1 << Integer.numberOfTrailingZeros(flags));
    869             stringBuilder.append(flagToString(flagBit));
    870             flags &= ~flagBit;
    871             if (flags != 0) {
    872                 stringBuilder.append(", ");
    873             }
    874         }
    875         stringBuilder.append("]");
    876     }
    877 
    878     private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
    879         stringBuilder.append("capabilities:");
    880         stringBuilder.append("[");
    881         while (capabilities != 0) {
    882             final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
    883             stringBuilder.append(capabilityToString(capabilityBit));
    884             capabilities &= ~capabilityBit;
    885             if (capabilities != 0) {
    886                 stringBuilder.append(", ");
    887             }
    888         }
    889         stringBuilder.append("]");
    890     }
    891 
    892     /**
    893      * Returns the string representation of a feedback type. For example,
    894      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
    895      *
    896      * @param feedbackType The feedback type.
    897      * @return The string representation.
    898      */
    899     public static String feedbackTypeToString(int feedbackType) {
    900         StringBuilder builder = new StringBuilder();
    901         builder.append("[");
    902         while (feedbackType != 0) {
    903             final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
    904             feedbackType &= ~feedbackTypeFlag;
    905             switch (feedbackTypeFlag) {
    906                 case FEEDBACK_AUDIBLE:
    907                     if (builder.length() > 1) {
    908                         builder.append(", ");
    909                     }
    910                     builder.append("FEEDBACK_AUDIBLE");
    911                     break;
    912                 case FEEDBACK_HAPTIC:
    913                     if (builder.length() > 1) {
    914                         builder.append(", ");
    915                     }
    916                     builder.append("FEEDBACK_HAPTIC");
    917                     break;
    918                 case FEEDBACK_GENERIC:
    919                     if (builder.length() > 1) {
    920                         builder.append(", ");
    921                     }
    922                     builder.append("FEEDBACK_GENERIC");
    923                     break;
    924                 case FEEDBACK_SPOKEN:
    925                     if (builder.length() > 1) {
    926                         builder.append(", ");
    927                     }
    928                     builder.append("FEEDBACK_SPOKEN");
    929                     break;
    930                 case FEEDBACK_VISUAL:
    931                     if (builder.length() > 1) {
    932                         builder.append(", ");
    933                     }
    934                     builder.append("FEEDBACK_VISUAL");
    935                     break;
    936                 case FEEDBACK_BRAILLE:
    937                     if (builder.length() > 1) {
    938                         builder.append(", ");
    939                     }
    940                     builder.append("FEEDBACK_BRAILLE");
    941                     break;
    942             }
    943         }
    944         builder.append("]");
    945         return builder.toString();
    946     }
    947 
    948     /**
    949      * Returns the string representation of a flag. For example,
    950      * {@link #DEFAULT} is represented by the string DEFAULT.
    951      *
    952      * @param flag The flag.
    953      * @return The string representation.
    954      */
    955     public static String flagToString(int flag) {
    956         switch (flag) {
    957             case DEFAULT:
    958                 return "DEFAULT";
    959             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
    960                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
    961             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
    962                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
    963             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
    964                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    965             case FLAG_REPORT_VIEW_IDS:
    966                 return "FLAG_REPORT_VIEW_IDS";
    967             case FLAG_REQUEST_FILTER_KEY_EVENTS:
    968                 return "FLAG_REQUEST_FILTER_KEY_EVENTS";
    969             case FLAG_RETRIEVE_INTERACTIVE_WINDOWS:
    970                 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
    971             case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
    972                 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
    973             case FLAG_REQUEST_ACCESSIBILITY_BUTTON:
    974                 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
    975             case FLAG_REQUEST_FINGERPRINT_GESTURES:
    976                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
    977             default:
    978                 return null;
    979         }
    980     }
    981 
    982     /**
    983      * Returns the string representation of a capability. For example,
    984      * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
    985      * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
    986      *
    987      * @param capability The capability.
    988      * @return The string representation.
    989      */
    990     public static String capabilityToString(int capability) {
    991         switch (capability) {
    992             case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
    993                 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
    994             case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
    995                 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
    996             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
    997                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    998             case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
    999                 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS";
   1000             case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
   1001                 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
   1002             case CAPABILITY_CAN_PERFORM_GESTURES:
   1003                 return "CAPABILITY_CAN_PERFORM_GESTURES";
   1004             case CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES:
   1005                 return "CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES";
   1006             default:
   1007                 return "UNKNOWN";
   1008         }
   1009     }
   1010 
   1011     /**
   1012      * @hide
   1013      * @return The list of {@link CapabilityInfo} objects.
   1014      * @deprecated The version that takes a context works better.
   1015      */
   1016     public List<CapabilityInfo> getCapabilityInfos() {
   1017         return getCapabilityInfos(null);
   1018     }
   1019 
   1020     /**
   1021      * @hide
   1022      * @param context A valid context
   1023      * @return The list of {@link CapabilityInfo} objects.
   1024      */
   1025     public List<CapabilityInfo> getCapabilityInfos(Context context) {
   1026         if (mCapabilities == 0) {
   1027             return Collections.emptyList();
   1028         }
   1029         int capabilities = mCapabilities;
   1030         List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
   1031         SparseArray<CapabilityInfo> capabilityInfoSparseArray =
   1032                 getCapabilityInfoSparseArray(context);
   1033         while (capabilities != 0) {
   1034             final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
   1035             capabilities &= ~capabilityBit;
   1036             CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit);
   1037             if (capabilityInfo != null) {
   1038                 capabilityInfos.add(capabilityInfo);
   1039             }
   1040         }
   1041         return capabilityInfos;
   1042     }
   1043 
   1044     private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) {
   1045         if (sAvailableCapabilityInfos == null) {
   1046             sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>();
   1047             sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
   1048                     new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
   1049                             R.string.capability_title_canRetrieveWindowContent,
   1050                             R.string.capability_desc_canRetrieveWindowContent));
   1051             sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
   1052                     new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
   1053                             R.string.capability_title_canRequestTouchExploration,
   1054                             R.string.capability_desc_canRequestTouchExploration));
   1055             sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
   1056                     new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
   1057                             R.string.capability_title_canRequestFilterKeyEvents,
   1058                             R.string.capability_desc_canRequestFilterKeyEvents));
   1059             sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
   1060                     new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
   1061                             R.string.capability_title_canControlMagnification,
   1062                             R.string.capability_desc_canControlMagnification));
   1063             sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
   1064                     new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
   1065                             R.string.capability_title_canPerformGestures,
   1066                             R.string.capability_desc_canPerformGestures));
   1067             if ((context == null) || fingerprintAvailable(context)) {
   1068                 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES,
   1069                         new CapabilityInfo(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES,
   1070                                 R.string.capability_title_canCaptureFingerprintGestures,
   1071                                 R.string.capability_desc_canCaptureFingerprintGestures));
   1072             }
   1073         }
   1074         return sAvailableCapabilityInfos;
   1075     }
   1076 
   1077     private static boolean fingerprintAvailable(Context context) {
   1078         return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT)
   1079                 && context.getSystemService(FingerprintManager.class).isHardwareDetected();
   1080     }
   1081     /**
   1082      * @hide
   1083      */
   1084     public static final class CapabilityInfo {
   1085         public final int capability;
   1086         public final int titleResId;
   1087         public final int descResId;
   1088 
   1089         public CapabilityInfo(int capability, int titleResId, int descResId) {
   1090             this.capability = capability;
   1091             this.titleResId = titleResId;
   1092             this.descResId = descResId;
   1093         }
   1094     }
   1095 
   1096     /**
   1097      * @see Parcelable.Creator
   1098      */
   1099     public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
   1100             new Parcelable.Creator<AccessibilityServiceInfo>() {
   1101         public AccessibilityServiceInfo createFromParcel(Parcel parcel) {
   1102             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
   1103             info.initFromParcel(parcel);
   1104             return info;
   1105         }
   1106 
   1107         public AccessibilityServiceInfo[] newArray(int size) {
   1108             return new AccessibilityServiceInfo[size];
   1109         }
   1110     };
   1111 }
   1112