• 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 android.content.ComponentName;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.content.pm.PackageManager.NameNotFoundException;
23 import android.content.pm.ResolveInfo;
24 import android.content.pm.ServiceInfo;
25 import android.content.res.Resources;
26 import android.content.res.TypedArray;
27 import android.content.res.XmlResourceParser;
28 import android.hardware.fingerprint.FingerprintManager;
29 import android.os.Build;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.util.AttributeSet;
33 import android.util.SparseArray;
34 import android.util.TypedValue;
35 import android.util.Xml;
36 import android.view.View;
37 import android.view.accessibility.AccessibilityEvent;
38 import android.view.accessibility.AccessibilityNodeInfo;
39 
40 import com.android.internal.R;
41 
42 import org.xmlpull.v1.XmlPullParser;
43 import org.xmlpull.v1.XmlPullParserException;
44 
45 import java.io.IOException;
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.List;
49 
50 import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
51 
52 /**
53  * This class describes an {@link AccessibilityService}. The system notifies an
54  * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s
55  * according to the information encapsulated in this class.
56  *
57  * <div class="special reference">
58  * <h3>Developer Guides</h3>
59  * <p>For more information about creating AccessibilityServices, read the
60  * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a>
61  * developer guide.</p>
62  * </div>
63  *
64  * @attr ref android.R.styleable#AccessibilityService_accessibilityEventTypes
65  * @attr ref android.R.styleable#AccessibilityService_accessibilityFeedbackType
66  * @attr ref android.R.styleable#AccessibilityService_accessibilityFlags
67  * @attr ref android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
68  * @attr ref android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
69  * @attr ref android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
70  * @attr ref android.R.styleable#AccessibilityService_canRetrieveWindowContent
71  * @attr ref android.R.styleable#AccessibilityService_description
72  * @attr ref android.R.styleable#AccessibilityService_summary
73  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
74  * @attr ref android.R.styleable#AccessibilityService_packageNames
75  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
76  * @see AccessibilityService
77  * @see android.view.accessibility.AccessibilityEvent
78  * @see android.view.accessibility.AccessibilityManager
79  */
80 public class AccessibilityServiceInfo implements Parcelable {
81 
82     private static final String TAG_ACCESSIBILITY_SERVICE = "accessibility-service";
83 
84     /**
85      * Capability: This accessibility service can retrieve the active window content.
86      * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
87      */
88     public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
89 
90     /**
91      * Capability: This accessibility service can request touch exploration mode in which
92      * touched items are spoken aloud and the UI can be explored via gestures.
93      * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
94      */
95     public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
96 
97     /**
98      * @deprecated No longer used
99      */
100     public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
101 
102     /**
103      * Capability: This accessibility service can request to filter the key event stream.
104      * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
105      */
106     public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 0x00000008;
107 
108     /**
109      * Capability: This accessibility service can control display magnification.
110      * @see android.R.styleable#AccessibilityService_canControlMagnification
111      */
112     public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 0x00000010;
113 
114     /**
115      * Capability: This accessibility service can perform gestures.
116      * @see android.R.styleable#AccessibilityService_canPerformGestures
117      */
118     public static final int CAPABILITY_CAN_PERFORM_GESTURES = 0x00000020;
119 
120     /**
121      * Capability: This accessibility service can capture gestures from the fingerprint sensor
122      * @see android.R.styleable#AccessibilityService_canRequestFingerprintGestures
123      */
124     public static final int CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES = 0x00000040;
125 
126     private static SparseArray<CapabilityInfo> sAvailableCapabilityInfos;
127 
128     /**
129      * Denotes spoken feedback.
130      */
131     public static final int FEEDBACK_SPOKEN = 0x0000001;
132 
133     /**
134      * Denotes haptic feedback.
135      */
136     public static final int FEEDBACK_HAPTIC =  0x0000002;
137 
138     /**
139      * Denotes audible (not spoken) feedback.
140      */
141     public static final int FEEDBACK_AUDIBLE = 0x0000004;
142 
143     /**
144      * Denotes visual feedback.
145      */
146     public static final int FEEDBACK_VISUAL = 0x0000008;
147 
148     /**
149      * Denotes generic feedback.
150      */
151     public static final int FEEDBACK_GENERIC = 0x0000010;
152 
153     /**
154      * Denotes braille feedback.
155      */
156     public static final int FEEDBACK_BRAILLE = 0x0000020;
157 
158     /**
159      * Mask for all feedback types.
160      *
161      * @see #FEEDBACK_SPOKEN
162      * @see #FEEDBACK_HAPTIC
163      * @see #FEEDBACK_AUDIBLE
164      * @see #FEEDBACK_VISUAL
165      * @see #FEEDBACK_GENERIC
166      * @see #FEEDBACK_BRAILLE
167      */
168     public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
169 
170     /**
171      * If an {@link AccessibilityService} is the default for a given type.
172      * Default service is invoked only if no package specific one exists. In case of
173      * more than one package specific service only the earlier registered is notified.
174      */
175     public static final int DEFAULT = 0x0000001;
176 
177     /**
178      * If this flag is set the system will regard views that are not important
179      * for accessibility in addition to the ones that are important for accessibility.
180      * That is, views that are marked as not important for accessibility via
181      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or
182      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are
183      * marked as potentially important for accessibility via
184      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
185      * that are not important for accessibility, are reported while querying the window
186      * content and also the accessibility service will receive accessibility events from
187      * them.
188      * <p>
189      * <strong>Note:</strong> For accessibility services targeting API version
190      * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
191      * set for the system to regard views that are not important for accessibility. For
192      * accessibility services targeting API version lower than
193      * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
194      * regarded for accessibility purposes.
195      * </p>
196      * <p>
197      * Usually views not important for accessibility are layout managers that do not
198      * react to user actions, do not draw any content, and do not have any special
199      * semantics in the context of the screen content. For example, a three by three
200      * grid can be implemented as three horizontal linear layouts and one vertical,
201      * or three vertical linear layouts and one horizontal, or one grid layout, etc.
202      * In this context the actual layout mangers used to achieve the grid configuration
203      * are not important, rather it is important that there are nine evenly distributed
204      * elements.
205      * </p>
206      */
207     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
208 
209     /**
210      * This flag requests that the system gets into touch exploration mode.
211      * In this mode a single finger moving on the screen behaves as a mouse
212      * pointer hovering over the user interface. The system will also detect
213      * certain gestures performed on the touch screen and notify this service.
214      * The system will enable touch exploration mode if there is at least one
215      * accessibility service that has this flag set. Hence, clearing this
216      * flag does not guarantee that the device will not be in touch exploration
217      * mode since there may be another enabled service that requested it.
218      * <p>
219      * For accessibility services targeting API version higher than
220      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
221      * this flag have to declare this capability in their meta-data by setting
222      * the attribute {@link android.R.attr#canRequestTouchExplorationMode
223      * canRequestTouchExplorationMode} to true, otherwise this flag will
224      * be ignored. For how to declare the meta-data of a service refer to
225      * {@value AccessibilityService#SERVICE_META_DATA}.
226      * </p>
227      * <p>
228      * Services targeting API version equal to or lower than
229      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
230      * the first time they are run, if this flag is specified, a dialog is
231      * shown to the user to confirm enabling explore by touch.
232      * </p>
233      * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode
234      */
235     public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
236 
237     /**
238      * @deprecated No longer used
239      */
240     public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
241 
242     /**
243      * This flag requests that the {@link AccessibilityNodeInfo}s obtained
244      * by an {@link AccessibilityService} contain the id of the source view.
245      * The source view id will be a fully qualified resource name of the
246      * form "package:id/name", for example "foo.bar:id/my_list", and it is
247      * useful for UI test automation. This flag is not set by default.
248      */
249     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
250 
251     /**
252      * This flag requests from the system to filter key events. If this flag
253      * is set the accessibility service will receive the key events before
254      * applications allowing it implement global shortcuts.
255      * <p>
256      * Services that want to set this flag have to declare this capability
257      * in their meta-data by setting the attribute {@link android.R.attr
258      * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true,
259      * otherwise this flag will be ignored. For how to declare the meta-data
260      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
261      * </p>
262      * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents
263      */
264     public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
265 
266     /**
267      * This flag indicates to the system that the accessibility service wants
268      * to access content of all interactive windows. An interactive window is a
269      * window that has input focus or can be touched by a sighted user when explore
270      * by touch is not enabled. If this flag is not set your service will not receive
271      * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
272      * events, calling AccessibilityService{@link AccessibilityService#getWindows()
273      * AccessibilityService.getWindows()} will return an empty list, and {@link
274      * AccessibilityNodeInfo#getWindow() AccessibilityNodeInfo.getWindow()} will
275      * return null.
276      * <p>
277      * Services that want to set this flag have to declare the capability
278      * to retrieve window content in their meta-data by setting the attribute
279      * {@link android.R.attr#canRetrieveWindowContent canRetrieveWindowContent} to
280      * true, otherwise this flag will be ignored. For how to declare the meta-data
281      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
282      * </p>
283      * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent
284      */
285     public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040;
286 
287     /**
288      * This flag requests that all audio tracks system-wide with
289      * {@link android.media.AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY} be controlled by the
290      * {@link android.media.AudioManager#STREAM_ACCESSIBILITY} volume.
291      */
292     public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 0x00000080;
293 
294      /**
295      * This flag indicates to the system that the accessibility service requests that an
296      * accessibility button be shown within the system's navigation area, if available.
297      */
298     public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 0x00000100;
299 
300     /**
301      * This flag requests that all fingerprint gestures be sent to the accessibility service.
302      * It is handled in {@link FingerprintGestureController}
303      */
304     public static final int FLAG_REQUEST_FINGERPRINT_GESTURES = 0x00000200;
305 
306     /** {@hide} */
307     public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000;
308 
309     /**
310      * The event types an {@link AccessibilityService} is interested in.
311      * <p>
312      *   <strong>Can be dynamically set at runtime.</strong>
313      * </p>
314      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED
315      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED
316      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED
317      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED
318      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
319      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
320      * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
321      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
322      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
323      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
324      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
325      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
326      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
327      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
328      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START
329      * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END
330      * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT
331      * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START
332      * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END
333      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED
334      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
335      * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY
336      * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED
337      */
338     public int eventTypes;
339 
340     /**
341      * The package names an {@link AccessibilityService} is interested in. Setting
342      * to <code>null</code> is equivalent to all packages.
343      * <p>
344      *   <strong>Can be dynamically set at runtime.</strong>
345      * </p>
346      */
347     public String[] packageNames;
348 
349     /**
350      * The feedback type an {@link AccessibilityService} provides.
351      * <p>
352      *   <strong>Can be dynamically set at runtime.</strong>
353      * </p>
354      * @see #FEEDBACK_AUDIBLE
355      * @see #FEEDBACK_GENERIC
356      * @see #FEEDBACK_HAPTIC
357      * @see #FEEDBACK_SPOKEN
358      * @see #FEEDBACK_VISUAL
359      * @see #FEEDBACK_BRAILLE
360      */
361     public int feedbackType;
362 
363     /**
364      * The timeout after the most recent event of a given type before an
365      * {@link AccessibilityService} is notified.
366      * <p>
367      *   <strong>Can be dynamically set at runtime.</strong>.
368      * </p>
369      * <p>
370      * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
371      *       events to the client too frequently since this is accomplished via an expensive
372      *       interprocess call. One can think of the timeout as a criteria to determine when
373      *       event generation has settled down.
374      */
375     public long notificationTimeout;
376 
377     /**
378      * This field represents a set of flags used for configuring an
379      * {@link AccessibilityService}.
380      * <p>
381      *   <strong>Can be dynamically set at runtime.</strong>
382      * </p>
383      * @see #DEFAULT
384      * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
385      * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE
386      * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY
387      * @see #FLAG_REQUEST_FILTER_KEY_EVENTS
388      * @see #FLAG_REPORT_VIEW_IDS
389      * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS
390      * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME
391      * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON
392      */
393     public int flags;
394 
395     /**
396      * The component name the accessibility service.
397      */
398     private ComponentName mComponentName;
399 
400     /**
401      * The Service that implements this accessibility service component.
402      */
403     private ResolveInfo mResolveInfo;
404 
405     /**
406      * The accessibility service setting activity's name, used by the system
407      * settings to launch the setting activity of this accessibility service.
408      */
409     private String mSettingsActivityName;
410 
411     /**
412      * Bit mask with capabilities of this service.
413      */
414     private int mCapabilities;
415 
416     /**
417      * Resource id of the summary of the accessibility service.
418      */
419     private int mSummaryResId;
420 
421     /**
422      * Non-localized summary of the accessibility service.
423      */
424     private String mNonLocalizedSummary;
425 
426     /**
427      * Resource id of the description of the accessibility service.
428      */
429     private int mDescriptionResId;
430 
431     /**
432      * Non localized description of the accessibility service.
433      */
434     private String mNonLocalizedDescription;
435 
436     /**
437      * Creates a new instance.
438      */
AccessibilityServiceInfo()439     public AccessibilityServiceInfo() {
440         /* do nothing */
441     }
442 
443     /**
444      * Creates a new instance.
445      *
446      * @param resolveInfo The service resolve info.
447      * @param context Context for accessing resources.
448      * @throws XmlPullParserException If a XML parsing error occurs.
449      * @throws IOException If a XML parsing error occurs.
450      *
451      * @hide
452      */
AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)453     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
454             throws XmlPullParserException, IOException {
455         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
456         mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
457         mResolveInfo = resolveInfo;
458 
459         XmlResourceParser parser = null;
460 
461         try {
462             PackageManager packageManager = context.getPackageManager();
463             parser = serviceInfo.loadXmlMetaData(packageManager,
464                     AccessibilityService.SERVICE_META_DATA);
465             if (parser == null) {
466                 return;
467             }
468 
469             int type = 0;
470             while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
471                 type = parser.next();
472             }
473 
474             String nodeName = parser.getName();
475             if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) {
476                 throw new XmlPullParserException( "Meta-data does not start with"
477                         + TAG_ACCESSIBILITY_SERVICE + " tag");
478             }
479 
480             AttributeSet allAttributes = Xml.asAttributeSet(parser);
481             Resources resources = packageManager.getResourcesForApplication(
482                     serviceInfo.applicationInfo);
483             TypedArray asAttributes = resources.obtainAttributes(allAttributes,
484                     com.android.internal.R.styleable.AccessibilityService);
485             eventTypes = asAttributes.getInt(
486                     com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes,
487                     0);
488             String packageNamez = asAttributes.getString(
489                     com.android.internal.R.styleable.AccessibilityService_packageNames);
490             if (packageNamez != null) {
491                 packageNames = packageNamez.split("(\\s)*,(\\s)*");
492             }
493             feedbackType = asAttributes.getInt(
494                     com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType,
495                     0);
496             notificationTimeout = asAttributes.getInt(
497                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
498                     0);
499             flags = asAttributes.getInt(
500                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
501             mSettingsActivityName = asAttributes.getString(
502                     com.android.internal.R.styleable.AccessibilityService_settingsActivity);
503             if (asAttributes.getBoolean(com.android.internal.R.styleable
504                     .AccessibilityService_canRetrieveWindowContent, false)) {
505                 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
506             }
507             if (asAttributes.getBoolean(com.android.internal.R.styleable
508                     .AccessibilityService_canRequestTouchExplorationMode, false)) {
509                 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
510             }
511             if (asAttributes.getBoolean(com.android.internal.R.styleable
512                     .AccessibilityService_canRequestFilterKeyEvents, false)) {
513                 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
514             }
515             if (asAttributes.getBoolean(com.android.internal.R.styleable
516                     .AccessibilityService_canControlMagnification, false)) {
517                 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION;
518             }
519             if (asAttributes.getBoolean(com.android.internal.R.styleable
520                     .AccessibilityService_canPerformGestures, false)) {
521                 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES;
522             }
523             if (asAttributes.getBoolean(com.android.internal.R.styleable
524                     .AccessibilityService_canRequestFingerprintGestures, false)) {
525                 mCapabilities |= CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES;
526             }
527             TypedValue peekedValue = asAttributes.peekValue(
528                     com.android.internal.R.styleable.AccessibilityService_description);
529             if (peekedValue != null) {
530                 mDescriptionResId = peekedValue.resourceId;
531                 CharSequence nonLocalizedDescription = peekedValue.coerceToString();
532                 if (nonLocalizedDescription != null) {
533                     mNonLocalizedDescription = nonLocalizedDescription.toString().trim();
534                 }
535             }
536             peekedValue = asAttributes.peekValue(
537                 com.android.internal.R.styleable.AccessibilityService_summary);
538             if (peekedValue != null) {
539                 mSummaryResId = peekedValue.resourceId;
540                 CharSequence nonLocalizedSummary = peekedValue.coerceToString();
541                 if (nonLocalizedSummary != null) {
542                     mNonLocalizedSummary = nonLocalizedSummary.toString().trim();
543                 }
544             }
545             asAttributes.recycle();
546         } catch (NameNotFoundException e) {
547             throw new XmlPullParserException( "Unable to create context for: "
548                     + serviceInfo.packageName);
549         } finally {
550             if (parser != null) {
551                 parser.close();
552             }
553         }
554     }
555 
556     /**
557      * Updates the properties that an AccessibilitySerivice can change dynamically.
558      *
559      * @param other The info from which to update the properties.
560      *
561      * @hide
562      */
updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other)563     public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) {
564         eventTypes = other.eventTypes;
565         packageNames = other.packageNames;
566         feedbackType = other.feedbackType;
567         notificationTimeout = other.notificationTimeout;
568         flags = other.flags;
569     }
570 
571     /**
572      * @hide
573      */
setComponentName(ComponentName component)574     public void setComponentName(ComponentName component) {
575         mComponentName = component;
576     }
577 
578     /**
579      * @hide
580      */
getComponentName()581     public ComponentName getComponentName() {
582         return mComponentName;
583     }
584 
585     /**
586      * The accessibility service id.
587      * <p>
588      *   <strong>Generated by the system.</strong>
589      * </p>
590      * @return The id.
591      */
getId()592     public String getId() {
593         return mComponentName.flattenToShortString();
594     }
595 
596     /**
597      * The service {@link ResolveInfo}.
598      * <p>
599      *   <strong>Generated by the system.</strong>
600      * </p>
601      * @return The info.
602      */
getResolveInfo()603     public ResolveInfo getResolveInfo() {
604         return mResolveInfo;
605     }
606 
607     /**
608      * The settings activity name.
609      * <p>
610      *    <strong>Statically set from
611      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
612      * </p>
613      * @return The settings activity name.
614      */
getSettingsActivityName()615     public String getSettingsActivityName() {
616         return mSettingsActivityName;
617     }
618 
619     /**
620      * Whether this service can retrieve the current window's content.
621      * <p>
622      *    <strong>Statically set from
623      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
624      * </p>
625      * @return True if window content can be retrieved.
626      *
627      * @deprecated Use {@link #getCapabilities()}.
628      */
getCanRetrieveWindowContent()629     public boolean getCanRetrieveWindowContent() {
630         return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
631     }
632 
633     /**
634      * Returns the bit mask of capabilities this accessibility service has such as
635      * being able to retrieve the active window content, etc.
636      *
637      * @return The capability bit mask.
638      *
639      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
640      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
641      * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
642      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
643      * @see #CAPABILITY_CAN_PERFORM_GESTURES
644      */
getCapabilities()645     public int getCapabilities() {
646         return mCapabilities;
647     }
648 
649     /**
650      * Sets the bit mask of capabilities this accessibility service has such as
651      * being able to retrieve the active window content, etc.
652      *
653      * @param capabilities The capability bit mask.
654      *
655      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
656      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
657      * @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
658      * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
659      * @see #CAPABILITY_CAN_PERFORM_GESTURES
660      *
661      * @hide
662      */
setCapabilities(int capabilities)663     public void setCapabilities(int capabilities) {
664         mCapabilities = capabilities;
665     }
666 
667     /**
668      * The localized summary of the accessibility service.
669      * <p>
670      *    <strong>Statically set from
671      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
672      * </p>
673      * @return The localized summary if available, and {@code null} if a summary
674      * has not been provided.
675      */
loadSummary(PackageManager packageManager)676     public CharSequence loadSummary(PackageManager packageManager) {
677         if (mSummaryResId == 0) {
678             return mNonLocalizedSummary;
679         }
680         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
681         CharSequence summary = packageManager.getText(serviceInfo.packageName,
682                 mSummaryResId, serviceInfo.applicationInfo);
683         if (summary != null) {
684             return summary.toString().trim();
685         }
686         return null;
687     }
688 
689     /**
690      * Gets the non-localized description of the accessibility service.
691      * <p>
692      *    <strong>Statically set from
693      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
694      * </p>
695      * @return The description.
696      *
697      * @deprecated Use {@link #loadDescription(PackageManager)}.
698      */
getDescription()699     public String getDescription() {
700         return mNonLocalizedDescription;
701     }
702 
703     /**
704      * The localized description of the accessibility service.
705      * <p>
706      *    <strong>Statically set from
707      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
708      * </p>
709      * @return The localized description.
710      */
loadDescription(PackageManager packageManager)711     public String loadDescription(PackageManager packageManager) {
712         if (mDescriptionResId == 0) {
713             return mNonLocalizedDescription;
714         }
715         ServiceInfo serviceInfo = mResolveInfo.serviceInfo;
716         CharSequence description = packageManager.getText(serviceInfo.packageName,
717                 mDescriptionResId, serviceInfo.applicationInfo);
718         if (description != null) {
719             return description.toString().trim();
720         }
721         return null;
722     }
723 
724     /** {@hide} */
isDirectBootAware()725     public boolean isDirectBootAware() {
726         return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
727                 || mResolveInfo.serviceInfo.directBootAware;
728     }
729 
730     /**
731      * {@inheritDoc}
732      */
describeContents()733     public int describeContents() {
734         return 0;
735     }
736 
writeToParcel(Parcel parcel, int flagz)737     public void writeToParcel(Parcel parcel, int flagz) {
738         parcel.writeInt(eventTypes);
739         parcel.writeStringArray(packageNames);
740         parcel.writeInt(feedbackType);
741         parcel.writeLong(notificationTimeout);
742         parcel.writeInt(flags);
743         parcel.writeParcelable(mComponentName, flagz);
744         parcel.writeParcelable(mResolveInfo, 0);
745         parcel.writeString(mSettingsActivityName);
746         parcel.writeInt(mCapabilities);
747         parcel.writeInt(mSummaryResId);
748         parcel.writeString(mNonLocalizedSummary);
749         parcel.writeInt(mDescriptionResId);
750         parcel.writeString(mNonLocalizedDescription);
751     }
752 
initFromParcel(Parcel parcel)753     private void initFromParcel(Parcel parcel) {
754         eventTypes = parcel.readInt();
755         packageNames = parcel.readStringArray();
756         feedbackType = parcel.readInt();
757         notificationTimeout = parcel.readLong();
758         flags = parcel.readInt();
759         mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
760         mResolveInfo = parcel.readParcelable(null);
761         mSettingsActivityName = parcel.readString();
762         mCapabilities = parcel.readInt();
763         mSummaryResId = parcel.readInt();
764         mNonLocalizedSummary = parcel.readString();
765         mDescriptionResId = parcel.readInt();
766         mNonLocalizedDescription = parcel.readString();
767     }
768 
769     @Override
hashCode()770     public int hashCode() {
771         return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
772     }
773 
774     @Override
equals(Object obj)775     public boolean equals(Object obj) {
776         if (this == obj) {
777             return true;
778         }
779         if (obj == null) {
780             return false;
781         }
782         if (getClass() != obj.getClass()) {
783             return false;
784         }
785         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
786         if (mComponentName == null) {
787             if (other.mComponentName != null) {
788                 return false;
789             }
790         } else if (!mComponentName.equals(other.mComponentName)) {
791             return false;
792         }
793         return true;
794     }
795 
796     @Override
toString()797     public String toString() {
798         StringBuilder stringBuilder = new StringBuilder();
799         appendEventTypes(stringBuilder, eventTypes);
800         stringBuilder.append(", ");
801         appendPackageNames(stringBuilder, packageNames);
802         stringBuilder.append(", ");
803         appendFeedbackTypes(stringBuilder, feedbackType);
804         stringBuilder.append(", ");
805         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
806         stringBuilder.append(", ");
807         appendFlags(stringBuilder, flags);
808         stringBuilder.append(", ");
809         stringBuilder.append("id: ").append(getId());
810         stringBuilder.append(", ");
811         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
812         stringBuilder.append(", ");
813         stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName);
814         stringBuilder.append(", ");
815         stringBuilder.append("summary: ").append(mNonLocalizedSummary);
816         stringBuilder.append(", ");
817         appendCapabilities(stringBuilder, mCapabilities);
818         return stringBuilder.toString();
819     }
820 
appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes)821     private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) {
822         stringBuilder.append("feedbackTypes:");
823         stringBuilder.append("[");
824         while (feedbackTypes != 0) {
825             final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes));
826             stringBuilder.append(feedbackTypeToString(feedbackTypeBit));
827             feedbackTypes &= ~feedbackTypeBit;
828             if (feedbackTypes != 0) {
829                 stringBuilder.append(", ");
830             }
831         }
832         stringBuilder.append("]");
833     }
834 
appendPackageNames(StringBuilder stringBuilder, String[] packageNames)835     private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) {
836         stringBuilder.append("packageNames:");
837         stringBuilder.append("[");
838         if (packageNames != null) {
839             final int packageNameCount = packageNames.length;
840             for (int i = 0; i < packageNameCount; i++) {
841                 stringBuilder.append(packageNames[i]);
842                 if (i < packageNameCount - 1) {
843                     stringBuilder.append(", ");
844                 }
845             }
846         }
847         stringBuilder.append("]");
848     }
849 
appendEventTypes(StringBuilder stringBuilder, int eventTypes)850     private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) {
851         stringBuilder.append("eventTypes:");
852         stringBuilder.append("[");
853         while (eventTypes != 0) {
854             final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes));
855             stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit));
856             eventTypes &= ~eventTypeBit;
857             if (eventTypes != 0) {
858                 stringBuilder.append(", ");
859             }
860         }
861         stringBuilder.append("]");
862     }
863 
appendFlags(StringBuilder stringBuilder, int flags)864     private static void appendFlags(StringBuilder stringBuilder, int flags) {
865         stringBuilder.append("flags:");
866         stringBuilder.append("[");
867         while (flags != 0) {
868             final int flagBit = (1 << Integer.numberOfTrailingZeros(flags));
869             stringBuilder.append(flagToString(flagBit));
870             flags &= ~flagBit;
871             if (flags != 0) {
872                 stringBuilder.append(", ");
873             }
874         }
875         stringBuilder.append("]");
876     }
877 
appendCapabilities(StringBuilder stringBuilder, int capabilities)878     private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) {
879         stringBuilder.append("capabilities:");
880         stringBuilder.append("[");
881         while (capabilities != 0) {
882             final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities));
883             stringBuilder.append(capabilityToString(capabilityBit));
884             capabilities &= ~capabilityBit;
885             if (capabilities != 0) {
886                 stringBuilder.append(", ");
887             }
888         }
889         stringBuilder.append("]");
890     }
891 
892     /**
893      * Returns the string representation of a feedback type. For example,
894      * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN.
895      *
896      * @param feedbackType The feedback type.
897      * @return The string representation.
898      */
feedbackTypeToString(int feedbackType)899     public static String feedbackTypeToString(int feedbackType) {
900         StringBuilder builder = new StringBuilder();
901         builder.append("[");
902         while (feedbackType != 0) {
903             final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
904             feedbackType &= ~feedbackTypeFlag;
905             switch (feedbackTypeFlag) {
906                 case FEEDBACK_AUDIBLE:
907                     if (builder.length() > 1) {
908                         builder.append(", ");
909                     }
910                     builder.append("FEEDBACK_AUDIBLE");
911                     break;
912                 case FEEDBACK_HAPTIC:
913                     if (builder.length() > 1) {
914                         builder.append(", ");
915                     }
916                     builder.append("FEEDBACK_HAPTIC");
917                     break;
918                 case FEEDBACK_GENERIC:
919                     if (builder.length() > 1) {
920                         builder.append(", ");
921                     }
922                     builder.append("FEEDBACK_GENERIC");
923                     break;
924                 case FEEDBACK_SPOKEN:
925                     if (builder.length() > 1) {
926                         builder.append(", ");
927                     }
928                     builder.append("FEEDBACK_SPOKEN");
929                     break;
930                 case FEEDBACK_VISUAL:
931                     if (builder.length() > 1) {
932                         builder.append(", ");
933                     }
934                     builder.append("FEEDBACK_VISUAL");
935                     break;
936                 case FEEDBACK_BRAILLE:
937                     if (builder.length() > 1) {
938                         builder.append(", ");
939                     }
940                     builder.append("FEEDBACK_BRAILLE");
941                     break;
942             }
943         }
944         builder.append("]");
945         return builder.toString();
946     }
947 
948     /**
949      * Returns the string representation of a flag. For example,
950      * {@link #DEFAULT} is represented by the string DEFAULT.
951      *
952      * @param flag The flag.
953      * @return The string representation.
954      */
flagToString(int flag)955     public static String flagToString(int flag) {
956         switch (flag) {
957             case DEFAULT:
958                 return "DEFAULT";
959             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
960                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
961             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
962                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
963             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
964                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
965             case FLAG_REPORT_VIEW_IDS:
966                 return "FLAG_REPORT_VIEW_IDS";
967             case FLAG_REQUEST_FILTER_KEY_EVENTS:
968                 return "FLAG_REQUEST_FILTER_KEY_EVENTS";
969             case FLAG_RETRIEVE_INTERACTIVE_WINDOWS:
970                 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS";
971             case FLAG_ENABLE_ACCESSIBILITY_VOLUME:
972                 return "FLAG_ENABLE_ACCESSIBILITY_VOLUME";
973             case FLAG_REQUEST_ACCESSIBILITY_BUTTON:
974                 return "FLAG_REQUEST_ACCESSIBILITY_BUTTON";
975             case FLAG_REQUEST_FINGERPRINT_GESTURES:
976                 return "FLAG_REQUEST_FINGERPRINT_GESTURES";
977             default:
978                 return null;
979         }
980     }
981 
982     /**
983      * Returns the string representation of a capability. For example,
984      * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
985      * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
986      *
987      * @param capability The capability.
988      * @return The string representation.
989      */
capabilityToString(int capability)990     public static String capabilityToString(int capability) {
991         switch (capability) {
992             case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
993                 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
994             case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
995                 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
996             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
997                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
998             case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS:
999                 return "CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS";
1000             case CAPABILITY_CAN_CONTROL_MAGNIFICATION:
1001                 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION";
1002             case CAPABILITY_CAN_PERFORM_GESTURES:
1003                 return "CAPABILITY_CAN_PERFORM_GESTURES";
1004             case CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES:
1005                 return "CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES";
1006             default:
1007                 return "UNKNOWN";
1008         }
1009     }
1010 
1011     /**
1012      * @hide
1013      * @return The list of {@link CapabilityInfo} objects.
1014      * @deprecated The version that takes a context works better.
1015      */
getCapabilityInfos()1016     public List<CapabilityInfo> getCapabilityInfos() {
1017         return getCapabilityInfos(null);
1018     }
1019 
1020     /**
1021      * @hide
1022      * @param context A valid context
1023      * @return The list of {@link CapabilityInfo} objects.
1024      */
getCapabilityInfos(Context context)1025     public List<CapabilityInfo> getCapabilityInfos(Context context) {
1026         if (mCapabilities == 0) {
1027             return Collections.emptyList();
1028         }
1029         int capabilities = mCapabilities;
1030         List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>();
1031         SparseArray<CapabilityInfo> capabilityInfoSparseArray =
1032                 getCapabilityInfoSparseArray(context);
1033         while (capabilities != 0) {
1034             final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities);
1035             capabilities &= ~capabilityBit;
1036             CapabilityInfo capabilityInfo = capabilityInfoSparseArray.get(capabilityBit);
1037             if (capabilityInfo != null) {
1038                 capabilityInfos.add(capabilityInfo);
1039             }
1040         }
1041         return capabilityInfos;
1042     }
1043 
getCapabilityInfoSparseArray(Context context)1044     private static SparseArray<CapabilityInfo> getCapabilityInfoSparseArray(Context context) {
1045         if (sAvailableCapabilityInfos == null) {
1046             sAvailableCapabilityInfos = new SparseArray<CapabilityInfo>();
1047             sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
1048                     new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT,
1049                             R.string.capability_title_canRetrieveWindowContent,
1050                             R.string.capability_desc_canRetrieveWindowContent));
1051             sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
1052                     new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
1053                             R.string.capability_title_canRequestTouchExploration,
1054                             R.string.capability_desc_canRequestTouchExploration));
1055             sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
1056                     new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
1057                             R.string.capability_title_canRequestFilterKeyEvents,
1058                             R.string.capability_desc_canRequestFilterKeyEvents));
1059             sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
1060                     new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION,
1061                             R.string.capability_title_canControlMagnification,
1062                             R.string.capability_desc_canControlMagnification));
1063             sAvailableCapabilityInfos.put(CAPABILITY_CAN_PERFORM_GESTURES,
1064                     new CapabilityInfo(CAPABILITY_CAN_PERFORM_GESTURES,
1065                             R.string.capability_title_canPerformGestures,
1066                             R.string.capability_desc_canPerformGestures));
1067             if ((context == null) || fingerprintAvailable(context)) {
1068                 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES,
1069                         new CapabilityInfo(CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES,
1070                                 R.string.capability_title_canCaptureFingerprintGestures,
1071                                 R.string.capability_desc_canCaptureFingerprintGestures));
1072             }
1073         }
1074         return sAvailableCapabilityInfos;
1075     }
1076 
fingerprintAvailable(Context context)1077     private static boolean fingerprintAvailable(Context context) {
1078         return context.getPackageManager().hasSystemFeature(FEATURE_FINGERPRINT)
1079                 && context.getSystemService(FingerprintManager.class).isHardwareDetected();
1080     }
1081     /**
1082      * @hide
1083      */
1084     public static final class CapabilityInfo {
1085         public final int capability;
1086         public final int titleResId;
1087         public final int descResId;
1088 
CapabilityInfo(int capability, int titleResId, int descResId)1089         public CapabilityInfo(int capability, int titleResId, int descResId) {
1090             this.capability = capability;
1091             this.titleResId = titleResId;
1092             this.descResId = descResId;
1093         }
1094     }
1095 
1096     /**
1097      * @see Parcelable.Creator
1098      */
1099     public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR =
1100             new Parcelable.Creator<AccessibilityServiceInfo>() {
1101         public AccessibilityServiceInfo createFromParcel(Parcel parcel) {
1102             AccessibilityServiceInfo info = new AccessibilityServiceInfo();
1103             info.initFromParcel(parcel);
1104             return info;
1105         }
1106 
1107         public AccessibilityServiceInfo[] newArray(int size) {
1108             return new AccessibilityServiceInfo[size];
1109         }
1110     };
1111 }
1112