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