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