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