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