AccessibilityServiceInfo.java revision a6b64f5099b7be6e8384958d8bcddb97bb06ec93
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 /** 690 * {@inheritDoc} 691 */ 692 public int describeContents() { 693 return 0; 694 } 695 696 public void writeToParcel(Parcel parcel, int flagz) { 697 parcel.writeInt(eventTypes); 698 parcel.writeStringArray(packageNames); 699 parcel.writeInt(feedbackType); 700 parcel.writeLong(notificationTimeout); 701 parcel.writeInt(flags); 702 parcel.writeString(mId); 703 parcel.writeParcelable(mResolveInfo, 0); 704 parcel.writeString(mSettingsActivityName); 705 parcel.writeInt(mCapabilities); 706 parcel.writeInt(mDescriptionResId); 707 parcel.writeString(mNonLocalizedDescription); 708 } 709 710 private void initFromParcel(Parcel parcel) { 711 eventTypes = parcel.readInt(); 712 packageNames = parcel.readStringArray(); 713 feedbackType = parcel.readInt(); 714 notificationTimeout = parcel.readLong(); 715 flags = parcel.readInt(); 716 mId = parcel.readString(); 717 mResolveInfo = parcel.readParcelable(null); 718 mSettingsActivityName = parcel.readString(); 719 mCapabilities = parcel.readInt(); 720 mDescriptionResId = parcel.readInt(); 721 mNonLocalizedDescription = parcel.readString(); 722 } 723 724 @Override 725 public int hashCode() { 726 return 31 * 1 + ((mId == null) ? 0 : mId.hashCode()); 727 } 728 729 @Override 730 public boolean equals(Object obj) { 731 if (this == obj) { 732 return true; 733 } 734 if (obj == null) { 735 return false; 736 } 737 if (getClass() != obj.getClass()) { 738 return false; 739 } 740 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 741 if (mId == null) { 742 if (other.mId != null) { 743 return false; 744 } 745 } else if (!mId.equals(other.mId)) { 746 return false; 747 } 748 return true; 749 } 750 751 @Override 752 public String toString() { 753 StringBuilder stringBuilder = new StringBuilder(); 754 appendEventTypes(stringBuilder, eventTypes); 755 stringBuilder.append(", "); 756 appendPackageNames(stringBuilder, packageNames); 757 stringBuilder.append(", "); 758 appendFeedbackTypes(stringBuilder, feedbackType); 759 stringBuilder.append(", "); 760 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 761 stringBuilder.append(", "); 762 appendFlags(stringBuilder, flags); 763 stringBuilder.append(", "); 764 stringBuilder.append("id: ").append(mId); 765 stringBuilder.append(", "); 766 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 767 stringBuilder.append(", "); 768 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 769 stringBuilder.append(", "); 770 appendCapabilities(stringBuilder, mCapabilities); 771 return stringBuilder.toString(); 772 } 773 774 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 775 stringBuilder.append("feedbackTypes:"); 776 stringBuilder.append("["); 777 while (feedbackTypes != 0) { 778 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 779 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 780 feedbackTypes &= ~feedbackTypeBit; 781 if (feedbackTypes != 0) { 782 stringBuilder.append(", "); 783 } 784 } 785 stringBuilder.append("]"); 786 } 787 788 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 789 stringBuilder.append("packageNames:"); 790 stringBuilder.append("["); 791 if (packageNames != null) { 792 final int packageNameCount = packageNames.length; 793 for (int i = 0; i < packageNameCount; i++) { 794 stringBuilder.append(packageNames[i]); 795 if (i < packageNameCount - 1) { 796 stringBuilder.append(", "); 797 } 798 } 799 } 800 stringBuilder.append("]"); 801 } 802 803 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 804 stringBuilder.append("eventTypes:"); 805 stringBuilder.append("["); 806 while (eventTypes != 0) { 807 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 808 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 809 eventTypes &= ~eventTypeBit; 810 if (eventTypes != 0) { 811 stringBuilder.append(", "); 812 } 813 } 814 stringBuilder.append("]"); 815 } 816 817 private static void appendFlags(StringBuilder stringBuilder, int flags) { 818 stringBuilder.append("flags:"); 819 stringBuilder.append("["); 820 while (flags != 0) { 821 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 822 stringBuilder.append(flagToString(flagBit)); 823 flags &= ~flagBit; 824 if (flags != 0) { 825 stringBuilder.append(", "); 826 } 827 } 828 stringBuilder.append("]"); 829 } 830 831 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 832 stringBuilder.append("capabilities:"); 833 stringBuilder.append("["); 834 while (capabilities != 0) { 835 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 836 stringBuilder.append(capabilityToString(capabilityBit)); 837 capabilities &= ~capabilityBit; 838 if (capabilities != 0) { 839 stringBuilder.append(", "); 840 } 841 } 842 stringBuilder.append("]"); 843 } 844 845 /** 846 * Returns the string representation of a feedback type. For example, 847 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 848 * 849 * @param feedbackType The feedback type. 850 * @return The string representation. 851 */ 852 public static String feedbackTypeToString(int feedbackType) { 853 StringBuilder builder = new StringBuilder(); 854 builder.append("["); 855 while (feedbackType != 0) { 856 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 857 feedbackType &= ~feedbackTypeFlag; 858 switch (feedbackTypeFlag) { 859 case FEEDBACK_AUDIBLE: 860 if (builder.length() > 1) { 861 builder.append(", "); 862 } 863 builder.append("FEEDBACK_AUDIBLE"); 864 break; 865 case FEEDBACK_HAPTIC: 866 if (builder.length() > 1) { 867 builder.append(", "); 868 } 869 builder.append("FEEDBACK_HAPTIC"); 870 break; 871 case FEEDBACK_GENERIC: 872 if (builder.length() > 1) { 873 builder.append(", "); 874 } 875 builder.append("FEEDBACK_GENERIC"); 876 break; 877 case FEEDBACK_SPOKEN: 878 if (builder.length() > 1) { 879 builder.append(", "); 880 } 881 builder.append("FEEDBACK_SPOKEN"); 882 break; 883 case FEEDBACK_VISUAL: 884 if (builder.length() > 1) { 885 builder.append(", "); 886 } 887 builder.append("FEEDBACK_VISUAL"); 888 break; 889 case FEEDBACK_BRAILLE: 890 if (builder.length() > 1) { 891 builder.append(", "); 892 } 893 builder.append("FEEDBACK_BRAILLE"); 894 break; 895 } 896 } 897 builder.append("]"); 898 return builder.toString(); 899 } 900 901 /** 902 * Returns the string representation of a flag. For example, 903 * {@link #DEFAULT} is represented by the string DEFAULT. 904 * 905 * @param flag The flag. 906 * @return The string representation. 907 */ 908 public static String flagToString(int flag) { 909 switch (flag) { 910 case DEFAULT: 911 return "DEFAULT"; 912 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 913 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 914 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 915 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 916 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 917 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 918 case FLAG_REPORT_VIEW_IDS: 919 return "FLAG_REPORT_VIEW_IDS"; 920 case FLAG_REQUEST_FILTER_KEY_EVENTS: 921 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 922 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 923 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 924 default: 925 return null; 926 } 927 } 928 929 /** 930 * Returns the string representation of a capability. For example, 931 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 932 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 933 * 934 * @param capability The capability. 935 * @return The string representation. 936 */ 937 public static String capabilityToString(int capability) { 938 switch (capability) { 939 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 940 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 941 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 942 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 943 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 944 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 945 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 946 return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; 947 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 948 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 949 case CAPABILITY_CAN_PERFORM_GESTURES: 950 return "CAPABILITY_CAN_PERFORM_GESTURES"; 951 default: 952 return "UNKNOWN"; 953 } 954 } 955 956 /** 957 * @hide 958 * @return The list of {@link CapabilityInfo} objects. 959 */ 960 public List<CapabilityInfo> getCapabilityInfos() { 961 if (mCapabilities == 0) { 962 return Collections.emptyList(); 963 } 964 int capabilities = mCapabilities; 965 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 966 while (capabilities != 0) { 967 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 968 capabilities &= ~capabilityBit; 969 CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit); 970 if (capabilityInfo != null) { 971 capabilityInfos.add(capabilityInfo); 972 } 973 } 974 return capabilityInfos; 975 } 976 977 /** 978 * @hide 979 */ 980 public static final class CapabilityInfo { 981 public final int capability; 982 public final int titleResId; 983 public final int descResId; 984 985 public CapabilityInfo(int capability, int titleResId, int descResId) { 986 this.capability = capability; 987 this.titleResId = titleResId; 988 this.descResId = descResId; 989 } 990 } 991 992 /** 993 * @see Parcelable.Creator 994 */ 995 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 996 new Parcelable.Creator<AccessibilityServiceInfo>() { 997 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 998 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 999 info.initFromParcel(parcel); 1000 return info; 1001 } 1002 1003 public AccessibilityServiceInfo[] newArray(int size) { 1004 return new AccessibilityServiceInfo[size]; 1005 } 1006 }; 1007} 1008