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