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