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