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