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