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