Home | History | Annotate | Download | only in accessibilityservice
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.accessibilityservice;
     18 
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.pm.PackageManager;
     22 import android.content.pm.PackageManager.NameNotFoundException;
     23 import android.content.pm.ResolveInfo;
     24 import android.content.pm.ServiceInfo;
     25 import android.content.res.Resources;
     26 import android.content.res.TypedArray;
     27 import android.content.res.XmlResourceParser;
     28 import android.os.Build;
     29 import android.os.Parcel;
     30 import android.os.Parcelable;
     31 import android.util.AttributeSet;
     32 import android.util.SparseArray;
     33 import android.util.TypedValue;
     34 import android.util.Xml;
     35 import android.view.View;
     36 import android.view.accessibility.AccessibilityEvent;
     37 import android.view.accessibility.AccessibilityNodeInfo;
     38 
     39 import org.xmlpull.v1.XmlPullParser;
     40 import org.xmlpull.v1.XmlPullParserException;
     41 
     42 import com.android.internal.R;
     43 
     44 import java.io.IOException;
     45 import java.util.ArrayList;
     46 import java.util.Collections;
     47 import java.util.List;
     48 
     49 /**
     50  * This class describes an {@link AccessibilityService}. The system notifies an
     51  * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s
     52  * according to the information encapsulated in this class.
     53  *
     54  * <div class="special reference">
     55  * <h3>Developer Guides</h3>
     56  * <p>For more information about creating AccessibilityServices, read the
     57  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
     58  * developer guide.</p>
     59  * </div>
     60  *
     61  * @attr ref android.R.styleable#AccessibilityService_accessibilityEventTypes
     62  * @attr ref android.R.styleable#AccessibilityService_accessibilityFeedbackType
     63  * @attr ref android.R.styleable#AccessibilityService_accessibilityFlags
     64  * @attr ref android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
     65  * @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
     66  * @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
     67  * @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
     68  * @attr ref android.R.styleable#AccessibilityService_description
     69  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
     70  * @attr ref android.R.styleable#AccessibilityService_packageNames
     71  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
     72  *
     73  * @see AccessibilityService
     74  * @see android.view.accessibility.AccessibilityEvent
     75  * @see android.view.accessibility.AccessibilityManager
     76  */
     77 public class AccessibilityServiceInfo implements Parcelable {
     78 
     79     private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";
     80 
     81     /**
     82      * Capability: This accessibility service can retrieve the active window content.
     83      * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
     84      */
     85     public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
     86 
     87     /**
     88      * Capability: This accessibility service can request touch exploration mode in which
     89      * touched items are spoken aloud and the UI can be explored via gestures.
     90      * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
     91      */
     92     public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
     93 
     94     /**
     95      * Capability: This accessibility service can request enhanced web accessibility
     96      * enhancements. For example, installing scripts to make app content more accessible.
     97      * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
     98      */
     99     public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
    100 
    101     /**
    102      * Capability: This accessibility service can request to filter the key event stream.
    103      * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
    104      */
    105     public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
    106 
    107     private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos =
    108             new SparseArray<CapabilityInfo>();
    109     static {
    110         sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
    111                 new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
    112                         R.string.capability_title_canRetrieveWindowContent,
    113                         R.string.capability_desc_canRetrieveWindowContent));
    114         sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
    115                 new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
    116                         R.string.capability_title_canRequestTouchExploration,
    117                         R.string.capability_desc_canRequestTouchExploration));
    118         sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
    119                 new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
    120                         R.string.capability_title_canRequestEnhancedWebAccessibility,
    121                         R.string.capability_desc_canRequestEnhancedWebAccessibility));
    122         sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
    123                 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
    124                         R.string.capability_title_canRequestFilterKeyEvents,
    125                         R.string.capability_desc_canRequestFilterKeyEvents));
    126     }
    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} and views that are marked as
    182      * potentially important for accessibility via
    183      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
    184      * that are not important for accessibility, are both reported while querying the
    185      * window content and also the accessibility service will receive accessibility events
    186      * from them.
    187      * <p>
    188      * <strong>Note:</strong> For accessibility services targeting API version
    189      * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
    190      * set for the system to regard views that are not important for accessibility. For
    191      * accessibility services targeting API version lower than
    192      * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
    193      * regarded for accessibility purposes.
    194      * </p>
    195      * <p>
    196      * Usually views not important for accessibility are layout managers that do not
    197      * react to user actions, do not draw any content, and do not have any special
    198      * semantics in the context of the screen content. For example, a three by three
    199      * grid can be implemented as three horizontal linear layouts and one vertical,
    200      * or three vertical linear layouts and one horizontal, or one grid layout, etc.
    201      * In this context the actual layout mangers used to achieve the grid configuration
    202      * are not important, rather it is important that there are nine evenly distributed
    203      * elements.
    204      * </p>
    205      */
    206     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
    207 
    208     /**
    209      * This flag requests that the system gets into touch exploration mode.
    210      * In this mode a single finger moving on the screen behaves as a mouse
    211      * pointer hovering over the user interface. The system will also detect
    212      * certain gestures performed on the touch screen and notify this service.
    213      * The system will enable touch exploration mode if there is at least one
    214      * accessibility service that has this flag set. Hence, clearing this
    215      * flag does not guarantee that the device will not be in touch exploration
    216      * mode since there may be another enabled service that requested it.
    217      * <p>
    218      * For accessibility services targeting API version higher than
    219      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
    220      * this flag have to declare this capability in their meta-data by setting
    221      * the attribute {@link android.R.attr#canRequestTouchExplorationMode
    222      * canRequestTouchExplorationMode} to true, otherwise this flag will
    223      * be ignored. For how to declare the meta-data of a service refer to
    224      * {@value AccessibilityService#SERVICE_META_DATA}.
    225      * </p>
    226      * <p>
    227      * Services targeting API version equal to or lower than
    228      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
    229      * the first time they are run, if this flag is specified, a dialog is
    230      * shown to the user to confirm enabling explore by touch.
    231      * </p>
    232      * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
    233      */
    234     public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
    235 
    236     /**
    237      * This flag requests from the system to enable web accessibility enhancing
    238      * extensions. Such extensions aim to provide improved accessibility support
    239      * for content presented in a {@link android.webkit.WebView}. An example of such
    240      * an extension is injecting JavaScript from a secure source. The system will enable
    241      * enhanced web accessibility if there is at least one accessibility service
    242      * that has this flag set. Hence, clearing this flag does not guarantee that the
    243      * device will not have enhanced web accessibility enabled since there may be
    244      * another enabled service that requested it.
    245      * <p>
    246      * Services that want to set this flag have to declare this capability
    247      * in their meta-data by setting the attribute {@link android.R.attr
    248      * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
    249      * true, otherwise this flag will be ignored. For how to declare the meta-data
    250      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
    251      * </p>
    252      * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
    253      */
    254     public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
    255 
    256     /**
    257      * This flag requests that the {@link AccessibilityNodeInfo}s obtained
    258      * by an {@link AccessibilityService} contain the id of the source view.
    259      * The source view id will be a fully qualified resource name of the
    260      * form "package:id/name", for example "foo.bar:id/my_list", and it is
    261      * useful for UI test automation. This flag is not set by default.
    262      */
    263     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
    264 
    265     /**
    266      * This flag requests from the system to filter key events. If this flag
    267      * is set the accessibility service will receive the key events before
    268      * applications allowing it implement global shortcuts. Setting this flag
    269      * does not guarantee that this service will filter key events since only
    270      * one service can do so at any given time. This avoids user confusion due
    271      * to behavior change in case different key filtering services are enabled.
    272      * If there is already another key filtering service enabled, this one will
    273      * not receive key events.
    274      * <p>
    275      * Services that want to set this flag have to declare this capability
    276      * in their meta-data by setting the attribute {@link android.R.attr
    277      * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
    278      * otherwise this flag will be ignored. For how to declare the meta-data
    279      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
    280      * </p>
    281      * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
    282      */
    283     public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
    284 
    285     /**
    286      * The event types an {@link AccessibilityService} is interested in.
    287      * <p>
    288      *   <strong>Can be dynamically set at runtime.</strong>
    289      * </p>
    290      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
    291      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
    292      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
    293      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
    294      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
    295      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
    296      * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
    297      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
    298      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
    299      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
    300      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
    301      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
    302      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
    303      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
    304      */
    305     public int eventTypes;
    306 
    307     /**
    308      * The package names an {@link AccessibilityService} is interested in. Setting
    309      * to <code>null</code> is equivalent to all packages.
    310      * <p>
    311      *   <strong>Can be dynamically set at runtime.</strong>
    312      * </p>
    313      */
    314     public String[] packageNames;
    315 
    316     /**
    317      * The feedback type an {@link AccessibilityService} provides.
    318      * <p>
    319      *   <strong>Can be dynamically set at runtime.</strong>
    320      * </p>
    321      * @see #FEEDBACK_AUDIBLE
    322      * @see #FEEDBACK_GENERIC
    323      * @see #FEEDBACK_HAPTIC
    324      * @see #FEEDBACK_SPOKEN
    325      * @see #FEEDBACK_VISUAL
    326      * @see #FEEDBACK_BRAILLE
    327      */
    328     public int feedbackType;
    329 
    330     /**
    331      * The timeout after the most recent event of a given type before an
    332      * {@link AccessibilityService} is notified.
    333      * <p>
    334      *   <strong>Can be dynamically set at runtime.</strong>.
    335      * </p>
    336      * <p>
    337      * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
    338      *       events to the client too frequently since this is accomplished via an expensive
    339      *       interprocess call. One can think of the timeout as a criteria to determine when
    340      *       event generation has settled down.
    341      */
    342     public long notificationTimeout;
    343 
    344     /**
    345      * This field represents a set of flags used for configuring an
    346      * {@link AccessibilityService}.
    347      * <p>
    348      *   <strong>Can be dynamically set at runtime.</strong>
    349      * </p>
    350      * @see #DEFAULT
    351      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
    352      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
    353      * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    354      * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
    355      * @see #FLAG_REPORT_VIEW_IDS
    356      */
    357     public int flags;
    358 
    359     /**
    360      * The unique string Id to identify the accessibility service.
    361      */
    362     private String mId;
    363 
    364     /**
    365      * The Service that implements this accessibility service component.
    366      */
    367     private ResolveInfo mResolveInfo;
    368 
    369     /**
    370      * The accessibility service setting activity's name, used by the system
    371      * settings to launch the setting activity of this accessibility service.
    372      */
    373     private String mSettingsActivityName;
    374 
    375     /**
    376      * Bit mask with capabilities of this service.
    377      */
    378     private int mCapabilities;
    379 
    380     /**
    381      * Resource id of the description of the accessibility service.
    382      */
    383     private int mDescriptionResId;
    384 
    385     /**
    386      * Non localized description of the accessibility service.
    387      */
    388     private String mNonLocalizedDescription;
    389 
    390     /**
    391      * Creates a new instance.
    392      */
    393     public AccessibilityServiceInfo() {
    394         /* do nothing */
    395     }
    396 
    397     /**
    398      * Creates a new instance.
    399      *
    400      * @param resolveInfo The service resolve info.
    401      * @param context Context for accessing resources.
    402      * @throws XmlPullParserException If a XML parsing error occurs.
    403      * @throws IOException If a XML parsing error occurs.
    404      *
    405      * @hide
    406      */
    407     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
    408             throws XmlPullParserException, IOException {
    409         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    410         mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
    411         mResolveInfo = resolveInfo;
    412 
    413         XmlResourceParser parser = null;
    414 
    415         try {
    416             PackageManager packageManager = context.getPackageManager();
    417             parser = serviceInfo.loadXmlMetaData(packageManager,
    418                     AccessibilityService.SERVICE_META_DATA);
    419             if (parser == null) {
    420                 return;
    421             }
    422 
    423             int type = 0;
    424             while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
    425                 type = parser.next();
    426             }
    427 
    428             String nodeName = parser.getName();
    429             if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) {
    430                 throw new XmlPullParserException( "Meta-data does not start with"
    431                         + TAG_ACCESSIBILITY_SERVICE + " tag");
    432             }
    433 
    434             AttributeSet allAttributes = Xml.asAttributeSet(parser);
    435             Resources resources = packageManager.getResourcesForApplication(
    436                     serviceInfo.applicationInfo);
    437             TypedArray asAttributes = resources.obtainAttributes(allAttributes,
    438                     com.android.internal.R.styleable.AccessibilityService);
    439             eventTypes = asAttributes.getInt(
    440                     com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes,
    441                     0);
    442             String packageNamez = asAttributes.getString(
    443                     com.android.internal.R.styleable.AccessibilityService_packageNames);
    444             if (packageNamez != null) {
    445                 packageNames = packageNamez.split("(\\s)*,(\\s)*");
    446             }
    447             feedbackType = asAttributes.getInt(
    448                     com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType,
    449                     0);
    450             notificationTimeout = asAttributes.getInt(
    451                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
    452                     0);
    453             flags = asAttributes.getInt(
    454                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
    455             mSettingsActivityName = asAttributes.getString(
    456                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
    457             if (asAttributes.getBoolean(com.android.internal.R.styleable
    458                     .AccessibilityService_canRetrieveWindowContent, false)) {
    459                 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
    460             }
    461             if (asAttributes.getBoolean(com.android.internal.R.styleable
    462                     .AccessibilityService_canRequestTouchExplorationMode, false)) {
    463                 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
    464             }
    465             if (asAttributes.getBoolean(com.android.internal.R.styleable
    466                         .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
    467                     mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
    468             }
    469             if (asAttributes.getBoolean(com.android.internal.R.styleable
    470                     .AccessibilityService_canRequestFilterKeyEvents, false)) {
    471                 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
    472             }
    473             TypedValue peekedValue = asAttributes.peekValue(
    474                     com.android.internal.R.styleable.AccessibilityService_description);
    475             if (peekedValue != null) {
    476                 mDescriptionResId = peekedValue.resourceId;
    477                 CharSequence nonLocalizedDescription = peekedValue.coerceToString();
    478                 if (nonLocalizedDescription != null) {
    479                     mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
    480                 }
    481             }
    482             asAttributes.recycle();
    483         } catch (NameNotFoundException e) {
    484             throw new XmlPullParserException( "Unable to create context for: "
    485                     + serviceInfo.packageName);
    486         } finally {
    487             if (parser != null) {
    488                 parser.close();
    489             }
    490         }
    491     }
    492 
    493     /**
    494      * Updates the properties that an AccessibilitySerivice can change dynamically.
    495      *
    496      * @param other The info from which to update the properties.
    497      *
    498      * @hide
    499      */
    500     public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) {
    501         eventTypes = other.eventTypes;
    502         packageNames = other.packageNames;
    503         feedbackType = other.feedbackType;
    504         notificationTimeout = other.notificationTimeout;
    505         flags = other.flags;
    506     }
    507 
    508     /**
    509      * @hide
    510      */
    511     public void setComponentName(ComponentName component) {
    512         mId = component.flattenToShortString();
    513     }
    514 
    515     /**
    516      * The accessibility service id.
    517      * <p>
    518      *   <strong>Generated by the system.</strong>
    519      * </p>
    520      * @return The id.
    521      */
    522     public String getId() {
    523         return mId;
    524     }
    525 
    526     /**
    527      * The service {@link ResolveInfo}.
    528      * <p>
    529      *   <strong>Generated by the system.</strong>
    530      * </p>
    531      * @return The info.
    532      */
    533     public ResolveInfo getResolveInfo() {
    534         return mResolveInfo;
    535     }
    536 
    537     /**
    538      * The settings activity name.
    539      * <p>
    540      *    <strong>Statically set from
    541      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    542      * </p>
    543      * @return The settings activity name.
    544      */
    545     public String getSettingsActivityName() {
    546         return mSettingsActivityName;
    547     }
    548 
    549     /**
    550      * Whether this service can retrieve the current window's content.
    551      * <p>
    552      *    <strong>Statically set from
    553      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    554      * </p>
    555      * @return True if window content can be retrieved.
    556      *
    557      * @deprecated Use {@link #getCapabilities()}.
    558      */
    559     public boolean getCanRetrieveWindowContent() {
    560         return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
    561     }
    562 
    563     /**
    564      * Returns the bit mask of capabilities this accessibility service has such as
    565      * being able to retrieve the active window content, etc.
    566      *
    567      * @return The capability bit mask.
    568      *
    569      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
    570      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
    571      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    572      * @see #CAPABILITY_FILTER_KEY_EVENTS
    573      */
    574     public int getCapabilities() {
    575         return mCapabilities;
    576     }
    577 
    578     /**
    579      * Sets the bit mask of capabilities this accessibility service has such as
    580      * being able to retrieve the active window content, etc.
    581      *
    582      * @param capabilities The capability bit mask.
    583      *
    584      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
    585      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
    586      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    587      * @see #CAPABILITY_FILTER_KEY_EVENTS
    588      *
    589      * @hide
    590      */
    591     public void setCapabilities(int capabilities) {
    592         mCapabilities = capabilities;
    593     }
    594 
    595     /**
    596      * Gets the non-localized description of the accessibility service.
    597      * <p>
    598      *    <strong>Statically set from
    599      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    600      * </p>
    601      * @return The description.
    602      *
    603      * @deprecated Use {@link #loadDescription(PackageManager)}.
    604      */
    605     public String getDescription() {
    606         return mNonLocalizedDescription;
    607     }
    608 
    609     /**
    610      * The localized description of the accessibility service.
    611      * <p>
    612      *    <strong>Statically set from
    613      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    614      * </p>
    615      * @return The localized description.
    616      */
    617     public String loadDescription(PackageManager packageManager) {
    618         if (mDescriptionResId == 0) {
    619             return mNonLocalizedDescription;
    620         }
    621         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
    622         CharSequence description = packageManager.getText(serviceInfo.packageName,
    623                 mDescriptionResId, serviceInfo.applicationInfo);
    624         if (description != null) {
    625             return description.toString().trim();
    626         }
    627         return null;
    628     }
    629 
    630     /**
    631      * {@inheritDoc}
    632      */
    633     public int describeContents() {
    634         return 0;
    635     }
    636 
    637     public void writeToParcel(Parcel parcel, int flagz) {
    638         parcel.writeInt(eventTypes);
    639         parcel.writeStringArray(packageNames);
    640         parcel.writeInt(feedbackType);
    641         parcel.writeLong(notificationTimeout);
    642         parcel.writeInt(flags);
    643         parcel.writeString(mId);
    644         parcel.writeParcelable(mResolveInfo, 0);
    645         parcel.writeString(mSettingsActivityName);
    646         parcel.writeInt(mCapabilities);
    647         parcel.writeInt(mDescriptionResId);
    648         parcel.writeString(mNonLocalizedDescription);
    649     }
    650 
    651     private void initFromParcel(Parcel parcel) {
    652         eventTypes = parcel.readInt();
    653         packageNames = parcel.readStringArray();
    654         feedbackType = parcel.readInt();
    655         notificationTimeout = parcel.readLong();
    656         flags = parcel.readInt();
    657         mId = parcel.readString();
    658         mResolveInfo = parcel.readParcelable(null);
    659         mSettingsActivityName = parcel.readString();
    660         mCapabilities = parcel.readInt();
    661         mDescriptionResId = parcel.readInt();
    662         mNonLocalizedDescription = parcel.readString();
    663     }
    664 
    665     @Override
    666     public int hashCode() {
    667         return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
    668     }
    669 
    670     @Override
    671     public boolean equals(Object obj) {
    672         if (this == obj) {
    673             return true;
    674         }
    675         if (obj == null) {
    676             return false;
    677         }
    678         if (getClass() != obj.getClass()) {
    679             return false;
    680         }
    681         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
    682         if (mId == null) {
    683             if (other.mId != null) {
    684                 return false;
    685             }
    686         } else if (!mId.equals(other.mId)) {
    687             return false;
    688         }
    689         return true;
    690     }
    691 
    692     @Override
    693     public String toString() {
    694         StringBuilder stringBuilder = new StringBuilder();
    695         appendEventTypes(stringBuilder, eventTypes);
    696         stringBuilder.append(", ");
    697         appendPackageNames(stringBuilder, packageNames);
    698         stringBuilder.append(", ");
    699         appendFeedbackTypes(stringBuilder, feedbackType);
    700         stringBuilder.append(", ");
    701         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
    702         stringBuilder.append(", ");
    703         appendFlags(stringBuilder, flags);
    704         stringBuilder.append(", ");
    705         stringBuilder.append("id: ").append(mId);
    706         stringBuilder.append(", ");
    707         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
    708         stringBuilder.append(", ");
    709         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
    710         stringBuilder.append(", ");
    711         appendCapabilities(stringBuilder, mCapabilities);
    712         return stringBuilder.toString();
    713     }
    714 
    715     private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) {
    716         stringBuilder.append("feedbackTypes:");
    717         stringBuilder.append("[");
    718         while (feedbackTypes != 0) {
    719             final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes));
    720             stringBuilder.append(feedbackTypeToString(feedbackTypeBit));
    721             feedbackTypes &= ~feedbackTypeBit;
    722             if (feedbackTypes != 0) {
    723                 stringBuilder.append(", ");
    724             }
    725         }
    726         stringBuilder.append("]");
    727     }
    728 
    729     private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) {
    730         stringBuilder.append("packageNames:");
    731         stringBuilder.append("[");
    732         if (packageNames != null) {
    733             final int packageNameCount = packageNames.length;
    734             for (int i = 0; i < packageNameCount; i++) {
    735                 stringBuilder.append(packageNames[i]);
    736                 if (i < packageNameCount - 1) {
    737                     stringBuilder.append(", ");
    738                 }
    739             }
    740         }
    741         stringBuilder.append("]");
    742     }
    743 
    744     private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) {
    745         stringBuilder.append("eventTypes:");
    746         stringBuilder.append("[");
    747         while (eventTypes != 0) {
    748             final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes));
    749             stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit));
    750             eventTypes &= ~eventTypeBit;
    751             if (eventTypes != 0) {
    752                 stringBuilder.append(", ");
    753             }
    754         }
    755         stringBuilder.append("]");
    756     }
    757 
    758     private static void appendFlags(StringBuilder stringBuilder, int flags) {
    759         stringBuilder.append("flags:");
    760         stringBuilder.append("[");
    761         while (flags != 0) {
    762             final int flagBit = (1 << Integer.numberOfTrailingZeros(flags));
    763             stringBuilder.append(flagToString(flagBit));
    764             flags &= ~flagBit;
    765             if (flags != 0) {
    766                 stringBuilder.append(", ");
    767             }
    768         }
    769         stringBuilder.append("]");
    770     }
    771 
    772     private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
    773         stringBuilder.append("capabilities:");
    774         stringBuilder.append("[");
    775         while (capabilities != 0) {
    776             final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
    777             stringBuilder.append(capabilityToString(capabilityBit));
    778             capabilities &= ~capabilityBit;
    779             if (capabilities != 0) {
    780                 stringBuilder.append(", ");
    781             }
    782         }
    783         stringBuilder.append("]");
    784     }
    785 
    786     /**
    787      * Returns the string representation of a feedback type. For example,
    788      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
    789      *
    790      * @param feedbackType The feedback type.
    791      * @return The string representation.
    792      */
    793     public static String feedbackTypeToString(int feedbackType) {
    794         StringBuilder builder = new StringBuilder();
    795         builder.append("[");
    796         while (feedbackType != 0) {
    797             final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
    798             feedbackType &= ~feedbackTypeFlag;
    799             switch (feedbackTypeFlag) {
    800                 case FEEDBACK_AUDIBLE:
    801                     if (builder.length() > 1) {
    802                         builder.append(", ");
    803                     }
    804                     builder.append("FEEDBACK_AUDIBLE");
    805                     break;
    806                 case FEEDBACK_HAPTIC:
    807                     if (builder.length() > 1) {
    808                         builder.append(", ");
    809                     }
    810                     builder.append("FEEDBACK_HAPTIC");
    811                     break;
    812                 case FEEDBACK_GENERIC:
    813                     if (builder.length() > 1) {
    814                         builder.append(", ");
    815                     }
    816                     builder.append("FEEDBACK_GENERIC");
    817                     break;
    818                 case FEEDBACK_SPOKEN:
    819                     if (builder.length() > 1) {
    820                         builder.append(", ");
    821                     }
    822                     builder.append("FEEDBACK_SPOKEN");
    823                     break;
    824                 case FEEDBACK_VISUAL:
    825                     if (builder.length() > 1) {
    826                         builder.append(", ");
    827                     }
    828                     builder.append("FEEDBACK_VISUAL");
    829                     break;
    830                 case FEEDBACK_BRAILLE:
    831                     if (builder.length() > 1) {
    832                         builder.append(", ");
    833                     }
    834                     builder.append("FEEDBACK_BRAILLE");
    835                     break;
    836             }
    837         }
    838         builder.append("]");
    839         return builder.toString();
    840     }
    841 
    842     /**
    843      * Returns the string representation of a flag. For example,
    844      * {@link #DEFAULT} is represented by the string DEFAULT.
    845      *
    846      * @param flag The flag.
    847      * @return The string representation.
    848      */
    849     public static String flagToString(int flag) {
    850         switch (flag) {
    851             case DEFAULT:
    852                 return "DEFAULT";
    853             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
    854                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
    855             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
    856                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
    857             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
    858                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    859             case FLAG_REPORT_VIEW_IDS:
    860                 return "FLAG_REPORT_VIEW_IDS";
    861             case FLAG_REQUEST_FILTER_KEY_EVENTS:
    862                 return "FLAG_REQUEST_FILTER_KEY_EVENTS";
    863             default:
    864                 return null;
    865         }
    866     }
    867 
    868     /**
    869      * Returns the string representation of a capability. For example,
    870      * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
    871      * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
    872      *
    873      * @param capability The capability.
    874      * @return The string representation.
    875      */
    876     public static String capabilityToString(int capability) {
    877         switch (capability) {
    878             case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
    879                 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
    880             case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
    881                 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
    882             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
    883                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    884             case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
    885                 return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
    886             default:
    887                 return "UNKNOWN";
    888         }
    889     }
    890 
    891     /**
    892      * @hide
    893      * @return The list of {@link CapabilityInfo} objects.
    894      */
    895     public List<CapabilityInfo> getCapabilityInfos() {
    896         if (mCapabilities == 0) {
    897             return Collections.emptyList();
    898         }
    899         int capabilities = mCapabilities;
    900         List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
    901         while (capabilities != 0) {
    902             final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
    903             capabilities &= ~capabilityBit;
    904             CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
    905             if (capabilityInfo != null) {
    906                 capabilityInfos.add(capabilityInfo);
    907             }
    908         }
    909         return capabilityInfos;
    910     }
    911 
    912     /**
    913      * @hide
    914      */
    915     public static final class CapabilityInfo {
    916         public final int capability;
    917         public final int titleResId;
    918         public final int descResId;
    919 
    920         public CapabilityInfo(int capability, int titleResId, int descResId) {
    921             this.capability = capability;
    922             this.titleResId = titleResId;
    923             this.descResId = descResId;
    924         }
    925     }
    926 
    927     /**
    928      * @see Parcelable.Creator
    929      */
    930     public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
    931             new Parcelable.Creator<AccessibilityServiceInfo>() {
    932         public AccessibilityServiceInfo createFromParcel(Parcel parcel) {
    933             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
    934             info.initFromParcel(parcel);
    935             return info;
    936         }
    937 
    938         public AccessibilityServiceInfo[] newArray(int size) {
    939             return new AccessibilityServiceInfo[size];
    940         }
    941     };
    942 }
    943