AccessibilityServiceInfo.java revision 8a372a0a280127743ce9a7ce4b6198c7a02d2a4f
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 17package android.accessibilityservice; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.pm.PackageManager; 22import android.content.pm.PackageManager.NameNotFoundException; 23import android.content.pm.ResolveInfo; 24import android.content.pm.ServiceInfo; 25import android.content.res.Resources; 26import android.content.res.TypedArray; 27import android.content.res.XmlResourceParser; 28import android.os.Build; 29import android.os.Parcel; 30import android.os.Parcelable; 31import android.util.AttributeSet; 32import android.util.SparseArray; 33import android.util.TypedValue; 34import android.util.Xml; 35import android.view.View; 36import android.view.accessibility.AccessibilityEvent; 37import android.view.accessibility.AccessibilityNodeInfo; 38 39import org.xmlpull.v1.XmlPullParser; 40import org.xmlpull.v1.XmlPullParserException; 41 42import com.android.internal.R; 43 44import java.io.IOException; 45import java.util.ArrayList; 46import java.util.Collections; 47import 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 */ 77public 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 { 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)); 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)); 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)); 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)); 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)); 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 /** 323 * The event types an {@link AccessibilityService} is interested in. 324 * <p> 325 * <strong>Can be dynamically set at runtime.</strong> 326 * </p> 327 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED 328 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED 329 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED 330 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED 331 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED 332 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 333 * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED 334 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START 335 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END 336 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER 337 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT 338 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED 339 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED 340 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED 341 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START 342 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END 343 * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT 344 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START 345 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END 346 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED 347 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 348 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 349 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED 350 */ 351 public int eventTypes; 352 353 /** 354 * The package names an {@link AccessibilityService} is interested in. Setting 355 * to <code>null</code> is equivalent to all packages. 356 * <p> 357 * <strong>Can be dynamically set at runtime.</strong> 358 * </p> 359 */ 360 public String[] packageNames; 361 362 /** 363 * The feedback type an {@link AccessibilityService} provides. 364 * <p> 365 * <strong>Can be dynamically set at runtime.</strong> 366 * </p> 367 * @see #FEEDBACK_AUDIBLE 368 * @see #FEEDBACK_GENERIC 369 * @see #FEEDBACK_HAPTIC 370 * @see #FEEDBACK_SPOKEN 371 * @see #FEEDBACK_VISUAL 372 * @see #FEEDBACK_BRAILLE 373 */ 374 public int feedbackType; 375 376 /** 377 * The timeout after the most recent event of a given type before an 378 * {@link AccessibilityService} is notified. 379 * <p> 380 * <strong>Can be dynamically set at runtime.</strong>. 381 * </p> 382 * <p> 383 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 384 * events to the client too frequently since this is accomplished via an expensive 385 * interprocess call. One can think of the timeout as a criteria to determine when 386 * event generation has settled down. 387 */ 388 public long notificationTimeout; 389 390 /** 391 * This field represents a set of flags used for configuring an 392 * {@link AccessibilityService}. 393 * <p> 394 * <strong>Can be dynamically set at runtime.</strong> 395 * </p> 396 * @see #DEFAULT 397 * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 398 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 399 * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY 400 * @see #FLAG_REQUEST_FILTER_KEY_EVENTS 401 * @see #FLAG_REPORT_VIEW_IDS 402 * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS 403 */ 404 public int flags; 405 406 /** 407 * The unique string Id to identify the accessibility service. 408 */ 409 private String mId; 410 411 /** 412 * The Service that implements this accessibility service component. 413 */ 414 private ResolveInfo mResolveInfo; 415 416 /** 417 * The accessibility service setting activity's name, used by the system 418 * settings to launch the setting activity of this accessibility service. 419 */ 420 private String mSettingsActivityName; 421 422 /** 423 * Bit mask with capabilities of this service. 424 */ 425 private int mCapabilities; 426 427 /** 428 * Resource id of the description of the accessibility service. 429 */ 430 private int mDescriptionResId; 431 432 /** 433 * Non localized description of the accessibility service. 434 */ 435 private String mNonLocalizedDescription; 436 437 /** 438 * Creates a new instance. 439 */ 440 public AccessibilityServiceInfo() { 441 /* do nothing */ 442 } 443 444 /** 445 * Creates a new instance. 446 * 447 * @param resolveInfo The service resolve info. 448 * @param context Context for accessing resources. 449 * @throws XmlPullParserException If a XML parsing error occurs. 450 * @throws IOException If a XML parsing error occurs. 451 * 452 * @hide 453 */ 454 public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context) 455 throws XmlPullParserException, IOException { 456 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 457 mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString(); 458 mResolveInfo = resolveInfo; 459 460 XmlResourceParser parser = null; 461 462 try { 463 PackageManager packageManager = context.getPackageManager(); 464 parser = serviceInfo.loadXmlMetaData(packageManager, 465 AccessibilityService.SERVICE_META_DATA); 466 if (parser == null) { 467 return; 468 } 469 470 int type = 0; 471 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 472 type = parser.next(); 473 } 474 475 String nodeName = parser.getName(); 476 if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) { 477 throw new XmlPullParserException( "Meta-data does not start with" 478 + TAG_ACCESSIBILITY_SERVICE + " tag"); 479 } 480 481 AttributeSet allAttributes = Xml.asAttributeSet(parser); 482 Resources resources = packageManager.getResourcesForApplication( 483 serviceInfo.applicationInfo); 484 TypedArray asAttributes = resources.obtainAttributes(allAttributes, 485 com.android.internal.R.styleable.AccessibilityService); 486 eventTypes = asAttributes.getInt( 487 com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes, 488 0); 489 String packageNamez = asAttributes.getString( 490 com.android.internal.R.styleable.AccessibilityService_packageNames); 491 if (packageNamez != null) { 492 packageNames = packageNamez.split("(\\s)*,(\\s)*"); 493 } 494 feedbackType = asAttributes.getInt( 495 com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType, 496 0); 497 notificationTimeout = asAttributes.getInt( 498 com.android.internal.R.styleable.AccessibilityService_notificationTimeout, 499 0); 500 flags = asAttributes.getInt( 501 com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); 502 mSettingsActivityName = asAttributes.getString( 503 com.android.internal.R.styleable.AccessibilityService_settingsActivity); 504 if (asAttributes.getBoolean(com.android.internal.R.styleable 505 .AccessibilityService_canRetrieveWindowContent, false)) { 506 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; 507 } 508 if (asAttributes.getBoolean(com.android.internal.R.styleable 509 .AccessibilityService_canRequestTouchExplorationMode, false)) { 510 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; 511 } 512 if (asAttributes.getBoolean(com.android.internal.R.styleable 513 .AccessibilityService_canRequestEnhancedWebAccessibility, false)) { 514 mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY; 515 } 516 if (asAttributes.getBoolean(com.android.internal.R.styleable 517 .AccessibilityService_canRequestFilterKeyEvents, false)) { 518 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; 519 } 520 if (asAttributes.getBoolean(com.android.internal.R.styleable 521 .AccessibilityService_canControlMagnification, false)) { 522 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION; 523 } 524 if (asAttributes.getBoolean(com.android.internal.R.styleable 525 .AccessibilityService_canPerformGestures, false)) { 526 mCapabilities |= CAPABILITY_CAN_PERFORM_GESTURES; 527 } 528 TypedValue peekedValue = asAttributes.peekValue( 529 com.android.internal.R.styleable.AccessibilityService_description); 530 if (peekedValue != null) { 531 mDescriptionResId = peekedValue.resourceId; 532 CharSequence nonLocalizedDescription = peekedValue.coerceToString(); 533 if (nonLocalizedDescription != null) { 534 mNonLocalizedDescription = nonLocalizedDescription.toString().trim(); 535 } 536 } 537 asAttributes.recycle(); 538 } catch (NameNotFoundException e) { 539 throw new XmlPullParserException( "Unable to create context for: " 540 + serviceInfo.packageName); 541 } finally { 542 if (parser != null) { 543 parser.close(); 544 } 545 } 546 } 547 548 /** 549 * Updates the properties that an AccessibilitySerivice can change dynamically. 550 * 551 * @param other The info from which to update the properties. 552 * 553 * @hide 554 */ 555 public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) { 556 eventTypes = other.eventTypes; 557 packageNames = other.packageNames; 558 feedbackType = other.feedbackType; 559 notificationTimeout = other.notificationTimeout; 560 flags = other.flags; 561 } 562 563 /** 564 * @hide 565 */ 566 public void setComponentName(ComponentName component) { 567 mId = component.flattenToShortString(); 568 } 569 570 /** 571 * The accessibility service id. 572 * <p> 573 * <strong>Generated by the system.</strong> 574 * </p> 575 * @return The id. 576 */ 577 public String getId() { 578 return mId; 579 } 580 581 /** 582 * The service {@link ResolveInfo}. 583 * <p> 584 * <strong>Generated by the system.</strong> 585 * </p> 586 * @return The info. 587 */ 588 public ResolveInfo getResolveInfo() { 589 return mResolveInfo; 590 } 591 592 /** 593 * The settings activity name. 594 * <p> 595 * <strong>Statically set from 596 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 597 * </p> 598 * @return The settings activity name. 599 */ 600 public String getSettingsActivityName() { 601 return mSettingsActivityName; 602 } 603 604 /** 605 * Whether this service can retrieve the current window's content. 606 * <p> 607 * <strong>Statically set from 608 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 609 * </p> 610 * @return True if window content can be retrieved. 611 * 612 * @deprecated Use {@link #getCapabilities()}. 613 */ 614 public boolean getCanRetrieveWindowContent() { 615 return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 616 } 617 618 /** 619 * Returns the bit mask of capabilities this accessibility service has such as 620 * being able to retrieve the active window content, etc. 621 * 622 * @return The capability bit mask. 623 * 624 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 625 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 626 * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY 627 * @see #CAPABILITY_FILTER_KEY_EVENTS 628 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 629 * @see #CAPABILITY_CAN_PERFORM_GESTURES 630 */ 631 public int getCapabilities() { 632 return mCapabilities; 633 } 634 635 /** 636 * Sets the bit mask of capabilities this accessibility service has such as 637 * being able to retrieve the active window content, etc. 638 * 639 * @param capabilities The capability bit mask. 640 * 641 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 642 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 643 * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY 644 * @see #CAPABILITY_FILTER_KEY_EVENTS 645 * @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION 646 * @see #CAPABILITY_CAN_PERFORM_GESTURES 647 * 648 * @hide 649 */ 650 public void setCapabilities(int capabilities) { 651 mCapabilities = capabilities; 652 } 653 654 /** 655 * Gets the non-localized description of the accessibility service. 656 * <p> 657 * <strong>Statically set from 658 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 659 * </p> 660 * @return The description. 661 * 662 * @deprecated Use {@link #loadDescription(PackageManager)}. 663 */ 664 public String getDescription() { 665 return mNonLocalizedDescription; 666 } 667 668 /** 669 * The localized description of the accessibility service. 670 * <p> 671 * <strong>Statically set from 672 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 673 * </p> 674 * @return The localized description. 675 */ 676 public String loadDescription(PackageManager packageManager) { 677 if (mDescriptionResId == 0) { 678 return mNonLocalizedDescription; 679 } 680 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 681 CharSequence description = packageManager.getText(serviceInfo.packageName, 682 mDescriptionResId, serviceInfo.applicationInfo); 683 if (description != null) { 684 return description.toString().trim(); 685 } 686 return null; 687 } 688 689 /** {@hide} */ 690 public boolean isEncryptionAware() { 691 return mResolveInfo.serviceInfo.directBootAware; 692 } 693 694 /** 695 * {@inheritDoc} 696 */ 697 public int describeContents() { 698 return 0; 699 } 700 701 public void writeToParcel(Parcel parcel, int flagz) { 702 parcel.writeInt(eventTypes); 703 parcel.writeStringArray(packageNames); 704 parcel.writeInt(feedbackType); 705 parcel.writeLong(notificationTimeout); 706 parcel.writeInt(flags); 707 parcel.writeString(mId); 708 parcel.writeParcelable(mResolveInfo, 0); 709 parcel.writeString(mSettingsActivityName); 710 parcel.writeInt(mCapabilities); 711 parcel.writeInt(mDescriptionResId); 712 parcel.writeString(mNonLocalizedDescription); 713 } 714 715 private void initFromParcel(Parcel parcel) { 716 eventTypes = parcel.readInt(); 717 packageNames = parcel.readStringArray(); 718 feedbackType = parcel.readInt(); 719 notificationTimeout = parcel.readLong(); 720 flags = parcel.readInt(); 721 mId = parcel.readString(); 722 mResolveInfo = parcel.readParcelable(null); 723 mSettingsActivityName = parcel.readString(); 724 mCapabilities = parcel.readInt(); 725 mDescriptionResId = parcel.readInt(); 726 mNonLocalizedDescription = parcel.readString(); 727 } 728 729 @Override 730 public int hashCode() { 731 return 31 * 1 + ((mId == null) ? 0 : mId.hashCode()); 732 } 733 734 @Override 735 public boolean equals(Object obj) { 736 if (this == obj) { 737 return true; 738 } 739 if (obj == null) { 740 return false; 741 } 742 if (getClass() != obj.getClass()) { 743 return false; 744 } 745 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 746 if (mId == null) { 747 if (other.mId != null) { 748 return false; 749 } 750 } else if (!mId.equals(other.mId)) { 751 return false; 752 } 753 return true; 754 } 755 756 @Override 757 public String toString() { 758 StringBuilder stringBuilder = new StringBuilder(); 759 appendEventTypes(stringBuilder, eventTypes); 760 stringBuilder.append(", "); 761 appendPackageNames(stringBuilder, packageNames); 762 stringBuilder.append(", "); 763 appendFeedbackTypes(stringBuilder, feedbackType); 764 stringBuilder.append(", "); 765 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 766 stringBuilder.append(", "); 767 appendFlags(stringBuilder, flags); 768 stringBuilder.append(", "); 769 stringBuilder.append("id: ").append(mId); 770 stringBuilder.append(", "); 771 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 772 stringBuilder.append(", "); 773 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 774 stringBuilder.append(", "); 775 appendCapabilities(stringBuilder, mCapabilities); 776 return stringBuilder.toString(); 777 } 778 779 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 780 stringBuilder.append("feedbackTypes:"); 781 stringBuilder.append("["); 782 while (feedbackTypes != 0) { 783 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 784 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 785 feedbackTypes &= ~feedbackTypeBit; 786 if (feedbackTypes != 0) { 787 stringBuilder.append(", "); 788 } 789 } 790 stringBuilder.append("]"); 791 } 792 793 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 794 stringBuilder.append("packageNames:"); 795 stringBuilder.append("["); 796 if (packageNames != null) { 797 final int packageNameCount = packageNames.length; 798 for (int i = 0; i < packageNameCount; i++) { 799 stringBuilder.append(packageNames[i]); 800 if (i < packageNameCount - 1) { 801 stringBuilder.append(", "); 802 } 803 } 804 } 805 stringBuilder.append("]"); 806 } 807 808 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 809 stringBuilder.append("eventTypes:"); 810 stringBuilder.append("["); 811 while (eventTypes != 0) { 812 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 813 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 814 eventTypes &= ~eventTypeBit; 815 if (eventTypes != 0) { 816 stringBuilder.append(", "); 817 } 818 } 819 stringBuilder.append("]"); 820 } 821 822 private static void appendFlags(StringBuilder stringBuilder, int flags) { 823 stringBuilder.append("flags:"); 824 stringBuilder.append("["); 825 while (flags != 0) { 826 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 827 stringBuilder.append(flagToString(flagBit)); 828 flags &= ~flagBit; 829 if (flags != 0) { 830 stringBuilder.append(", "); 831 } 832 } 833 stringBuilder.append("]"); 834 } 835 836 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 837 stringBuilder.append("capabilities:"); 838 stringBuilder.append("["); 839 while (capabilities != 0) { 840 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 841 stringBuilder.append(capabilityToString(capabilityBit)); 842 capabilities &= ~capabilityBit; 843 if (capabilities != 0) { 844 stringBuilder.append(", "); 845 } 846 } 847 stringBuilder.append("]"); 848 } 849 850 /** 851 * Returns the string representation of a feedback type. For example, 852 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 853 * 854 * @param feedbackType The feedback type. 855 * @return The string representation. 856 */ 857 public static String feedbackTypeToString(int feedbackType) { 858 StringBuilder builder = new StringBuilder(); 859 builder.append("["); 860 while (feedbackType != 0) { 861 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 862 feedbackType &= ~feedbackTypeFlag; 863 switch (feedbackTypeFlag) { 864 case FEEDBACK_AUDIBLE: 865 if (builder.length() > 1) { 866 builder.append(", "); 867 } 868 builder.append("FEEDBACK_AUDIBLE"); 869 break; 870 case FEEDBACK_HAPTIC: 871 if (builder.length() > 1) { 872 builder.append(", "); 873 } 874 builder.append("FEEDBACK_HAPTIC"); 875 break; 876 case FEEDBACK_GENERIC: 877 if (builder.length() > 1) { 878 builder.append(", "); 879 } 880 builder.append("FEEDBACK_GENERIC"); 881 break; 882 case FEEDBACK_SPOKEN: 883 if (builder.length() > 1) { 884 builder.append(", "); 885 } 886 builder.append("FEEDBACK_SPOKEN"); 887 break; 888 case FEEDBACK_VISUAL: 889 if (builder.length() > 1) { 890 builder.append(", "); 891 } 892 builder.append("FEEDBACK_VISUAL"); 893 break; 894 case FEEDBACK_BRAILLE: 895 if (builder.length() > 1) { 896 builder.append(", "); 897 } 898 builder.append("FEEDBACK_BRAILLE"); 899 break; 900 } 901 } 902 builder.append("]"); 903 return builder.toString(); 904 } 905 906 /** 907 * Returns the string representation of a flag. For example, 908 * {@link #DEFAULT} is represented by the string DEFAULT. 909 * 910 * @param flag The flag. 911 * @return The string representation. 912 */ 913 public static String flagToString(int flag) { 914 switch (flag) { 915 case DEFAULT: 916 return "DEFAULT"; 917 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 918 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 919 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 920 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 921 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 922 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 923 case FLAG_REPORT_VIEW_IDS: 924 return "FLAG_REPORT_VIEW_IDS"; 925 case FLAG_REQUEST_FILTER_KEY_EVENTS: 926 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 927 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 928 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 929 default: 930 return null; 931 } 932 } 933 934 /** 935 * Returns the string representation of a capability. For example, 936 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 937 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 938 * 939 * @param capability The capability. 940 * @return The string representation. 941 */ 942 public static String capabilityToString(int capability) { 943 switch (capability) { 944 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 945 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 946 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 947 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 948 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 949 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 950 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 951 return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; 952 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 953 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 954 case CAPABILITY_CAN_PERFORM_GESTURES: 955 return "CAPABILITY_CAN_PERFORM_GESTURES"; 956 default: 957 return "UNKNOWN"; 958 } 959 } 960 961 /** 962 * @hide 963 * @return The list of {@link CapabilityInfo} objects. 964 */ 965 public List<CapabilityInfo> getCapabilityInfos() { 966 if (mCapabilities == 0) { 967 return Collections.emptyList(); 968 } 969 int capabilities = mCapabilities; 970 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 971 while (capabilities != 0) { 972 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 973 capabilities &= ~capabilityBit; 974 CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit); 975 if (capabilityInfo != null) { 976 capabilityInfos.add(capabilityInfo); 977 } 978 } 979 return capabilityInfos; 980 } 981 982 /** 983 * @hide 984 */ 985 public static final class CapabilityInfo { 986 public final int capability; 987 public final int titleResId; 988 public final int descResId; 989 990 public CapabilityInfo(int capability, int titleResId, int descResId) { 991 this.capability = capability; 992 this.titleResId = titleResId; 993 this.descResId = descResId; 994 } 995 } 996 997 /** 998 * @see Parcelable.Creator 999 */ 1000 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 1001 new Parcelable.Creator<AccessibilityServiceInfo>() { 1002 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 1003 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 1004 info.initFromParcel(parcel); 1005 return info; 1006 } 1007 1008 public AccessibilityServiceInfo[] newArray(int size) { 1009 return new AccessibilityServiceInfo[size]; 1010 } 1011 }; 1012} 1013