AccessibilityServiceInfo.java revision cb75b5454b54f7d443f1552adb7813ca139d22e3
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     * Capability: This accessibility service can request enhanced web accessibility
99     * enhancements. For example, installing scripts to make app content more accessible.
100     * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
101     */
102    public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
103
104    /**
105     * Capability: This accessibility service can request to filter the key event stream.
106     * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
107     */
108    public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
109
110    /**
111     * Capability: This accessibility service can control display magnification.
112     * @see android.R.styleable#AccessibilityService_canControlMagnification
113     */
114    public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010;
115
116    /**
117     * Capability: This accessibility service can perform gestures.
118     * @see android.R.styleable#AccessibilityService_canPerformGestures
119     */
120    public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020;
121
122    /**
123     * Capability: This accessibility service can capture gestures from the fingerprint sensor
124     * @see android.R.styleable#AccessibilityService_canCaptureFingerprintGestures
125     */
126    public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 0x00000040;
127
128    private static SparseArray<CapabilityInfo> sAvailableCapabilityInfos;
129
130    /**
131     * Denotes spoken feedback.
132     */
133    public static final int FEEDBACK_SPOKEN = 0x0000001;
134
135    /**
136     * Denotes haptic feedback.
137     */
138    public static final int FEEDBACK_HAPTIC =  0x0000002;
139
140    /**
141     * Denotes audible (not spoken) feedback.
142     */
143    public static final int FEEDBACK_AUDIBLE = 0x0000004;
144
145    /**
146     * Denotes visual feedback.
147     */
148    public static final int FEEDBACK_VISUAL = 0x0000008;
149
150    /**
151     * Denotes generic feedback.
152     */
153    public static final int FEEDBACK_GENERIC = 0x0000010;
154
155    /**
156     * Denotes braille feedback.
157     */
158    public static final int FEEDBACK_BRAILLE = 0x0000020;
159
160    /**
161     * Mask for all feedback types.
162     *
163     * @see #FEEDBACK_SPOKEN
164     * @see #FEEDBACK_HAPTIC
165     * @see #FEEDBACK_AUDIBLE
166     * @see #FEEDBACK_VISUAL
167     * @see #FEEDBACK_GENERIC
168     * @see #FEEDBACK_BRAILLE
169     */
170    public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
171
172    /**
173     * If an {@link AccessibilityService} is the default for a given type.
174     * Default service is invoked only if no package specific one exists. In case of
175     * more than one package specific service only the earlier registered is notified.
176     */
177    public static final int DEFAULT = 0x0000001;
178
179    /**
180     * If this flag is set the system will regard views that are not important
181     * for accessibility in addition to the ones that are important for accessibility.
182     * That is, views that are marked as not important for accessibility via
183     * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or
184     * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are
185     * marked as potentially important for accessibility via
186     * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
187     * that are not important for accessibility, are reported while querying the window
188     * content and also the accessibility service will receive accessibility events from
189     * them.
190     * <p>
191     * <strong>Note:</strong> For accessibility services targeting API version
192     * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
193     * set for the system to regard views that are not important for accessibility. For
194     * accessibility services targeting API version lower than
195     * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
196     * regarded for accessibility purposes.
197     * </p>
198     * <p>
199     * Usually views not important for accessibility are layout managers that do not
200     * react to user actions, do not draw any content, and do not have any special
201     * semantics in the context of the screen content. For example, a three by three
202     * grid can be implemented as three horizontal linear layouts and one vertical,
203     * or three vertical linear layouts and one horizontal, or one grid layout, etc.
204     * In this context the actual layout mangers used to achieve the grid configuration
205     * are not important, rather it is important that there are nine evenly distributed
206     * elements.
207     * </p>
208     */
209    public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
210
211    /**
212     * This flag requests that the system gets into touch exploration mode.
213     * In this mode a single finger moving on the screen behaves as a mouse
214     * pointer hovering over the user interface. The system will also detect
215     * certain gestures performed on the touch screen and notify this service.
216     * The system will enable touch exploration mode if there is at least one
217     * accessibility service that has this flag set. Hence, clearing this
218     * flag does not guarantee that the device will not be in touch exploration
219     * mode since there may be another enabled service that requested it.
220     * <p>
221     * For accessibility services targeting API version higher than
222     * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
223     * this flag have to declare this capability in their meta-data by setting
224     * the attribute {@link android.R.attr#canRequestTouchExplorationMode
225     * canRequestTouchExplorationMode} to true, otherwise this flag will
226     * be ignored. For how to declare the meta-data of a service refer to
227     * {@value AccessibilityService#SERVICE_META_DATA}.
228     * </p>
229     * <p>
230     * Services targeting API version equal to or lower than
231     * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
232     * the first time they are run, if this flag is specified, a dialog is
233     * shown to the user to confirm enabling explore by touch.
234     * </p>
235     * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
236     */
237    public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
238
239    /**
240     * This flag requests from the system to enable web accessibility enhancing
241     * extensions. Such extensions aim to provide improved accessibility support
242     * for content presented in a {@link android.webkit.WebView}. An example of such
243     * an extension is injecting JavaScript from a secure source. The system will enable
244     * enhanced web accessibility if there is at least one accessibility service
245     * that has this flag set. Hence, clearing this flag does not guarantee that the
246     * device will not have enhanced web accessibility enabled since there may be
247     * another enabled service that requested it.
248     * <p>
249     * Services that want to set this flag have to declare this capability
250     * in their meta-data by setting the attribute {@link android.R.attr
251     * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
252     * true, otherwise this flag will be ignored. For how to declare the meta-data
253     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
254     * </p>
255     * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
256     */
257    public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
258
259    /**
260     * This flag requests that the {@link AccessibilityNodeInfo}s obtained
261     * by an {@link AccessibilityService} contain the id of the source view.
262     * The source view id will be a fully qualified resource name of the
263     * form "package:id/name", for example "foo.bar:id/my_list", and it is
264     * useful for UI test automation. This flag is not set by default.
265     */
266    public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
267
268    /**
269     * This flag requests from the system to filter key events. If this flag
270     * is set the accessibility service will receive the key events before
271     * applications allowing it implement global shortcuts.
272     * <p>
273     * Services that want to set this flag have to declare this capability
274     * in their meta-data by setting the attribute {@link android.R.attr
275     * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
276     * otherwise this flag will be ignored. For how to declare the meta-data
277     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
278     * </p>
279     * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
280     */
281    public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
282
283    /**
284     * This flag indicates to the system that the accessibility service wants
285     * to access content of all interactive windows. An interactive window is a
286     * window that has input focus or can be touched by a sighted user when explore
287     * by touch is not enabled. If this flag is not set your service will not receive
288     * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
289     * events, calling AccessibilityService{@link AccessibilityService#getWindows()
290     * AccessibilityService.getWindows()} will return an empty list, and {@link
291     * AccessibilityNodeInfo#getWindow() AccessibilityNodeInfo.getWindow()} will
292     * return null.
293     * <p>
294     * Services that want to set this flag have to declare the capability
295     * to retrieve window content in their meta-data by setting the attribute
296     * {@link android.R.attr#canRetrieveWindowContent canRetrieveWindowContent} to
297     * true, otherwise this flag will be ignored. For how to declare the meta-data
298     * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
299     * </p>
300     * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
301     */
302    public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
303
304    /**
305     * This flag requests that all audio tracks system-wide with
306     * {@link android.media.AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY} be controlled by the
307     * {@link android.media.AudioManager#STREAM_ACCESSIBILITY} volume.
308     */
309    public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080;
310
311     /**
312     * This flag indicates to the system that the accessibility service requests that an
313     * accessibility button be shown within the system's navigation area, if available.
314     */
315    public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100;
316
317    /**
318     * This flag requests that all fingerprint gestures be sent to the accessibility service.
319     * It is handled in {@link FingerprintGestureController}
320     */
321    public static final int FLAG_CAPTURE_FINGERPRINT_GESTURES = 0x00000200;
322
323    /** {@hide} */
324    public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
325
326    /**
327     * The event types an {@link AccessibilityService} is interested in.
328     * <p>
329     *   <strong>Can be dynamically set at runtime.</strong>
330     * </p>
331     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
332     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
333     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
334     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
335     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
336     * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
337     * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
338     * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
339     * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
340     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
341     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
342     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
343     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
344     * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
345     * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
346     * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
347     * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT
348     * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START
349     * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END
350     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
351     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
352     * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
353     * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED
354     */
355    public int eventTypes;
356
357    /**
358     * The package names an {@link AccessibilityService} is interested in. Setting
359     * to <code>null</code> is equivalent to all packages.
360     * <p>
361     *   <strong>Can be dynamically set at runtime.</strong>
362     * </p>
363     */
364    public String[] packageNames;
365
366    /**
367     * The feedback type an {@link AccessibilityService} provides.
368     * <p>
369     *   <strong>Can be dynamically set at runtime.</strong>
370     * </p>
371     * @see #FEEDBACK_AUDIBLE
372     * @see #FEEDBACK_GENERIC
373     * @see #FEEDBACK_HAPTIC
374     * @see #FEEDBACK_SPOKEN
375     * @see #FEEDBACK_VISUAL
376     * @see #FEEDBACK_BRAILLE
377     */
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_canRequestEnhancedWebAccessibility, false)) {
530                    mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
531            }
532            if (asAttributes.getBoolean(com.android.internal.R.styleable
533                    .AccessibilityService_canRequestFilterKeyEvents, false)) {
534                mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
535            }
536            if (asAttributes.getBoolean(com.android.internal.R.styleable
537                    .AccessibilityService_canControlMagnification, false)) {
538                mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION;
539            }
540            if (asAttributes.getBoolean(com.android.internal.R.styleable
541                    .AccessibilityService_canPerformGestures, false)) {
542                mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
543            }
544            if (asAttributes.getBoolean(com.android.internal.R.styleable
545                    .AccessibilityService_canCaptureFingerprintGestures, false)) {
546                mCapabilities |= CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES;
547            }
548            TypedValue peekedValue = asAttributes.peekValue(
549                    com.android.internal.R.styleable.AccessibilityService_description);
550            if (peekedValue != null) {
551                mDescriptionResId = peekedValue.resourceId;
552                CharSequence nonLocalizedDescription = peekedValue.coerceToString();
553                if (nonLocalizedDescription != null) {
554                    mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
555                }
556            }
557            peekedValue = asAttributes.peekValue(
558                com.android.internal.R.styleable.AccessibilityService_summary);
559            if (peekedValue != null) {
560                mSummaryResId = peekedValue.resourceId;
561                CharSequence nonLocalizedSummary = peekedValue.coerceToString();
562                if (nonLocalizedSummary != null) {
563                    mNonLocalizedSummary = nonLocalizedSummary.toString().trim();
564                }
565            }
566            asAttributes.recycle();
567        } catch (NameNotFoundException e) {
568            throw new XmlPullParserException( "Unable to create context for: "
569                    + serviceInfo.packageName);
570        } finally {
571            if (parser != null) {
572                parser.close();
573            }
574        }
575    }
576
577    /**
578     * Updates the properties that an AccessibilitySerivice can change dynamically.
579     *
580     * @param other The info from which to update the properties.
581     *
582     * @hide
583     */
584    public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) {
585        eventTypes = other.eventTypes;
586        packageNames = other.packageNames;
587        feedbackType = other.feedbackType;
588        notificationTimeout = other.notificationTimeout;
589        flags = other.flags;
590    }
591
592    /**
593     * @hide
594     */
595    public void setComponentName(ComponentName component) {
596        mComponentName = component;
597    }
598
599    /**
600     * @hide
601     */
602    public ComponentName getComponentName() {
603        return mComponentName;
604    }
605
606    /**
607     * The accessibility service id.
608     * <p>
609     *   <strong>Generated by the system.</strong>
610     * </p>
611     * @return The id.
612     */
613    public String getId() {
614        return mComponentName.flattenToShortString();
615    }
616
617    /**
618     * The service {@link ResolveInfo}.
619     * <p>
620     *   <strong>Generated by the system.</strong>
621     * </p>
622     * @return The info.
623     */
624    public ResolveInfo getResolveInfo() {
625        return mResolveInfo;
626    }
627
628    /**
629     * The settings activity name.
630     * <p>
631     *    <strong>Statically set from
632     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
633     * </p>
634     * @return The settings activity name.
635     */
636    public String getSettingsActivityName() {
637        return mSettingsActivityName;
638    }
639
640    /**
641     * Whether this service can retrieve the current window's content.
642     * <p>
643     *    <strong>Statically set from
644     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
645     * </p>
646     * @return True if window content can be retrieved.
647     *
648     * @deprecated Use {@link #getCapabilities()}.
649     */
650    public boolean getCanRetrieveWindowContent() {
651        return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
652    }
653
654    /**
655     * Returns the bit mask of capabilities this accessibility service has such as
656     * being able to retrieve the active window content, etc.
657     *
658     * @return The capability bit mask.
659     *
660     * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
661     * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
662     * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
663     * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
664     * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
665     * @see #CAPABILITY_CAN_PERFORM_GESTURES
666     */
667    public int getCapabilities() {
668        return mCapabilities;
669    }
670
671    /**
672     * Sets the bit mask of capabilities this accessibility service has such as
673     * being able to retrieve the active window content, etc.
674     *
675     * @param capabilities The capability bit mask.
676     *
677     * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
678     * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
679     * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
680     * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
681     * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
682     * @see #CAPABILITY_CAN_PERFORM_GESTURES
683     *
684     * @hide
685     */
686    public void setCapabilities(int capabilities) {
687        mCapabilities = capabilities;
688    }
689
690    /**
691     * The localized summary of the accessibility service.
692     * <p>
693     *    <strong>Statically set from
694     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
695     * </p>
696     * @return The localized summary if available, and {@code null} if a summary
697     * has not been provided.
698     */
699    public CharSequence loadSummary(PackageManager packageManager) {
700        if (mSummaryResId == 0) {
701            return mNonLocalizedSummary;
702        }
703        ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
704        CharSequence summary = packageManager.getText(serviceInfo.packageName,
705                mSummaryResId, serviceInfo.applicationInfo);
706        if (summary != null) {
707            return summary.toString().trim();
708        }
709        return null;
710    }
711
712    /**
713     * Gets the non-localized description of the accessibility service.
714     * <p>
715     *    <strong>Statically set from
716     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
717     * </p>
718     * @return The description.
719     *
720     * @deprecated Use {@link #loadDescription(PackageManager)}.
721     */
722    public String getDescription() {
723        return mNonLocalizedDescription;
724    }
725
726    /**
727     * The localized description of the accessibility service.
728     * <p>
729     *    <strong>Statically set from
730     *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
731     * </p>
732     * @return The localized description.
733     */
734    public String loadDescription(PackageManager packageManager) {
735        if (mDescriptionResId == 0) {
736            return mNonLocalizedDescription;
737        }
738        ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
739        CharSequence description = packageManager.getText(serviceInfo.packageName,
740                mDescriptionResId, serviceInfo.applicationInfo);
741        if (description != null) {
742            return description.toString().trim();
743        }
744        return null;
745    }
746
747    /** {@hide} */
748    public boolean isDirectBootAware() {
749        return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
750                || mResolveInfo.serviceInfo.directBootAware;
751    }
752
753    /**
754     * {@inheritDoc}
755     */
756    public int describeContents() {
757        return 0;
758    }
759
760    public void writeToParcel(Parcel parcel, int flagz) {
761        parcel.writeInt(eventTypes);
762        parcel.writeStringArray(packageNames);
763        parcel.writeInt(feedbackType);
764        parcel.writeLong(notificationTimeout);
765        parcel.writeInt(flags);
766        parcel.writeParcelable(mComponentName, flagz);
767        parcel.writeParcelable(mResolveInfo, 0);
768        parcel.writeString(mSettingsActivityName);
769        parcel.writeInt(mCapabilities);
770        parcel.writeInt(mSummaryResId);
771        parcel.writeString(mNonLocalizedSummary);
772        parcel.writeInt(mDescriptionResId);
773        parcel.writeString(mNonLocalizedDescription);
774    }
775
776    private void initFromParcel(Parcel parcel) {
777        eventTypes = parcel.readInt();
778        packageNames = parcel.readStringArray();
779        feedbackType = parcel.readInt();
780        notificationTimeout = parcel.readLong();
781        flags = parcel.readInt();
782        mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
783        mResolveInfo = parcel.readParcelable(null);
784        mSettingsActivityName = parcel.readString();
785        mCapabilities = parcel.readInt();
786        mSummaryResId = parcel.readInt();
787        mNonLocalizedSummary = parcel.readString();
788        mDescriptionResId = parcel.readInt();
789        mNonLocalizedDescription = parcel.readString();
790    }
791
792    @Override
793    public int hashCode() {
794        return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
795    }
796
797    @Override
798    public boolean equals(Object obj) {
799        if (this == obj) {
800            return true;
801        }
802        if (obj == null) {
803            return false;
804        }
805        if (getClass() != obj.getClass()) {
806            return false;
807        }
808        AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
809        if (mComponentName == null) {
810            if (other.mComponentName != null) {
811                return false;
812            }
813        } else if (!mComponentName.equals(other.mComponentName)) {
814            return false;
815        }
816        return true;
817    }
818
819    @Override
820    public String toString() {
821        StringBuilder stringBuilder = new StringBuilder();
822        appendEventTypes(stringBuilder, eventTypes);
823        stringBuilder.append(", ");
824        appendPackageNames(stringBuilder, packageNames);
825        stringBuilder.append(", ");
826        appendFeedbackTypes(stringBuilder, feedbackType);
827        stringBuilder.append(", ");
828        stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
829        stringBuilder.append(", ");
830        appendFlags(stringBuilder, flags);
831        stringBuilder.append(", ");
832        stringBuilder.append("id: ").append(getId());
833        stringBuilder.append(", ");
834        stringBuilder.append("resolveInfo: ").append(mResolveInfo);
835        stringBuilder.append(", ");
836        stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
837        stringBuilder.append(", ");
838        stringBuilder.append("summary: ").append(mNonLocalizedSummary);
839        stringBuilder.append(", ");
840        appendCapabilities(stringBuilder, mCapabilities);
841        return stringBuilder.toString();
842    }
843
844    private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) {
845        stringBuilder.append("feedbackTypes:");
846        stringBuilder.append("[");
847        while (feedbackTypes != 0) {
848            final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes));
849            stringBuilder.append(feedbackTypeToString(feedbackTypeBit));
850            feedbackTypes &= ~feedbackTypeBit;
851            if (feedbackTypes != 0) {
852                stringBuilder.append(", ");
853            }
854        }
855        stringBuilder.append("]");
856    }
857
858    private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) {
859        stringBuilder.append("packageNames:");
860        stringBuilder.append("[");
861        if (packageNames != null) {
862            final int packageNameCount = packageNames.length;
863            for (int i = 0; i < packageNameCount; i++) {
864                stringBuilder.append(packageNames[i]);
865                if (i < packageNameCount - 1) {
866                    stringBuilder.append(", ");
867                }
868            }
869        }
870        stringBuilder.append("]");
871    }
872
873    private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) {
874        stringBuilder.append("eventTypes:");
875        stringBuilder.append("[");
876        while (eventTypes != 0) {
877            final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes));
878            stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit));
879            eventTypes &= ~eventTypeBit;
880            if (eventTypes != 0) {
881                stringBuilder.append(", ");
882            }
883        }
884        stringBuilder.append("]");
885    }
886
887    private static void appendFlags(StringBuilder stringBuilder, int flags) {
888        stringBuilder.append("flags:");
889        stringBuilder.append("[");
890        while (flags != 0) {
891            final int flagBit = (1 << Integer.numberOfTrailingZeros(flags));
892            stringBuilder.append(flagToString(flagBit));
893            flags &= ~flagBit;
894            if (flags != 0) {
895                stringBuilder.append(", ");
896            }
897        }
898        stringBuilder.append("]");
899    }
900
901    private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
902        stringBuilder.append("capabilities:");
903        stringBuilder.append("[");
904        while (capabilities != 0) {
905            final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
906            stringBuilder.append(capabilityToString(capabilityBit));
907            capabilities &= ~capabilityBit;
908            if (capabilities != 0) {
909                stringBuilder.append(", ");
910            }
911        }
912        stringBuilder.append("]");
913    }
914
915    /**
916     * Returns the string representation of a feedback type. For example,
917     * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
918     *
919     * @param feedbackType The feedback type.
920     * @return The string representation.
921     */
922    public static String feedbackTypeToString(int feedbackType) {
923        StringBuilder builder = new StringBuilder();
924        builder.append("[");
925        while (feedbackType != 0) {
926            final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
927            feedbackType &= ~feedbackTypeFlag;
928            switch (feedbackTypeFlag) {
929                case FEEDBACK_AUDIBLE:
930                    if (builder.length() > 1) {
931                        builder.append(", ");
932                    }
933                    builder.append("FEEDBACK_AUDIBLE");
934                    break;
935                case FEEDBACK_HAPTIC:
936                    if (builder.length() > 1) {
937                        builder.append(", ");
938                    }
939                    builder.append("FEEDBACK_HAPTIC");
940                    break;
941                case FEEDBACK_GENERIC:
942                    if (builder.length() > 1) {
943                        builder.append(", ");
944                    }
945                    builder.append("FEEDBACK_GENERIC");
946                    break;
947                case FEEDBACK_SPOKEN:
948                    if (builder.length() > 1) {
949                        builder.append(", ");
950                    }
951                    builder.append("FEEDBACK_SPOKEN");
952                    break;
953                case FEEDBACK_VISUAL:
954                    if (builder.length() > 1) {
955                        builder.append(", ");
956                    }
957                    builder.append("FEEDBACK_VISUAL");
958                    break;
959                case FEEDBACK_BRAILLE:
960                    if (builder.length() > 1) {
961                        builder.append(", ");
962                    }
963                    builder.append("FEEDBACK_BRAILLE");
964                    break;
965            }
966        }
967        builder.append("]");
968        return builder.toString();
969    }
970
971    /**
972     * Returns the string representation of a flag. For example,
973     * {@link #DEFAULT} is represented by the string DEFAULT.
974     *
975     * @param flag The flag.
976     * @return The string representation.
977     */
978    public static String flagToString(int flag) {
979        switch (flag) {
980            case DEFAULT:
981                return "DEFAULT";
982            case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
983                return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
984            case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
985                return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
986            case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
987                return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
988            case FLAG_REPORT_VIEW_IDS:
989                return "FLAG_REPORT_VIEW_IDS";
990            case FLAG_REQUEST_FILTER_KEY_EVENTS:
991                return "FLAG_REQUEST_FILTER_KEY_EVENTS";
992            case FLAG_RETRIEVE_INTERACTIVE_WINDOWS:
993                return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
994            case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
995                return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
996            case FLAG_REQUEST_ACCESSIBILITY_BUTTON:
997                return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
998            case FLAG_CAPTURE_FINGERPRINT_GESTURES:
999                return "FLAG_CAPTURE_FINGERPRINT_GESTURES";
1000            default:
1001                return null;
1002        }
1003    }
1004
1005    /**
1006     * Returns the string representation of a capability. For example,
1007     * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
1008     * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
1009     *
1010     * @param capability The capability.
1011     * @return The string representation.
1012     */
1013    public static String capabilityToString(int capability) {
1014        switch (capability) {
1015            case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
1016                return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
1017            case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
1018                return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
1019            case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
1020                return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
1021            case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
1022                return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS";
1023            case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
1024                return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
1025            case CAPABILITY_CAN_PERFORM_GESTURES:
1026                return "CAPABILITY_CAN_PERFORM_GESTURES";
1027            case CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES:
1028                return "CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES";
1029            default:
1030                return "UNKNOWN";
1031        }
1032    }
1033
1034    /**
1035     * @hide
1036     * @return The list of {@link CapabilityInfo} objects.
1037     * @deprecated The version that takes a context works better.
1038     */
1039    public List<CapabilityInfo> getCapabilityInfos() {
1040        return getCapabilityInfos(null);
1041    }
1042
1043    /**
1044     * @hide
1045     * @param context A valid context
1046     * @return The list of {@link CapabilityInfo} objects.
1047     */
1048    public List<CapabilityInfo> getCapabilityInfos(Context context) {
1049        if (mCapabilities == 0) {
1050            return Collections.emptyList();
1051        }
1052        int capabilities = mCapabilities;
1053        List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
1054        SparseArray<CapabilityInfo> capabilityInfoSparseArray =
1055                getCapabilityInfoSparseArray(context);
1056        while (capabilities != 0) {
1057            final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
1058            capabilities &= ~capabilityBit;
1059            CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit);
1060            if (capabilityInfo != null) {
1061                capabilityInfos.add(capabilityInfo);
1062            }
1063        }
1064        return capabilityInfos;
1065    }
1066
1067    private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) {
1068        if (sAvailableCapabilityInfos == null) {
1069            sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>();
1070            sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
1071                    new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
1072                            R.string.capability_title_canRetrieveWindowContent,
1073                            R.string.capability_desc_canRetrieveWindowContent));
1074            sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
1075                    new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
1076                            R.string.capability_title_canRequestTouchExploration,
1077                            R.string.capability_desc_canRequestTouchExploration));
1078            sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
1079                    new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
1080                            R.string.capability_title_canRequestEnhancedWebAccessibility,
1081                            R.string.capability_desc_canRequestEnhancedWebAccessibility));
1082            sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
1083                    new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
1084                            R.string.capability_title_canRequestFilterKeyEvents,
1085                            R.string.capability_desc_canRequestFilterKeyEvents));
1086            sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
1087                    new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
1088                            R.string.capability_title_canControlMagnification,
1089                            R.string.capability_desc_canControlMagnification));
1090            sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
1091                    new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
1092                            R.string.capability_title_canPerformGestures,
1093                            R.string.capability_desc_canPerformGestures));
1094            if ((context == null) || fingerprintAvailable(context)) {
1095                sAvailableCapabilityInfos.put(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES,
1096                        new CapabilityInfo(CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES,
1097                                R.string.capability_title_canCaptureFingerprintGestures,
1098                                R.string.capability_desc_canCaptureFingerprintGestures));
1099            }
1100        }
1101        return sAvailableCapabilityInfos;
1102    }
1103
1104    private static boolean fingerprintAvailable(Context context) {
1105        return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT)
1106                && context.getSystemService(FingerprintManager.class).isHardwareDetected();
1107    }
1108    /**
1109     * @hide
1110     */
1111    public static final class CapabilityInfo {
1112        public final int capability;
1113        public final int titleResId;
1114        public final int descResId;
1115
1116        public CapabilityInfo(int capability, int titleResId, int descResId) {
1117            this.capability = capability;
1118            this.titleResId = titleResId;
1119            this.descResId = descResId;
1120        }
1121    }
1122
1123    /**
1124     * @see Parcelable.Creator
1125     */
1126    public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
1127            new Parcelable.Creator<AccessibilityServiceInfo>() {
1128        public AccessibilityServiceInfo createFromParcel(Parcel parcel) {
1129            AccessibilityServiceInfo info = new AccessibilityServiceInfo();
1130            info.initFromParcel(parcel);
1131            return info;
1132        }
1133
1134        public AccessibilityServiceInfo[] newArray(int size) {
1135            return new AccessibilityServiceInfo[size];
1136        }
1137    };
1138}
1139