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      * The event types an {@link AccessibilityService} is interested in.
    288      * <p>
    289      *   <strong>Can be dynamically set at runtime.</strong>
    290      * </p>
    291      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
    292      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
    293      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
    294      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
    295      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
    296      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
    297      * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
    298      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
    299      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
    300      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
    301      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
    302      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
    303      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
    304      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
    305      */
    306     public int eventTypes;
    307 
    308     /**
    309      * The package names an {@link AccessibilityService} is interested in. Setting
    310      * to <code>null</code> is equivalent to all packages.
    311      * <p>
    312      *   <strong>Can be dynamically set at runtime.</strong>
    313      * </p>
    314      */
    315     public String[] packageNames;
    316 
    317     /**
    318      * The feedback type an {@link AccessibilityService} provides.
    319      * <p>
    320      *   <strong>Can be dynamically set at runtime.</strong>
    321      * </p>
    322      * @see #FEEDBACK_AUDIBLE
    323      * @see #FEEDBACK_GENERIC
    324      * @see #FEEDBACK_HAPTIC
    325      * @see #FEEDBACK_SPOKEN
    326      * @see #FEEDBACK_VISUAL
    327      * @see #FEEDBACK_BRAILLE
    328      */
    329     public int feedbackType;
    330 
    331     /**
    332      * The timeout after the most recent event of a given type before an
    333      * {@link AccessibilityService} is notified.
    334      * <p>
    335      *   <strong>Can be dynamically set at runtime.</strong>.
    336      * </p>
    337      * <p>
    338      * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
    339      *       events to the client too frequently since this is accomplished via an expensive
    340      *       interprocess call. One can think of the timeout as a criteria to determine when
    341      *       event generation has settled down.
    342      */
    343     public long notificationTimeout;
    344 
    345     /**
    346      * This field represents a set of flags used for configuring an
    347      * {@link AccessibilityService}.
    348      * <p>
    349      *   <strong>Can be dynamically set at runtime.</strong>
    350      * </p>
    351      * @see #DEFAULT
    352      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
    353      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
    354      * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    355      * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
    356      * @see #FLAG_REPORT_VIEW_IDS
    357      */
    358     public int flags;
    359 
    360     /**
    361      * The unique string Id to identify the accessibility service.
    362      */
    363     private String mId;
    364 
    365     /**
    366      * The Service that implements this accessibility service component.
    367      */
    368     private ResolveInfo mResolveInfo;
    369 
    370     /**
    371      * The accessibility service setting activity's name, used by the system
    372      * settings to launch the setting activity of this accessibility service.
    373      */
    374     private String mSettingsActivityName;
    375 
    376     /**
    377      * Bit mask with capabilities of this service.
    378      */
    379     private int mCapabilities;
    380 
    381     /**
    382      * Resource id of the description of the accessibility service.
    383      */
    384     private int mDescriptionResId;
    385 
    386     /**
    387      * Non localized description of the accessibility service.
    388      */
    389     private String mNonLocalizedDescription;
    390 
    391     /**
    392      * Creates a new instance.
    393      */
    394     public AccessibilityServiceInfo() {
    395         /* do nothing */
    396     }
    397 
    398     /**
    399      * Creates a new instance.
    400      *
    401      * @param resolveInfo The service resolve info.
    402      * @param context Context for accessing resources.
    403      * @throws XmlPullParserException If a XML parsing error occurs.
    404      * @throws IOException If a XML parsing error occurs.
    405      *
    406      * @hide
    407      */
    408     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
    409             throws XmlPullParserException, IOException {
    410         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    411         mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
    412         mResolveInfo = resolveInfo;
    413 
    414         XmlResourceParser parser = null;
    415 
    416         try {
    417             PackageManager packageManager = context.getPackageManager();
    418             parser = serviceInfo.loadXmlMetaData(packageManager,
    419                     AccessibilityService.SERVICE_META_DATA);
    420             if (parser == null) {
    421                 return;
    422             }
    423 
    424             int type = 0;
    425             while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
    426                 type = parser.next();
    427             }
    428 
    429             String nodeName = parser.getName();
    430             if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) {
    431                 throw new XmlPullParserException( "Meta-data does not start with"
    432                         + TAG_ACCESSIBILITY_SERVICE + " tag");
    433             }
    434 
    435             AttributeSet allAttributes = Xml.asAttributeSet(parser);
    436             Resources resources = packageManager.getResourcesForApplication(
    437                     serviceInfo.applicationInfo);
    438             TypedArray asAttributes = resources.obtainAttributes(allAttributes,
    439                     com.android.internal.R.styleable.AccessibilityService);
    440             eventTypes = asAttributes.getInt(
    441                     com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes,
    442                     0);
    443             String packageNamez = asAttributes.getString(
    444                     com.android.internal.R.styleable.AccessibilityService_packageNames);
    445             if (packageNamez != null) {
    446                 packageNames = packageNamez.split("(\\s)*,(\\s)*");
    447             }
    448             feedbackType = asAttributes.getInt(
    449                     com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType,
    450                     0);
    451             notificationTimeout = asAttributes.getInt(
    452                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
    453                     0);
    454             flags = asAttributes.getInt(
    455                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
    456             mSettingsActivityName = asAttributes.getString(
    457                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
    458             if (asAttributes.getBoolean(com.android.internal.R.styleable
    459                     .AccessibilityService_canRetrieveWindowContent, false)) {
    460                 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
    461             }
    462             if (asAttributes.getBoolean(com.android.internal.R.styleable
    463                     .AccessibilityService_canRequestTouchExplorationMode, false)) {
    464                 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
    465             }
    466             if (asAttributes.getBoolean(com.android.internal.R.styleable
    467                         .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
    468                     mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
    469             }
    470             if (asAttributes.getBoolean(com.android.internal.R.styleable
    471                     .AccessibilityService_canRequestFilterKeyEvents, false)) {
    472                 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
    473             }
    474             TypedValue peekedValue = asAttributes.peekValue(
    475                     com.android.internal.R.styleable.AccessibilityService_description);
    476             if (peekedValue != null) {
    477                 mDescriptionResId = peekedValue.resourceId;
    478                 CharSequence nonLocalizedDescription = peekedValue.coerceToString();
    479                 if (nonLocalizedDescription != null) {
    480                     mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
    481                 }
    482             }
    483             asAttributes.recycle();
    484         } catch (NameNotFoundException e) {
    485             throw new XmlPullParserException( "Unable to create context for: "
    486                     + serviceInfo.packageName);
    487         } finally {
    488             if (parser != null) {
    489                 parser.close();
    490             }
    491         }
    492     }
    493 
    494     /**
    495      * Updates the properties that an AccessibilitySerivice can change dynamically.
    496      *
    497      * @param other The info from which to update the properties.
    498      *
    499      * @hide
    500      */
    501     public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) {
    502         eventTypes = other.eventTypes;
    503         packageNames = other.packageNames;
    504         feedbackType = other.feedbackType;
    505         notificationTimeout = other.notificationTimeout;
    506         flags = other.flags;
    507     }
    508 
    509     /**
    510      * @hide
    511      */
    512     public void setComponentName(ComponentName component) {
    513         mId = component.flattenToShortString();
    514     }
    515 
    516     /**
    517      * The accessibility service id.
    518      * <p>
    519      *   <strong>Generated by the system.</strong>
    520      * </p>
    521      * @return The id.
    522      */
    523     public String getId() {
    524         return mId;
    525     }
    526 
    527     /**
    528      * The service {@link ResolveInfo}.
    529      * <p>
    530      *   <strong>Generated by the system.</strong>
    531      * </p>
    532      * @return The info.
    533      */
    534     public ResolveInfo getResolveInfo() {
    535         return mResolveInfo;
    536     }
    537 
    538     /**
    539      * The settings activity name.
    540      * <p>
    541      *    <strong>Statically set from
    542      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    543      * </p>
    544      * @return The settings activity name.
    545      */
    546     public String getSettingsActivityName() {
    547         return mSettingsActivityName;
    548     }
    549 
    550     /**
    551      * Whether this service can retrieve the current window's content.
    552      * <p>
    553      *    <strong>Statically set from
    554      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    555      * </p>
    556      * @return True if window content can be retrieved.
    557      *
    558      * @deprecated Use {@link #getCapabilities()}.
    559      */
    560     public boolean getCanRetrieveWindowContent() {
    561         return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
    562     }
    563 
    564     /**
    565      * Returns the bit mask of capabilities this accessibility service has such as
    566      * being able to retrieve the active window content, etc.
    567      *
    568      * @return The capability bit mask.
    569      *
    570      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
    571      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
    572      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    573      * @see #CAPABILITY_FILTER_KEY_EVENTS
    574      */
    575     public int getCapabilities() {
    576         return mCapabilities;
    577     }
    578 
    579     /**
    580      * Sets the bit mask of capabilities this accessibility service has such as
    581      * being able to retrieve the active window content, etc.
    582      *
    583      * @param capabilities The capability bit mask.
    584      *
    585      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
    586      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
    587      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
    588      * @see #CAPABILITY_FILTER_KEY_EVENTS
    589      *
    590      * @hide
    591      */
    592     public void setCapabilities(int capabilities) {
    593         mCapabilities = capabilities;
    594     }
    595 
    596     /**
    597      * Gets the non-localized description of the accessibility service.
    598      * <p>
    599      *    <strong>Statically set from
    600      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    601      * </p>
    602      * @return The description.
    603      *
    604      * @deprecated Use {@link #loadDescription(PackageManager)}.
    605      */
    606     public String getDescription() {
    607         return mNonLocalizedDescription;
    608     }
    609 
    610     /**
    611      * The localized description of the accessibility service.
    612      * <p>
    613      *    <strong>Statically set from
    614      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
    615      * </p>
    616      * @return The localized description.
    617      */
    618     public String loadDescription(PackageManager packageManager) {
    619         if (mDescriptionResId == 0) {
    620             return mNonLocalizedDescription;
    621         }
    622         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
    623         CharSequence description = packageManager.getText(serviceInfo.packageName,
    624                 mDescriptionResId, serviceInfo.applicationInfo);
    625         if (description != null) {
    626             return description.toString().trim();
    627         }
    628         return null;
    629     }
    630 
    631     /**
    632      * {@inheritDoc}
    633      */
    634     public int describeContents() {
    635         return 0;
    636     }
    637 
    638     public void writeToParcel(Parcel parcel, int flagz) {
    639         parcel.writeInt(eventTypes);
    640         parcel.writeStringArray(packageNames);
    641         parcel.writeInt(feedbackType);
    642         parcel.writeLong(notificationTimeout);
    643         parcel.writeInt(flags);
    644         parcel.writeString(mId);
    645         parcel.writeParcelable(mResolveInfo, 0);
    646         parcel.writeString(mSettingsActivityName);
    647         parcel.writeInt(mCapabilities);
    648         parcel.writeInt(mDescriptionResId);
    649         parcel.writeString(mNonLocalizedDescription);
    650     }
    651 
    652     private void initFromParcel(Parcel parcel) {
    653         eventTypes = parcel.readInt();
    654         packageNames = parcel.readStringArray();
    655         feedbackType = parcel.readInt();
    656         notificationTimeout = parcel.readLong();
    657         flags = parcel.readInt();
    658         mId = parcel.readString();
    659         mResolveInfo = parcel.readParcelable(null);
    660         mSettingsActivityName = parcel.readString();
    661         mCapabilities = parcel.readInt();
    662         mDescriptionResId = parcel.readInt();
    663         mNonLocalizedDescription = parcel.readString();
    664     }
    665 
    666     @Override
    667     public int hashCode() {
    668         return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
    669     }
    670 
    671     @Override
    672     public boolean equals(Object obj) {
    673         if (this == obj) {
    674             return true;
    675         }
    676         if (obj == null) {
    677             return false;
    678         }
    679         if (getClass() != obj.getClass()) {
    680             return false;
    681         }
    682         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
    683         if (mId == null) {
    684             if (other.mId != null) {
    685                 return false;
    686             }
    687         } else if (!mId.equals(other.mId)) {
    688             return false;
    689         }
    690         return true;
    691     }
    692 
    693     @Override
    694     public String toString() {
    695         StringBuilder stringBuilder = new StringBuilder();
    696         appendEventTypes(stringBuilder, eventTypes);
    697         stringBuilder.append(", ");
    698         appendPackageNames(stringBuilder, packageNames);
    699         stringBuilder.append(", ");
    700         appendFeedbackTypes(stringBuilder, feedbackType);
    701         stringBuilder.append(", ");
    702         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
    703         stringBuilder.append(", ");
    704         appendFlags(stringBuilder, flags);
    705         stringBuilder.append(", ");
    706         stringBuilder.append("id: ").append(mId);
    707         stringBuilder.append(", ");
    708         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
    709         stringBuilder.append(", ");
    710         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
    711         stringBuilder.append(", ");
    712         appendCapabilities(stringBuilder, mCapabilities);
    713         return stringBuilder.toString();
    714     }
    715 
    716     private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) {
    717         stringBuilder.append("feedbackTypes:");
    718         stringBuilder.append("[");
    719         while (feedbackTypes != 0) {
    720             final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes));
    721             stringBuilder.append(feedbackTypeToString(feedbackTypeBit));
    722             feedbackTypes &= ~feedbackTypeBit;
    723             if (feedbackTypes != 0) {
    724                 stringBuilder.append(", ");
    725             }
    726         }
    727         stringBuilder.append("]");
    728     }
    729 
    730     private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) {
    731         stringBuilder.append("packageNames:");
    732         stringBuilder.append("[");
    733         if (packageNames != null) {
    734             final int packageNameCount = packageNames.length;
    735             for (int i = 0; i < packageNameCount; i++) {
    736                 stringBuilder.append(packageNames[i]);
    737                 if (i < packageNameCount - 1) {
    738                     stringBuilder.append(", ");
    739                 }
    740             }
    741         }
    742         stringBuilder.append("]");
    743     }
    744 
    745     private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) {
    746         stringBuilder.append("eventTypes:");
    747         stringBuilder.append("[");
    748         while (eventTypes != 0) {
    749             final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes));
    750             stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit));
    751             eventTypes &= ~eventTypeBit;
    752             if (eventTypes != 0) {
    753                 stringBuilder.append(", ");
    754             }
    755         }
    756         stringBuilder.append("]");
    757     }
    758 
    759     private static void appendFlags(StringBuilder stringBuilder, int flags) {
    760         stringBuilder.append("flags:");
    761         stringBuilder.append("[");
    762         while (flags != 0) {
    763             final int flagBit = (1 << Integer.numberOfTrailingZeros(flags));
    764             stringBuilder.append(flagToString(flagBit));
    765             flags &= ~flagBit;
    766             if (flags != 0) {
    767                 stringBuilder.append(", ");
    768             }
    769         }
    770         stringBuilder.append("]");
    771     }
    772 
    773     private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
    774         stringBuilder.append("capabilities:");
    775         stringBuilder.append("[");
    776         while (capabilities != 0) {
    777             final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
    778             stringBuilder.append(capabilityToString(capabilityBit));
    779             capabilities &= ~capabilityBit;
    780             if (capabilities != 0) {
    781                 stringBuilder.append(", ");
    782             }
    783         }
    784         stringBuilder.append("]");
    785     }
    786 
    787     /**
    788      * Returns the string representation of a feedback type. For example,
    789      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
    790      *
    791      * @param feedbackType The feedback type.
    792      * @return The string representation.
    793      */
    794     public static String feedbackTypeToString(int feedbackType) {
    795         StringBuilder builder = new StringBuilder();
    796         builder.append("[");
    797         while (feedbackType != 0) {
    798             final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
    799             feedbackType &= ~feedbackTypeFlag;
    800             switch (feedbackTypeFlag) {
    801                 case FEEDBACK_AUDIBLE:
    802                     if (builder.length() > 1) {
    803                         builder.append(", ");
    804                     }
    805                     builder.append("FEEDBACK_AUDIBLE");
    806                     break;
    807                 case FEEDBACK_HAPTIC:
    808                     if (builder.length() > 1) {
    809                         builder.append(", ");
    810                     }
    811                     builder.append("FEEDBACK_HAPTIC");
    812                     break;
    813                 case FEEDBACK_GENERIC:
    814                     if (builder.length() > 1) {
    815                         builder.append(", ");
    816                     }
    817                     builder.append("FEEDBACK_GENERIC");
    818                     break;
    819                 case FEEDBACK_SPOKEN:
    820                     if (builder.length() > 1) {
    821                         builder.append(", ");
    822                     }
    823                     builder.append("FEEDBACK_SPOKEN");
    824                     break;
    825                 case FEEDBACK_VISUAL:
    826                     if (builder.length() > 1) {
    827                         builder.append(", ");
    828                     }
    829                     builder.append("FEEDBACK_VISUAL");
    830                     break;
    831                 case FEEDBACK_BRAILLE:
    832                     if (builder.length() > 1) {
    833                         builder.append(", ");
    834                     }
    835                     builder.append("FEEDBACK_BRAILLE");
    836                     break;
    837             }
    838         }
    839         builder.append("]");
    840         return builder.toString();
    841     }
    842 
    843     /**
    844      * Returns the string representation of a flag. For example,
    845      * {@link #DEFAULT} is represented by the string DEFAULT.
    846      *
    847      * @param flag The flag.
    848      * @return The string representation.
    849      */
    850     public static String flagToString(int flag) {
    851         switch (flag) {
    852             case DEFAULT:
    853                 return "DEFAULT";
    854             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
    855                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
    856             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
    857                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
    858             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
    859                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    860             case FLAG_REPORT_VIEW_IDS:
    861                 return "FLAG_REPORT_VIEW_IDS";
    862             case FLAG_REQUEST_FILTER_KEY_EVENTS:
    863                 return "FLAG_REQUEST_FILTER_KEY_EVENTS";
    864             default:
    865                 return null;
    866         }
    867     }
    868 
    869     /**
    870      * Returns the string representation of a capability. For example,
    871      * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
    872      * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
    873      *
    874      * @param capability The capability.
    875      * @return The string representation.
    876      */
    877     public static String capabilityToString(int capability) {
    878         switch (capability) {
    879             case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
    880                 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
    881             case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
    882                 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
    883             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
    884                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
    885             case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
    886                 return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
    887             default:
    888                 return "UNKNOWN";
    889         }
    890     }
    891 
    892     /**
    893      * @hide
    894      * @return The list of {@link CapabilityInfo} objects.
    895      */
    896     public List<CapabilityInfo> getCapabilityInfos() {
    897         if (mCapabilities == 0) {
    898             return Collections.emptyList();
    899         }
    900         int capabilities = mCapabilities;
    901         List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
    902         while (capabilities != 0) {
    903             final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
    904             capabilities &= ~capabilityBit;
    905             CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit);
    906             if (capabilityInfo != null) {
    907                 capabilityInfos.add(capabilityInfo);
    908             }
    909         }
    910         return capabilityInfos;
    911     }
    912 
    913     /**
    914      * @hide
    915      */
    916     public static final class CapabilityInfo {
    917         public final int capability;
    918         public final int titleResId;
    919         public final int descResId;
    920 
    921         public CapabilityInfo(int capability, int titleResId, int descResId) {
    922             this.capability = capability;
    923             this.titleResId = titleResId;
    924             this.descResId = descResId;
    925         }
    926     }
    927 
    928     /**
    929      * @see Parcelable.Creator
    930      */
    931     public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
    932             new Parcelable.Creator<AccessibilityServiceInfo>() {
    933         public AccessibilityServiceInfo createFromParcel(Parcel parcel) {
    934             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
    935             info.initFromParcel(parcel);
    936             return info;
    937         }
    938 
    939         public AccessibilityServiceInfo[] newArray(int size) {
    940             return new AccessibilityServiceInfo[size];
    941         }
    942     };
    943 }
    944