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