• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     /**
368      * This flag requests that when when {@link #FLAG_REQUEST_MULTI_FINGER_GESTURES} is enabled,
369      * two-finger passthrough gestures are re-enabled. Two-finger swipe gestures are not detected,
370      * but instead passed through as one-finger gestures. In addition, three-finger swipes from the
371      * bottom of the screen are not detected, and instead are passed through unchanged. If {@link
372      * #FLAG_REQUEST_MULTI_FINGER_GESTURES} is disabled this flag has no effect.
373      *
374      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
375      * @hide
376      */
377     public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000;
378 
379     /** {@hide} */
380     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
381 
382     /**
383      * The event types an {@link AccessibilityService} is interested in.
384      * <p>
385      *   <strong>Can be dynamically set at runtime.</strong>
386      * </p>
387      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
388      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
389      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
390      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
391      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
392      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
393      * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
394      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
395      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
396      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
397      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
398      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
399      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
400      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
401      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
402      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
403      * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT
404      * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START
405      * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END
406      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
407      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
408      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
409      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED
410      */
411     public int eventTypes;
412 
413     /**
414      * The package names an {@link AccessibilityService} is interested in. Setting
415      * to <code>null</code> is equivalent to all packages.
416      * <p>
417      *   <strong>Can be dynamically set at runtime.</strong>
418      * </p>
419      */
420     public String[] packageNames;
421 
422 
423     /** @hide */
424     @IntDef(flag = true, prefix = { "FEEDBACK_" }, value = {
425             FEEDBACK_AUDIBLE,
426             FEEDBACK_GENERIC,
427             FEEDBACK_HAPTIC,
428             FEEDBACK_SPOKEN,
429             FEEDBACK_VISUAL,
430             FEEDBACK_BRAILLE
431     })
432     @Retention(RetentionPolicy.SOURCE)
433     public @interface FeedbackType {}
434 
435     /**
436      * The feedback type an {@link AccessibilityService} provides.
437      * <p>
438      *   <strong>Can be dynamically set at runtime.</strong>
439      * </p>
440      * @see #FEEDBACK_AUDIBLE
441      * @see #FEEDBACK_GENERIC
442      * @see #FEEDBACK_HAPTIC
443      * @see #FEEDBACK_SPOKEN
444      * @see #FEEDBACK_VISUAL
445      * @see #FEEDBACK_BRAILLE
446      */
447     @FeedbackType
448     public int feedbackType;
449 
450     /**
451      * The timeout, in milliseconds, after the most recent event of a given type before an
452      * {@link AccessibilityService} is notified.
453      * <p>
454      *   <strong>Can be dynamically set at runtime.</strong>
455      * </p>
456      * <p>
457      * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
458      *       events to the client too frequently since this is accomplished via an expensive
459      *       interprocess call. One can think of the timeout as a criteria to determine when
460      *       event generation has settled down.
461      */
462     public long notificationTimeout;
463 
464     /**
465      * This field represents a set of flags used for configuring an
466      * {@link AccessibilityService}.
467      * <p>
468      *   <strong>Can be dynamically set at runtime.</strong>
469      * </p>
470      * <p>
471      *   <strong>Note:</strong> Accessibility services with targetSdkVersion greater than
472      *   {@link Build.VERSION_CODES#Q API 29} cannot dynamically set the
473      *   {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} at runtime. It must be specified in the
474      *   accessibility service metadata file.
475      * </p>
476      * @see #DEFAULT
477      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
478      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
479      * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
480      * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
481      * @see #FLAG_REPORT_VIEW_IDS
482      * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
483      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
484      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
485      * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK
486      */
487     public int flags;
488 
489     /**
490      * Whether or not the service has crashed and is awaiting restart. Only valid from {@link
491      * android.view.accessibility.AccessibilityManager#getInstalledAccessibilityServiceList()},
492      * because that is populated from the internal list of running services.
493      *
494      * @hide
495      */
496     public boolean crashed;
497 
498     /**
499      * A recommended timeout in milliseconds for non-interactive controls.
500      */
501     private int mNonInteractiveUiTimeout;
502 
503     /**
504      * A recommended timeout in milliseconds for interactive controls.
505      */
506     private int mInteractiveUiTimeout;
507 
508     /**
509      * The component name the accessibility service.
510      */
511     private ComponentName mComponentName;
512 
513     /**
514      * The Service that implements this accessibility service component.
515      */
516     private ResolveInfo mResolveInfo;
517 
518     /**
519      * The accessibility service setting activity's name, used by the system
520      * settings to launch the setting activity of this accessibility service.
521      */
522     private String mSettingsActivityName;
523 
524     /**
525      * Bit mask with capabilities of this service.
526      */
527     private int mCapabilities;
528 
529     /**
530      * Resource id of the summary of the accessibility service.
531      */
532     private int mSummaryResId;
533 
534     /**
535      * Non-localized summary of the accessibility service.
536      */
537     private String mNonLocalizedSummary;
538 
539     /**
540      * Resource id of the description of the accessibility service.
541      */
542     private int mDescriptionResId;
543 
544     /**
545      * Non localized description of the accessibility service.
546      */
547     private String mNonLocalizedDescription;
548 
549     /**
550      * For accessibility services targeting APIs greater than {@link Build.VERSION_CODES#Q API 29},
551      * {@link #FLAG_REQUEST_ACCESSIBILITY_BUTTON} must be specified in the accessibility service
552      * metadata file. Otherwise, it will be ignored.
553      */
554     @ChangeId
555     @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q)
556     private static final long REQUEST_ACCESSIBILITY_BUTTON_CHANGE = 136293963L;
557 
558     /**
559      * Resource id of the animated image of the accessibility service.
560      */
561     private int mAnimatedImageRes;
562 
563     /**
564      * Resource id of the html description of the accessibility service.
565      */
566     private int mHtmlDescriptionRes;
567 
568     /**
569      * Creates a new instance.
570      */
AccessibilityServiceInfo()571     public AccessibilityServiceInfo() {
572         /* do nothing */
573     }
574 
575     /**
576      * Creates a new instance.
577      *
578      * @param resolveInfo The service resolve info.
579      * @param context Context for accessing resources.
580      * @throws XmlPullParserException If a XML parsing error occurs.
581      * @throws IOException If a XML parsing error occurs.
582      *
583      * @hide
584      */
AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)585     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
586             throws XmlPullParserException, IOException {
587         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
588         mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
589         mResolveInfo = resolveInfo;
590 
591         XmlResourceParser parser = null;
592 
593         try {
594             PackageManager packageManager = context.getPackageManager();
595             parser = serviceInfo.loadXmlMetaData(packageManager,
596                     AccessibilityService.SERVICE_META_DATA);
597             if (parser == null) {
598                 return;
599             }
600 
601             int type = 0;
602             while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
603                 type = parser.next();
604             }
605 
606             String nodeName = parser.getName();
607             if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) {
608                 throw new XmlPullParserException( "Meta-data does not start with"
609                         + TAG_ACCESSIBILITY_SERVICE + " tag");
610             }
611 
612             AttributeSet allAttributes = Xml.asAttributeSet(parser);
613             Resources resources = packageManager.getResourcesForApplication(
614                     serviceInfo.applicationInfo);
615             TypedArray asAttributes = resources.obtainAttributes(allAttributes,
616                     com.android.internal.R.styleable.AccessibilityService);
617             eventTypes = asAttributes.getInt(
618                     com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes,
619                     0);
620             String packageNamez = asAttributes.getString(
621                     com.android.internal.R.styleable.AccessibilityService_packageNames);
622             if (packageNamez != null) {
623                 packageNames = packageNamez.split("(\\s)*,(\\s)*");
624             }
625             feedbackType = asAttributes.getInt(
626                     com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType,
627                     0);
628             notificationTimeout = asAttributes.getInt(
629                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
630                     0);
631             mNonInteractiveUiTimeout = asAttributes.getInt(
632                     com.android.internal.R.styleable.AccessibilityService_nonInteractiveUiTimeout,
633                     0);
634             mInteractiveUiTimeout = asAttributes.getInt(
635                     com.android.internal.R.styleable.AccessibilityService_interactiveUiTimeout,
636                     0);
637             flags = asAttributes.getInt(
638                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
639             mSettingsActivityName = asAttributes.getString(
640                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
641             if (asAttributes.getBoolean(com.android.internal.R.styleable
642                     .AccessibilityService_canRetrieveWindowContent, false)) {
643                 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
644             }
645             if (asAttributes.getBoolean(com.android.internal.R.styleable
646                     .AccessibilityService_canRequestTouchExplorationMode, false)) {
647                 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
648             }
649             if (asAttributes.getBoolean(com.android.internal.R.styleable
650                     .AccessibilityService_canRequestFilterKeyEvents, false)) {
651                 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
652             }
653             if (asAttributes.getBoolean(com.android.internal.R.styleable
654                     .AccessibilityService_canControlMagnification, false)) {
655                 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION;
656             }
657             if (asAttributes.getBoolean(com.android.internal.R.styleable
658                     .AccessibilityService_canPerformGestures, false)) {
659                 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
660             }
661             if (asAttributes.getBoolean(com.android.internal.R.styleable
662                     .AccessibilityService_canRequestFingerprintGestures, false)) {
663                 mCapabilities |= CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES;
664             }
665             if (asAttributes.getBoolean(com.android.internal.R.styleable
666                     .AccessibilityService_canTakeScreenshot, false)) {
667                 mCapabilities |= CAPABILITY_CAN_TAKE_SCREENSHOT;
668             }
669             TypedValue peekedValue = asAttributes.peekValue(
670                     com.android.internal.R.styleable.AccessibilityService_description);
671             if (peekedValue != null) {
672                 mDescriptionResId = peekedValue.resourceId;
673                 CharSequence nonLocalizedDescription = peekedValue.coerceToString();
674                 if (nonLocalizedDescription != null) {
675                     mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
676                 }
677             }
678             peekedValue = asAttributes.peekValue(
679                 com.android.internal.R.styleable.AccessibilityService_summary);
680             if (peekedValue != null) {
681                 mSummaryResId = peekedValue.resourceId;
682                 CharSequence nonLocalizedSummary = peekedValue.coerceToString();
683                 if (nonLocalizedSummary != null) {
684                     mNonLocalizedSummary = nonLocalizedSummary.toString().trim();
685                 }
686             }
687             peekedValue = asAttributes.peekValue(
688                     com.android.internal.R.styleable.AccessibilityService_animatedImageDrawable);
689             if (peekedValue != null) {
690                 mAnimatedImageRes = peekedValue.resourceId;
691             }
692             peekedValue = asAttributes.peekValue(
693                     com.android.internal.R.styleable.AccessibilityService_htmlDescription);
694             if (peekedValue != null) {
695                 mHtmlDescriptionRes = peekedValue.resourceId;
696             }
697             asAttributes.recycle();
698         } catch (NameNotFoundException e) {
699             throw new XmlPullParserException( "Unable to create context for: "
700                     + serviceInfo.packageName);
701         } finally {
702             if (parser != null) {
703                 parser.close();
704             }
705         }
706     }
707 
708     /**
709      * Updates the properties that an AccessibilityService can change dynamically.
710      * <p>
711      * Note: A11y services targeting APIs > Q, it cannot update flagRequestAccessibilityButton
712      * dynamically.
713      * </p>
714      *
715      * @param platformCompat The platform compat service to check the compatibility change.
716      * @param other The info from which to update the properties.
717      *
718      * @hide
719      */
updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat, AccessibilityServiceInfo other)720     public void updateDynamicallyConfigurableProperties(IPlatformCompat platformCompat,
721             AccessibilityServiceInfo other) {
722         if (isRequestAccessibilityButtonChangeEnabled(platformCompat)) {
723             other.flags &= ~FLAG_REQUEST_ACCESSIBILITY_BUTTON;
724             other.flags |= (flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON);
725         }
726         eventTypes = other.eventTypes;
727         packageNames = other.packageNames;
728         feedbackType = other.feedbackType;
729         notificationTimeout = other.notificationTimeout;
730         mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout;
731         mInteractiveUiTimeout = other.mInteractiveUiTimeout;
732         flags = other.flags;
733     }
734 
isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat)735     private boolean isRequestAccessibilityButtonChangeEnabled(IPlatformCompat platformCompat) {
736         if (mResolveInfo == null) {
737             return true;
738         }
739         try {
740             if (platformCompat != null) {
741                 return platformCompat.isChangeEnabled(REQUEST_ACCESSIBILITY_BUTTON_CHANGE,
742                         mResolveInfo.serviceInfo.applicationInfo);
743             }
744         } catch (RemoteException ignore) {
745         }
746         return mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q;
747     }
748 
749     /**
750      * @hide
751      */
setComponentName(ComponentName component)752     public void setComponentName(ComponentName component) {
753         mComponentName = component;
754     }
755 
756     /**
757      * @hide
758      */
getComponentName()759     public ComponentName getComponentName() {
760         return mComponentName;
761     }
762 
763     /**
764      * The accessibility service id.
765      * <p>
766      *   <strong>Generated by the system.</strong>
767      * </p>
768      * @return The id.
769      */
getId()770     public String getId() {
771         return mComponentName.flattenToShortString();
772     }
773 
774     /**
775      * The service {@link ResolveInfo}.
776      * <p>
777      *   <strong>Generated by the system.</strong>
778      * </p>
779      * @return The info.
780      */
getResolveInfo()781     public ResolveInfo getResolveInfo() {
782         return mResolveInfo;
783     }
784 
785     /**
786      * The settings activity name.
787      * <p>
788      *    <strong>Statically set from
789      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
790      * </p>
791      * @return The settings activity name.
792      */
getSettingsActivityName()793     public String getSettingsActivityName() {
794         return mSettingsActivityName;
795     }
796 
797     /**
798      * Gets the animated image resource id.
799      *
800      * @return The animated image resource id.
801      *
802      * @hide
803      */
getAnimatedImageRes()804     public int getAnimatedImageRes() {
805         return mAnimatedImageRes;
806     }
807 
808     /**
809      * The animated image drawable.
810      * <p>
811      *    Image can not exceed the screen size.
812      *    <strong>Statically set from
813      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
814      * </p>
815      * @return The animated image drawable, or null if the resource is invalid or the image
816      * exceed the screen size.
817      *
818      * @hide
819      */
820     @Nullable
loadAnimatedImage(@onNull Context context)821     public Drawable loadAnimatedImage(@NonNull Context context)  {
822         if (mAnimatedImageRes == /* invalid */ 0) {
823             return null;
824         }
825 
826         return loadSafeAnimatedImage(context, mResolveInfo.serviceInfo.applicationInfo,
827                 mAnimatedImageRes);
828     }
829 
830     /**
831      * Whether this service can retrieve the current window's content.
832      * <p>
833      *    <strong>Statically set from
834      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
835      * </p>
836      * @return True if window content can be retrieved.
837      *
838      * @deprecated Use {@link #getCapabilities()}.
839      */
getCanRetrieveWindowContent()840     public boolean getCanRetrieveWindowContent() {
841         return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
842     }
843 
844     /**
845      * Returns the bit mask of capabilities this accessibility service has such as
846      * being able to retrieve the active window content, etc.
847      *
848      * @return The capability bit mask.
849      *
850      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
851      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
852      * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
853      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
854      * @see #CAPABILITY_CAN_PERFORM_GESTURES
855      * @see #CAPABILITY_CAN_TAKE_SCREENSHOT
856      */
getCapabilities()857     public int getCapabilities() {
858         return mCapabilities;
859     }
860 
861     /**
862      * Sets the bit mask of capabilities this accessibility service has such as
863      * being able to retrieve the active window content, etc.
864      *
865      * @param capabilities The capability bit mask.
866      *
867      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
868      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
869      * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
870      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
871      * @see #CAPABILITY_CAN_PERFORM_GESTURES
872      * @see #CAPABILITY_CAN_TAKE_SCREENSHOT
873      *
874      * @hide
875      */
876     @UnsupportedAppUsage
setCapabilities(int capabilities)877     public void setCapabilities(int capabilities) {
878         mCapabilities = capabilities;
879     }
880 
881     /**
882      * The localized summary of the accessibility service.
883      * <p>
884      *    <strong>Statically set from
885      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
886      * </p>
887      * @return The localized summary if available, and {@code null} if a summary
888      * has not been provided.
889      */
loadSummary(PackageManager packageManager)890     public CharSequence loadSummary(PackageManager packageManager) {
891         if (mSummaryResId == 0) {
892             return mNonLocalizedSummary;
893         }
894         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
895         CharSequence summary = packageManager.getText(serviceInfo.packageName,
896                 mSummaryResId, serviceInfo.applicationInfo);
897         if (summary != null) {
898             return summary.toString().trim();
899         }
900         return null;
901     }
902 
903     /**
904      * Gets the non-localized description of the accessibility service.
905      * <p>
906      *    <strong>Statically set from
907      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
908      * </p>
909      * @return The description.
910      *
911      * @deprecated Use {@link #loadDescription(PackageManager)}.
912      */
getDescription()913     public String getDescription() {
914         return mNonLocalizedDescription;
915     }
916 
917     /**
918      * The localized description of the accessibility service.
919      * <p>
920      *    <strong>Statically set from
921      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
922      * </p>
923      * @return The localized description.
924      */
loadDescription(PackageManager packageManager)925     public String loadDescription(PackageManager packageManager) {
926         if (mDescriptionResId == 0) {
927             return mNonLocalizedDescription;
928         }
929         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
930         CharSequence description = packageManager.getText(serviceInfo.packageName,
931                 mDescriptionResId, serviceInfo.applicationInfo);
932         if (description != null) {
933             return description.toString().trim();
934         }
935         return null;
936     }
937 
938     /**
939      * The localized and restricted html description of the accessibility service.
940      * <p>
941      *    Filters the <img> tag which do not meet the custom specification and the <a> tag.
942      *    <strong>Statically set from
943      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
944      * </p>
945      * @return The localized and restricted html description.
946      *
947      * @hide
948      */
949     @Nullable
loadHtmlDescription(@onNull PackageManager packageManager)950     public String loadHtmlDescription(@NonNull PackageManager packageManager) {
951         if (mHtmlDescriptionRes == /* invalid */ 0) {
952             return null;
953         }
954 
955         final ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
956         final CharSequence htmlDescription = packageManager.getText(serviceInfo.packageName,
957                 mHtmlDescriptionRes, serviceInfo.applicationInfo);
958         if (htmlDescription != null) {
959             return getFilteredHtmlText(htmlDescription.toString().trim());
960         }
961         return null;
962     }
963 
964     /**
965      * Set the recommended time that non-interactive controls need to remain on the screen to
966      * support the user.
967      * <p>
968      *     <strong>This value can be dynamically set at runtime by
969      *     {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
970      * </p>
971      *
972      * @param timeout The timeout in milliseconds.
973      *
974      * @see android.R.styleable#AccessibilityService_nonInteractiveUiTimeout
975      */
setNonInteractiveUiTimeoutMillis(@ntRangefrom = 0) int timeout)976     public void setNonInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) {
977         mNonInteractiveUiTimeout = timeout;
978     }
979 
980     /**
981      * Get the recommended timeout for non-interactive controls.
982      *
983      * @return The timeout in milliseconds.
984      *
985      * @see #setNonInteractiveUiTimeoutMillis(int)
986      */
getNonInteractiveUiTimeoutMillis()987     public int getNonInteractiveUiTimeoutMillis() {
988         return mNonInteractiveUiTimeout;
989     }
990 
991     /**
992      * Set the recommended time that interactive controls need to remain on the screen to
993      * support the user.
994      * <p>
995      *     <strong>This value can be dynamically set at runtime by
996      *     {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
997      * </p>
998      *
999      * @param timeout The timeout in milliseconds.
1000      *
1001      * @see android.R.styleable#AccessibilityService_interactiveUiTimeout
1002      */
setInteractiveUiTimeoutMillis(@ntRangefrom = 0) int timeout)1003     public void setInteractiveUiTimeoutMillis(@IntRange(from = 0) int timeout) {
1004         mInteractiveUiTimeout = timeout;
1005     }
1006 
1007     /**
1008      * Get the recommended timeout for interactive controls.
1009      *
1010      * @return The timeout in milliseconds.
1011      *
1012      * @see #setInteractiveUiTimeoutMillis(int)
1013      */
getInteractiveUiTimeoutMillis()1014     public int getInteractiveUiTimeoutMillis() {
1015         return mInteractiveUiTimeout;
1016     }
1017 
1018     /** {@hide} */
isDirectBootAware()1019     public boolean isDirectBootAware() {
1020         return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
1021                 || mResolveInfo.serviceInfo.directBootAware;
1022     }
1023 
1024     /**
1025      * {@inheritDoc}
1026      */
describeContents()1027     public int describeContents() {
1028         return 0;
1029     }
1030 
writeToParcel(Parcel parcel, int flagz)1031     public void writeToParcel(Parcel parcel, int flagz) {
1032         parcel.writeInt(eventTypes);
1033         parcel.writeStringArray(packageNames);
1034         parcel.writeInt(feedbackType);
1035         parcel.writeLong(notificationTimeout);
1036         parcel.writeInt(mNonInteractiveUiTimeout);
1037         parcel.writeInt(mInteractiveUiTimeout);
1038         parcel.writeInt(flags);
1039         parcel.writeInt(crashed ? 1 : 0);
1040         parcel.writeParcelable(mComponentName, flagz);
1041         parcel.writeParcelable(mResolveInfo, 0);
1042         parcel.writeString(mSettingsActivityName);
1043         parcel.writeInt(mCapabilities);
1044         parcel.writeInt(mSummaryResId);
1045         parcel.writeString(mNonLocalizedSummary);
1046         parcel.writeInt(mDescriptionResId);
1047         parcel.writeInt(mAnimatedImageRes);
1048         parcel.writeInt(mHtmlDescriptionRes);
1049         parcel.writeString(mNonLocalizedDescription);
1050     }
1051 
initFromParcel(Parcel parcel)1052     private void initFromParcel(Parcel parcel) {
1053         eventTypes = parcel.readInt();
1054         packageNames = parcel.readStringArray();
1055         feedbackType = parcel.readInt();
1056         notificationTimeout = parcel.readLong();
1057         mNonInteractiveUiTimeout = parcel.readInt();
1058         mInteractiveUiTimeout = parcel.readInt();
1059         flags = parcel.readInt();
1060         crashed = parcel.readInt() != 0;
1061         mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
1062         mResolveInfo = parcel.readParcelable(null);
1063         mSettingsActivityName = parcel.readString();
1064         mCapabilities = parcel.readInt();
1065         mSummaryResId = parcel.readInt();
1066         mNonLocalizedSummary = parcel.readString();
1067         mDescriptionResId = parcel.readInt();
1068         mAnimatedImageRes = parcel.readInt();
1069         mHtmlDescriptionRes = parcel.readInt();
1070         mNonLocalizedDescription = parcel.readString();
1071     }
1072 
1073     @Override
hashCode()1074     public int hashCode() {
1075         return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
1076     }
1077 
1078     @Override
equals(Object obj)1079     public boolean equals(Object obj) {
1080         if (this == obj) {
1081             return true;
1082         }
1083         if (obj == null) {
1084             return false;
1085         }
1086         if (getClass() != obj.getClass()) {
1087             return false;
1088         }
1089         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
1090         if (mComponentName == null) {
1091             if (other.mComponentName != null) {
1092                 return false;
1093             }
1094         } else if (!mComponentName.equals(other.mComponentName)) {
1095             return false;
1096         }
1097         return true;
1098     }
1099 
1100     @Override
toString()1101     public String toString() {
1102         StringBuilder stringBuilder = new StringBuilder();
1103         appendEventTypes(stringBuilder, eventTypes);
1104         stringBuilder.append(", ");
1105         appendPackageNames(stringBuilder, packageNames);
1106         stringBuilder.append(", ");
1107         appendFeedbackTypes(stringBuilder, feedbackType);
1108         stringBuilder.append(", ");
1109         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
1110         stringBuilder.append(", ");
1111         stringBuilder.append("nonInteractiveUiTimeout: ").append(mNonInteractiveUiTimeout);
1112         stringBuilder.append(", ");
1113         stringBuilder.append("interactiveUiTimeout: ").append(mInteractiveUiTimeout);
1114         stringBuilder.append(", ");
1115         appendFlags(stringBuilder, flags);
1116         stringBuilder.append(", ");
1117         stringBuilder.append("id: ").append(getId());
1118         stringBuilder.append(", ");
1119         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
1120         stringBuilder.append(", ");
1121         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
1122         stringBuilder.append(", ");
1123         stringBuilder.append("summary: ").append(mNonLocalizedSummary);
1124         stringBuilder.append(", ");
1125         appendCapabilities(stringBuilder, mCapabilities);
1126         return stringBuilder.toString();
1127     }
1128 
appendFeedbackTypes(StringBuilder stringBuilder, @FeedbackType int feedbackTypes)1129     private static void appendFeedbackTypes(StringBuilder stringBuilder,
1130             @FeedbackType int feedbackTypes) {
1131         stringBuilder.append("feedbackTypes:");
1132         stringBuilder.append("[");
1133         while (feedbackTypes != 0) {
1134             final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes));
1135             stringBuilder.append(feedbackTypeToString(feedbackTypeBit));
1136             feedbackTypes &= ~feedbackTypeBit;
1137             if (feedbackTypes != 0) {
1138                 stringBuilder.append(", ");
1139             }
1140         }
1141         stringBuilder.append("]");
1142     }
1143 
appendPackageNames(StringBuilder stringBuilder, String[] packageNames)1144     private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) {
1145         stringBuilder.append("packageNames:");
1146         stringBuilder.append("[");
1147         if (packageNames != null) {
1148             final int packageNameCount = packageNames.length;
1149             for (int i = 0; i < packageNameCount; i++) {
1150                 stringBuilder.append(packageNames[i]);
1151                 if (i < packageNameCount - 1) {
1152                     stringBuilder.append(", ");
1153                 }
1154             }
1155         }
1156         stringBuilder.append("]");
1157     }
1158 
appendEventTypes(StringBuilder stringBuilder, int eventTypes)1159     private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) {
1160         stringBuilder.append("eventTypes:");
1161         stringBuilder.append("[");
1162         while (eventTypes != 0) {
1163             final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes));
1164             stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit));
1165             eventTypes &= ~eventTypeBit;
1166             if (eventTypes != 0) {
1167                 stringBuilder.append(", ");
1168             }
1169         }
1170         stringBuilder.append("]");
1171     }
1172 
appendFlags(StringBuilder stringBuilder, int flags)1173     private static void appendFlags(StringBuilder stringBuilder, int flags) {
1174         stringBuilder.append("flags:");
1175         stringBuilder.append("[");
1176         while (flags != 0) {
1177             final int flagBit = (1 << Integer.numberOfTrailingZeros(flags));
1178             stringBuilder.append(flagToString(flagBit));
1179             flags &= ~flagBit;
1180             if (flags != 0) {
1181                 stringBuilder.append(", ");
1182             }
1183         }
1184         stringBuilder.append("]");
1185     }
1186 
appendCapabilities(StringBuilder stringBuilder, int capabilities)1187     private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
1188         stringBuilder.append("capabilities:");
1189         stringBuilder.append("[");
1190         while (capabilities != 0) {
1191             final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
1192             stringBuilder.append(capabilityToString(capabilityBit));
1193             capabilities &= ~capabilityBit;
1194             if (capabilities != 0) {
1195                 stringBuilder.append(", ");
1196             }
1197         }
1198         stringBuilder.append("]");
1199     }
1200 
1201     /**
1202      * Returns the string representation of a feedback type. For example,
1203      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
1204      *
1205      * @param feedbackType The feedback type.
1206      * @return The string representation.
1207      */
feedbackTypeToString(int feedbackType)1208     public static String feedbackTypeToString(int feedbackType) {
1209         StringBuilder builder = new StringBuilder();
1210         builder.append("[");
1211         while (feedbackType != 0) {
1212             final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
1213             feedbackType &= ~feedbackTypeFlag;
1214             switch (feedbackTypeFlag) {
1215                 case FEEDBACK_AUDIBLE:
1216                     if (builder.length() > 1) {
1217                         builder.append(", ");
1218                     }
1219                     builder.append("FEEDBACK_AUDIBLE");
1220                     break;
1221                 case FEEDBACK_HAPTIC:
1222                     if (builder.length() > 1) {
1223                         builder.append(", ");
1224                     }
1225                     builder.append("FEEDBACK_HAPTIC");
1226                     break;
1227                 case FEEDBACK_GENERIC:
1228                     if (builder.length() > 1) {
1229                         builder.append(", ");
1230                     }
1231                     builder.append("FEEDBACK_GENERIC");
1232                     break;
1233                 case FEEDBACK_SPOKEN:
1234                     if (builder.length() > 1) {
1235                         builder.append(", ");
1236                     }
1237                     builder.append("FEEDBACK_SPOKEN");
1238                     break;
1239                 case FEEDBACK_VISUAL:
1240                     if (builder.length() > 1) {
1241                         builder.append(", ");
1242                     }
1243                     builder.append("FEEDBACK_VISUAL");
1244                     break;
1245                 case FEEDBACK_BRAILLE:
1246                     if (builder.length() > 1) {
1247                         builder.append(", ");
1248                     }
1249                     builder.append("FEEDBACK_BRAILLE");
1250                     break;
1251             }
1252         }
1253         builder.append("]");
1254         return builder.toString();
1255     }
1256 
1257     /**
1258      * Returns the string representation of a flag. For example,
1259      * {@link #DEFAULT} is represented by the string DEFAULT.
1260      *
1261      * @param flag The flag.
1262      * @return The string representation.
1263      */
flagToString(int flag)1264     public static String flagToString(int flag) {
1265         switch (flag) {
1266             case DEFAULT:
1267                 return "DEFAULT";
1268             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
1269                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
1270             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
1271                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
1272             case FLAG_SERVICE_HANDLES_DOUBLE_TAP:
1273                 return "FLAG_SERVICE_HANDLES_DOUBLE_TAP";
1274             case FLAG_REQUEST_MULTI_FINGER_GESTURES:
1275                 return "FLAG_REQUEST_MULTI_FINGER_GESTURES";
1276             case FLAG_REQUEST_2_FINGER_PASSTHROUGH:
1277                 return "FLAG_REQUEST_2_FINGER_PASSTHROUGH";
1278             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
1279                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
1280             case FLAG_REPORT_VIEW_IDS:
1281                 return "FLAG_REPORT_VIEW_IDS";
1282             case FLAG_REQUEST_FILTER_KEY_EVENTS:
1283                 return "FLAG_REQUEST_FILTER_KEY_EVENTS";
1284             case FLAG_RETRIEVE_INTERACTIVE_WINDOWS:
1285                 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
1286             case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
1287                 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
1288             case FLAG_REQUEST_ACCESSIBILITY_BUTTON:
1289                 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
1290             case FLAG_REQUEST_FINGERPRINT_GESTURES:
1291                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
1292             case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK:
1293                 return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK";
1294             default:
1295                 return null;
1296         }
1297     }
1298 
1299     /**
1300      * Returns the string representation of a capability. For example,
1301      * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
1302      * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
1303      *
1304      * @param capability The capability.
1305      * @return The string representation.
1306      */
capabilityToString(int capability)1307     public static String capabilityToString(int capability) {
1308         switch (capability) {
1309             case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
1310                 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
1311             case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
1312                 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
1313             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
1314                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
1315             case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
1316                 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS";
1317             case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
1318                 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
1319             case CAPABILITY_CAN_PERFORM_GESTURES:
1320                 return "CAPABILITY_CAN_PERFORM_GESTURES";
1321             case CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES:
1322                 return "CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES";
1323             case CAPABILITY_CAN_TAKE_SCREENSHOT:
1324                 return "CAPABILITY_CAN_TAKE_SCREENSHOT";
1325             default:
1326                 return "UNKNOWN";
1327         }
1328     }
1329 
1330     /**
1331      * @hide
1332      * @return The list of {@link CapabilityInfo} objects.
1333      * @deprecated The version that takes a context works better.
1334      */
getCapabilityInfos()1335     public List<CapabilityInfo> getCapabilityInfos() {
1336         return getCapabilityInfos(null);
1337     }
1338 
1339     /**
1340      * @hide
1341      * @param context A valid context
1342      * @return The list of {@link CapabilityInfo} objects.
1343      */
getCapabilityInfos(Context context)1344     public List<CapabilityInfo> getCapabilityInfos(Context context) {
1345         if (mCapabilities == 0) {
1346             return Collections.emptyList();
1347         }
1348         int capabilities = mCapabilities;
1349         List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
1350         SparseArray<CapabilityInfo> capabilityInfoSparseArray =
1351                 getCapabilityInfoSparseArray(context);
1352         while (capabilities != 0) {
1353             final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
1354             capabilities &= ~capabilityBit;
1355             CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit);
1356             if (capabilityInfo != null) {
1357                 capabilityInfos.add(capabilityInfo);
1358             }
1359         }
1360         return capabilityInfos;
1361     }
1362 
getCapabilityInfoSparseArray(Context context)1363     private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) {
1364         if (sAvailableCapabilityInfos == null) {
1365             sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>();
1366             sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
1367                     new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
1368                             R.string.capability_title_canRetrieveWindowContent,
1369                             R.string.capability_desc_canRetrieveWindowContent));
1370             sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
1371                     new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
1372                             R.string.capability_title_canRequestTouchExploration,
1373                             R.string.capability_desc_canRequestTouchExploration));
1374             sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
1375                     new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
1376                             R.string.capability_title_canRequestFilterKeyEvents,
1377                             R.string.capability_desc_canRequestFilterKeyEvents));
1378             sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
1379                     new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
1380                             R.string.capability_title_canControlMagnification,
1381                             R.string.capability_desc_canControlMagnification));
1382             sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
1383                     new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
1384                             R.string.capability_title_canPerformGestures,
1385                             R.string.capability_desc_canPerformGestures));
1386             sAvailableCapabilityInfos.put(CAPABILITY_CAN_TAKE_SCREENSHOT,
1387                     new CapabilityInfo(CAPABILITY_CAN_TAKE_SCREENSHOT,
1388                             R.string.capability_title_canTakeScreenshot,
1389                             R.string.capability_desc_canTakeScreenshot));
1390             if ((context == null) || fingerprintAvailable(context)) {
1391                 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES,
1392                         new CapabilityInfo(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES,
1393                                 R.string.capability_title_canCaptureFingerprintGestures,
1394                                 R.string.capability_desc_canCaptureFingerprintGestures));
1395             }
1396         }
1397         return sAvailableCapabilityInfos;
1398     }
1399 
fingerprintAvailable(Context context)1400     private static boolean fingerprintAvailable(Context context) {
1401         return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT)
1402                 && context.getSystemService(FingerprintManager.class).isHardwareDetected();
1403     }
1404     /**
1405      * @hide
1406      */
1407     public static final class CapabilityInfo {
1408         public final int capability;
1409         public final int titleResId;
1410         public final int descResId;
1411 
CapabilityInfo(int capability, int titleResId, int descResId)1412         public CapabilityInfo(int capability, int titleResId, int descResId) {
1413             this.capability = capability;
1414             this.titleResId = titleResId;
1415             this.descResId = descResId;
1416         }
1417     }
1418 
1419     /**
1420      * @see Parcelable.Creator
1421      */
1422     public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
1423             new Parcelable.Creator<AccessibilityServiceInfo>() {
1424         public AccessibilityServiceInfo createFromParcel(Parcel parcel) {
1425             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
1426             info.initFromParcel(parcel);
1427             return info;
1428         }
1429 
1430         public AccessibilityServiceInfo[] newArray(int size) {
1431             return new AccessibilityServiceInfo[size];
1432         }
1433     };
1434 }
1435