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