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