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