1 /*
2  * Copyright (C) 2011 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 androidx.core.accessibilityservice;
18 
19 import android.accessibilityservice.AccessibilityService;
20 import android.accessibilityservice.AccessibilityServiceInfo;
21 import android.content.pm.PackageManager;
22 import android.os.Build;
23 import android.view.View;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 
28 /**
29  * Helper for accessing features in {@link AccessibilityServiceInfo}.
30  */
31 public final class AccessibilityServiceInfoCompat {
32     /**
33      * Capability: This accessibility service can retrieve the active window content.
34      */
35     public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 0x00000001;
36 
37     /**
38      * Capability: This accessibility service can request touch exploration mode in which
39      * touched items are spoken aloud and the UI can be explored via gestures.
40      */
41     public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
42 
43     /**
44      * Capability: This accessibility service can request enhanced web accessibility
45      * enhancements. For example, installing scripts to make app content more accessible.
46      */
47     public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
48 
49     /**
50      * Capability: This accessibility service can filter the key event stream.
51      */
52     public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 0x00000008;
53 
54     // Feedback types
55 
56     /**
57      * Denotes braille feedback.
58      */
59     public static final int FEEDBACK_BRAILLE = 0x0000020;
60 
61     /**
62      * Mask for all feedback types.
63      *
64      * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
65      * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
66      * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
67      * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
68      * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
69      * @see AccessibilityServiceInfo#FEEDBACK_BRAILLE
70      */
71     public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
72 
73     // Flags
74 
75     /**
76      * If this flag is set the system will regard views that are not important
77      * for accessibility in addition to the ones that are important for accessibility.
78      * That is, views that are marked as not important for accessibility via
79      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or
80      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are
81      * marked as potentially important for accessibility via
82      * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined
83      * that are not important for accessibility, are both reported while querying the
84      * window content and also the accessibility service will receive accessibility events
85      * from them.
86      * <p>
87      * <strong>Note:</strong> For accessibility services targeting API version
88      * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly
89      * set for the system to regard views that are not important for accessibility. For
90      * accessibility services targeting API version lower than
91      * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are
92      * regarded for accessibility purposes.
93      * </p>
94      * <p>
95      * Usually views not important for accessibility are layout managers that do not
96      * react to user actions, do not draw any content, and do not have any special
97      * semantics in the context of the screen content. For example, a three by three
98      * grid can be implemented as three horizontal linear layouts and one vertical,
99      * or three vertical linear layouts and one horizontal, or one grid layout, etc.
100      * In this context the actual layout mangers used to achieve the grid configuration
101      * are not important, rather it is important that there are nine evenly distributed
102      * elements.
103      * </p>
104      */
105     public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002;
106 
107     /**
108      * This flag requests that the system gets into touch exploration mode.
109      * In this mode a single finger moving on the screen behaves as a mouse
110      * pointer hovering over the user interface. The system will also detect
111      * certain gestures performed on the touch screen and notify this service.
112      * The system will enable touch exploration mode if there is at least one
113      * accessibility service that has this flag set. Hence, clearing this
114      * flag does not guarantee that the device will not be in touch exploration
115      * mode since there may be another enabled service that requested it.
116      * <p>
117      * For accessibility services targeting API version higher than
118      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set
119      * this flag have to declare this capability in their meta-data by setting
120      * the attribute canRequestTouchExplorationMode to true, otherwise this flag
121      * will be ignored. For how to declare the meta-data of a service refer to
122      * {@value AccessibilityService#SERVICE_META_DATA}.
123      * </p>
124      * <p>
125      * Services targeting API version equal to or lower than
126      * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e.
127      * the first time they are run, if this flag is specified, a dialog is
128      * shown to the user to confirm enabling explore by touch.
129      * </p>
130      */
131     public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
132 
133     /**
134      * This flag requests from the system to enable web accessibility enhancing
135      * extensions. Such extensions aim to provide improved accessibility support
136      * for content presented in a {@link android.webkit.WebView}. An example of such
137      * an extension is injecting JavaScript from a secure source. The system will enable
138      * enhanced web accessibility if there is at least one accessibility service
139      * that has this flag set. Hence, clearing this flag does not guarantee that the
140      * device will not have enhanced web accessibility enabled since there may be
141      * another enabled service that requested it.
142      * <p>
143      * Services that want to set this flag have to declare this capability
144      * in their meta-data by setting the attribute canRequestEnhancedWebAccessibility
145      * to true, otherwise this flag will be ignored. For how to declare the meta-data
146      * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
147      * </p>
148      */
149     public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
150 
151     /**
152      * This flag requests that the AccessibilityNodeInfos obtained
153      * by an {@link AccessibilityService} contain the id of the source view.
154      * The source view id will be a fully qualified resource name of the
155      * form "package:id/name", for example "foo.bar:id/my_list", and it is
156      * useful for UI test automation. This flag is not set by default.
157      */
158     public static final int FLAG_REPORT_VIEW_IDS = 0x00000010;
159 
160     /**
161      * This flag requests from the system to filter key events. If this flag
162      * is set the accessibility service will receive the key events before
163      * applications allowing it implement global shortcuts. Setting this flag
164      * does not guarantee that this service will filter key events since only
165      * one service can do so at any given time. This avoids user confusion due
166      * to behavior change in case different key filtering services are enabled.
167      * If there is already another key filtering service enabled, this one will
168      * not receive key events.
169      * <p>
170      * Services that want to set this flag have to declare this capability
171      * in their meta-data by setting the attribute canRequestFilterKeyEvents
172      * to true, otherwise this flag will be ignored. For how to declare the meta
173      * -data of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
174      * </p>
175      */
176     public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020;
177 
178     /*
179      * Hide constructor
180      */
AccessibilityServiceInfoCompat()181     private AccessibilityServiceInfoCompat() {}
182 
183     /**
184      * The localized description of the accessibility service.
185      * <p>
186      *    <strong>Statically set from
187      *    {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
188      * </p>
189      *
190      * @param info The service info of interest
191      * @param packageManager The current package manager
192      * @return The localized description.
193      */
194     @Nullable
loadDescription( @onNull AccessibilityServiceInfo info, @NonNull PackageManager packageManager)195     public static String loadDescription(
196             @NonNull AccessibilityServiceInfo info, @NonNull PackageManager packageManager) {
197         if (Build.VERSION.SDK_INT >= 16) {
198             return info.loadDescription(packageManager);
199         } else {
200             //noinspection deprecation
201             return info.getDescription();
202         }
203     }
204 
205     /**
206      * Returns the string representation of a feedback type. For example,
207      * {@link AccessibilityServiceInfo#FEEDBACK_SPOKEN} is represented by the
208      * string FEEDBACK_SPOKEN.
209      *
210      * @param feedbackType The feedback type.
211      * @return The string representation.
212      */
213     @NonNull
feedbackTypeToString(int feedbackType)214     public static String feedbackTypeToString(int feedbackType) {
215         StringBuilder builder = new StringBuilder();
216         builder.append("[");
217         while (feedbackType > 0) {
218             final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType);
219             feedbackType &= ~feedbackTypeFlag;
220             if (builder.length() > 1) {
221                 builder.append(", ");
222             }
223             switch (feedbackTypeFlag) {
224                 case AccessibilityServiceInfo.FEEDBACK_AUDIBLE:
225                     builder.append("FEEDBACK_AUDIBLE");
226                     break;
227                 case AccessibilityServiceInfo.FEEDBACK_HAPTIC:
228                     builder.append("FEEDBACK_HAPTIC");
229                     break;
230                 case AccessibilityServiceInfo.FEEDBACK_GENERIC:
231                     builder.append("FEEDBACK_GENERIC");
232                     break;
233                 case AccessibilityServiceInfo.FEEDBACK_SPOKEN:
234                     builder.append("FEEDBACK_SPOKEN");
235                     break;
236                 case AccessibilityServiceInfo.FEEDBACK_VISUAL:
237                     builder.append("FEEDBACK_VISUAL");
238                     break;
239             }
240         }
241         builder.append("]");
242         return builder.toString();
243     }
244 
245     /**
246      * Returns the string representation of a flag. For example,
247      * {@link AccessibilityServiceInfo#DEFAULT} is represented by the
248      * string DEFAULT.
249      *
250      * @param flag The flag.
251      * @return The string representation.
252      */
253     @Nullable
flagToString(int flag)254     public static String flagToString(int flag) {
255         switch (flag) {
256             case AccessibilityServiceInfo.DEFAULT:
257                 return "DEFAULT";
258             case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS:
259                 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS";
260             case FLAG_REQUEST_TOUCH_EXPLORATION_MODE:
261                 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE";
262             case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
263                 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
264             case FLAG_REPORT_VIEW_IDS:
265                 return "FLAG_REPORT_VIEW_IDS";
266             case FLAG_REQUEST_FILTER_KEY_EVENTS:
267                 return "FLAG_REQUEST_FILTER_KEY_EVENTS";
268             default:
269                 return null;
270         }
271     }
272 
273     /**
274      * Returns the bit mask of capabilities this accessibility service has such as
275      * being able to retrieve the active window content, etc.
276      *
277      * @param info The service info whose capabilities to get.
278      * @return The capability bit mask.
279      *
280      * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
281      * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
282      * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
283      * @see #CAPABILITY_CAN_FILTER_KEY_EVENTS
284      */
getCapabilities(@onNull AccessibilityServiceInfo info)285     public static int getCapabilities(@NonNull AccessibilityServiceInfo info) {
286         if (Build.VERSION.SDK_INT >= 18) {
287             return info.getCapabilities();
288         } else {
289             //noinspection deprecation
290             if (info.getCanRetrieveWindowContent()) {
291                 return CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT;
292             }
293             return 0;
294         }
295     }
296 
297     /**
298      * Returns the string representation of a capability. For example,
299      * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented
300      * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT.
301      *
302      * @param capability The capability.
303      * @return The string representation.
304      */
305     @NonNull
capabilityToString(int capability)306     public static String capabilityToString(int capability) {
307         switch (capability) {
308             case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT:
309                 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT";
310             case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION:
311                 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION";
312             case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY:
313                 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY";
314             case CAPABILITY_CAN_FILTER_KEY_EVENTS:
315                 return "CAPABILITY_CAN_FILTER_KEY_EVENTS";
316             default:
317                 return "UNKNOWN";
318         }
319     }
320 }
321