AccessibilityServiceInfo.java revision 214fb68767502f5fede643a062c1dc5975d75b27
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 private static final SparseArray<CapabilityInfo> sAvailableCapabilityInfos = 114 new SparseArray<CapabilityInfo>(); 115 static { 116 sAvailableCapabilityInfos.put(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 117 new CapabilityInfo(CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT, 118 R.string.capability_title_canRetrieveWindowContent, 119 R.string.capability_desc_canRetrieveWindowContent)); 120 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 121 new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION, 122 R.string.capability_title_canRequestTouchExploration, 123 R.string.capability_desc_canRequestTouchExploration)); 124 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, 125 new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY, 126 R.string.capability_title_canRequestEnhancedWebAccessibility, 127 R.string.capability_desc_canRequestEnhancedWebAccessibility)); 128 sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 129 new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS, 130 R.string.capability_title_canRequestFilterKeyEvents, 131 R.string.capability_desc_canRequestFilterKeyEvents)); 132 sAvailableCapabilityInfos.put(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 133 new CapabilityInfo(CAPABILITY_CAN_CONTROL_MAGNIFICATION, 134 R.string.capability_title_canControlMagnification, 135 R.string.capability_desc_canControlMagnification)); 136 } 137 138 /** 139 * Denotes spoken feedback. 140 */ 141 public static final int FEEDBACK_SPOKEN = 0x0000001; 142 143 /** 144 * Denotes haptic feedback. 145 */ 146 public static final int FEEDBACK_HAPTIC = 0x0000002; 147 148 /** 149 * Denotes audible (not spoken) feedback. 150 */ 151 public static final int FEEDBACK_AUDIBLE = 0x0000004; 152 153 /** 154 * Denotes visual feedback. 155 */ 156 public static final int FEEDBACK_VISUAL = 0x0000008; 157 158 /** 159 * Denotes generic feedback. 160 */ 161 public static final int FEEDBACK_GENERIC = 0x0000010; 162 163 /** 164 * Denotes braille feedback. 165 */ 166 public static final int FEEDBACK_BRAILLE = 0x0000020; 167 168 /** 169 * Mask for all feedback types. 170 * 171 * @see #FEEDBACK_SPOKEN 172 * @see #FEEDBACK_HAPTIC 173 * @see #FEEDBACK_AUDIBLE 174 * @see #FEEDBACK_VISUAL 175 * @see #FEEDBACK_GENERIC 176 * @see #FEEDBACK_BRAILLE 177 */ 178 public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF; 179 180 /** 181 * If an {@link AccessibilityService} is the default for a given type. 182 * Default service is invoked only if no package specific one exists. In case of 183 * more than one package specific service only the earlier registered is notified. 184 */ 185 public static final int DEFAULT = 0x0000001; 186 187 /** 188 * If this flag is set the system will regard views that are not important 189 * for accessibility in addition to the ones that are important for accessibility. 190 * That is, views that are marked as not important for accessibility via 191 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO} or 192 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} and views that are 193 * marked as potentially important for accessibility via 194 * {@link View#IMPORTANT_FOR_ACCESSIBILITY_AUTO} for which the system has determined 195 * that are not important for accessibility, are reported while querying the window 196 * content and also the accessibility service will receive accessibility events from 197 * them. 198 * <p> 199 * <strong>Note:</strong> For accessibility services targeting API version 200 * {@link Build.VERSION_CODES#JELLY_BEAN} or higher this flag has to be explicitly 201 * set for the system to regard views that are not important for accessibility. For 202 * accessibility services targeting API version lower than 203 * {@link Build.VERSION_CODES#JELLY_BEAN} this flag is ignored and all views are 204 * regarded for accessibility purposes. 205 * </p> 206 * <p> 207 * Usually views not important for accessibility are layout managers that do not 208 * react to user actions, do not draw any content, and do not have any special 209 * semantics in the context of the screen content. For example, a three by three 210 * grid can be implemented as three horizontal linear layouts and one vertical, 211 * or three vertical linear layouts and one horizontal, or one grid layout, etc. 212 * In this context the actual layout mangers used to achieve the grid configuration 213 * are not important, rather it is important that there are nine evenly distributed 214 * elements. 215 * </p> 216 */ 217 public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x0000002; 218 219 /** 220 * This flag requests that the system gets into touch exploration mode. 221 * In this mode a single finger moving on the screen behaves as a mouse 222 * pointer hovering over the user interface. The system will also detect 223 * certain gestures performed on the touch screen and notify this service. 224 * The system will enable touch exploration mode if there is at least one 225 * accessibility service that has this flag set. Hence, clearing this 226 * flag does not guarantee that the device will not be in touch exploration 227 * mode since there may be another enabled service that requested it. 228 * <p> 229 * For accessibility services targeting API version higher than 230 * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} that want to set 231 * this flag have to declare this capability in their meta-data by setting 232 * the attribute {@link android.R.attr#canRequestTouchExplorationMode 233 * canRequestTouchExplorationMode} to true, otherwise this flag will 234 * be ignored. For how to declare the meta-data of a service refer to 235 * {@value AccessibilityService#SERVICE_META_DATA}. 236 * </p> 237 * <p> 238 * Services targeting API version equal to or lower than 239 * {@link Build.VERSION_CODES#JELLY_BEAN_MR1} will work normally, i.e. 240 * the first time they are run, if this flag is specified, a dialog is 241 * shown to the user to confirm enabling explore by touch. 242 * </p> 243 * @see android.R.styleable#AccessibilityService_canRequestTouchExplorationMode 244 */ 245 public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004; 246 247 /** 248 * This flag requests from the system to enable web accessibility enhancing 249 * extensions. Such extensions aim to provide improved accessibility support 250 * for content presented in a {@link android.webkit.WebView}. An example of such 251 * an extension is injecting JavaScript from a secure source. The system will enable 252 * enhanced web accessibility if there is at least one accessibility service 253 * that has this flag set. Hence, clearing this flag does not guarantee that the 254 * device will not have enhanced web accessibility enabled since there may be 255 * another enabled service that requested it. 256 * <p> 257 * Services that want to set this flag have to declare this capability 258 * in their meta-data by setting the attribute {@link android.R.attr 259 * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to 260 * true, otherwise this flag will be ignored. For how to declare the meta-data 261 * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. 262 * </p> 263 * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility 264 */ 265 public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008; 266 267 /** 268 * This flag requests that the {@link AccessibilityNodeInfo}s obtained 269 * by an {@link AccessibilityService} contain the id of the source view. 270 * The source view id will be a fully qualified resource name of the 271 * form "package:id/name", for example "foo.bar:id/my_list", and it is 272 * useful for UI test automation. This flag is not set by default. 273 */ 274 public static final int FLAG_REPORT_VIEW_IDS = 0x00000010; 275 276 /** 277 * This flag requests from the system to filter key events. If this flag 278 * is set the accessibility service will receive the key events before 279 * applications allowing it implement global shortcuts. Setting this flag 280 * does not guarantee that this service will filter key events since only 281 * one service can do so at any given time. This avoids user confusion due 282 * to behavior change in case different key filtering services are enabled. 283 * If there is already another key filtering service enabled, this one will 284 * not receive key events. 285 * <p> 286 * Services that want to set this flag have to declare this capability 287 * in their meta-data by setting the attribute {@link android.R.attr 288 * #canRequestFilterKeyEvents canRequestFilterKeyEvents} to true, 289 * otherwise this flag will be ignored. For how to declare the meta-data 290 * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. 291 * </p> 292 * @see android.R.styleable#AccessibilityService_canRequestFilterKeyEvents 293 */ 294 public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 0x00000020; 295 296 /** 297 * This flag indicates to the system that the accessibility service wants 298 * to access content of all interactive windows. An interactive window is a 299 * window that has input focus or can be touched by a sighted user when explore 300 * by touch is not enabled. If this flag is not set your service will not receive 301 * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED} 302 * events, calling AccessibilityService{@link AccessibilityService#getWindows() 303 * AccessibilityService.getWindows()} will return an empty list, and {@link 304 * AccessibilityNodeInfo#getWindow() AccessibilityNodeInfo.getWindow()} will 305 * return null. 306 * <p> 307 * Services that want to set this flag have to declare the capability 308 * to retrieve window content in their meta-data by setting the attribute 309 * {@link android.R.attr#canRetrieveWindowContent canRetrieveWindowContent} to 310 * true, otherwise this flag will be ignored. For how to declare the meta-data 311 * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}. 312 * </p> 313 * @see android.R.styleable#AccessibilityService_canRetrieveWindowContent 314 */ 315 public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 0x00000040; 316 317 /** 318 * The event types an {@link AccessibilityService} is interested in. 319 * <p> 320 * <strong>Can be dynamically set at runtime.</strong> 321 * </p> 322 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED 323 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_LONG_CLICKED 324 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_FOCUSED 325 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SELECTED 326 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED 327 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED 328 * @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED 329 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START 330 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END 331 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER 332 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT 333 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED 334 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED 335 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED 336 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_START 337 * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_INTERACTION_END 338 * @see android.view.accessibility.AccessibilityEvent#TYPE_ANNOUNCEMENT 339 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_START 340 * @see android.view.accessibility.AccessibilityEvent#TYPE_GESTURE_DETECTION_END 341 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUSED 342 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 343 * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY 344 * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED 345 */ 346 public int eventTypes; 347 348 /** 349 * The package names an {@link AccessibilityService} is interested in. Setting 350 * to <code>null</code> is equivalent to all packages. 351 * <p> 352 * <strong>Can be dynamically set at runtime.</strong> 353 * </p> 354 */ 355 public String[] packageNames; 356 357 /** 358 * The feedback type an {@link AccessibilityService} provides. 359 * <p> 360 * <strong>Can be dynamically set at runtime.</strong> 361 * </p> 362 * @see #FEEDBACK_AUDIBLE 363 * @see #FEEDBACK_GENERIC 364 * @see #FEEDBACK_HAPTIC 365 * @see #FEEDBACK_SPOKEN 366 * @see #FEEDBACK_VISUAL 367 * @see #FEEDBACK_BRAILLE 368 */ 369 public int feedbackType; 370 371 /** 372 * The timeout after the most recent event of a given type before an 373 * {@link AccessibilityService} is notified. 374 * <p> 375 * <strong>Can be dynamically set at runtime.</strong>. 376 * </p> 377 * <p> 378 * <strong>Note:</strong> The event notification timeout is useful to avoid propagating 379 * events to the client too frequently since this is accomplished via an expensive 380 * interprocess call. One can think of the timeout as a criteria to determine when 381 * event generation has settled down. 382 */ 383 public long notificationTimeout; 384 385 /** 386 * This field represents a set of flags used for configuring an 387 * {@link AccessibilityService}. 388 * <p> 389 * <strong>Can be dynamically set at runtime.</strong> 390 * </p> 391 * @see #DEFAULT 392 * @see #FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 393 * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE 394 * @see #FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY 395 * @see #FLAG_REQUEST_FILTER_KEY_EVENTS 396 * @see #FLAG_REPORT_VIEW_IDS 397 * @see #FLAG_RETRIEVE_INTERACTIVE_WINDOWS 398 */ 399 public int flags; 400 401 /** 402 * The unique string Id to identify the accessibility service. 403 */ 404 private String mId; 405 406 /** 407 * The Service that implements this accessibility service component. 408 */ 409 private ResolveInfo mResolveInfo; 410 411 /** 412 * The accessibility service setting activity's name, used by the system 413 * settings to launch the setting activity of this accessibility service. 414 */ 415 private String mSettingsActivityName; 416 417 /** 418 * Bit mask with capabilities of this service. 419 */ 420 private int mCapabilities; 421 422 /** 423 * Resource id of the description of the accessibility service. 424 */ 425 private int mDescriptionResId; 426 427 /** 428 * Non localized description of the accessibility service. 429 */ 430 private String mNonLocalizedDescription; 431 432 /** 433 * Creates a new instance. 434 */ 435 public AccessibilityServiceInfo() { 436 /* do nothing */ 437 } 438 439 /** 440 * Creates a new instance. 441 * 442 * @param resolveInfo The service resolve info. 443 * @param context Context for accessing resources. 444 * @throws XmlPullParserException If a XML parsing error occurs. 445 * @throws IOException If a XML parsing error occurs. 446 * 447 * @hide 448 */ 449 public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context) 450 throws XmlPullParserException, IOException { 451 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 452 mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString(); 453 mResolveInfo = resolveInfo; 454 455 XmlResourceParser parser = null; 456 457 try { 458 PackageManager packageManager = context.getPackageManager(); 459 parser = serviceInfo.loadXmlMetaData(packageManager, 460 AccessibilityService.SERVICE_META_DATA); 461 if (parser == null) { 462 return; 463 } 464 465 int type = 0; 466 while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { 467 type = parser.next(); 468 } 469 470 String nodeName = parser.getName(); 471 if (!TAG_ACCESSIBILITY_SERVICE.equals(nodeName)) { 472 throw new XmlPullParserException( "Meta-data does not start with" 473 + TAG_ACCESSIBILITY_SERVICE + " tag"); 474 } 475 476 AttributeSet allAttributes = Xml.asAttributeSet(parser); 477 Resources resources = packageManager.getResourcesForApplication( 478 serviceInfo.applicationInfo); 479 TypedArray asAttributes = resources.obtainAttributes(allAttributes, 480 com.android.internal.R.styleable.AccessibilityService); 481 eventTypes = asAttributes.getInt( 482 com.android.internal.R.styleable.AccessibilityService_accessibilityEventTypes, 483 0); 484 String packageNamez = asAttributes.getString( 485 com.android.internal.R.styleable.AccessibilityService_packageNames); 486 if (packageNamez != null) { 487 packageNames = packageNamez.split("(\\s)*,(\\s)*"); 488 } 489 feedbackType = asAttributes.getInt( 490 com.android.internal.R.styleable.AccessibilityService_accessibilityFeedbackType, 491 0); 492 notificationTimeout = asAttributes.getInt( 493 com.android.internal.R.styleable.AccessibilityService_notificationTimeout, 494 0); 495 flags = asAttributes.getInt( 496 com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); 497 mSettingsActivityName = asAttributes.getString( 498 com.android.internal.R.styleable.AccessibilityService_settingsActivity); 499 if (asAttributes.getBoolean(com.android.internal.R.styleable 500 .AccessibilityService_canRetrieveWindowContent, false)) { 501 mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT; 502 } 503 if (asAttributes.getBoolean(com.android.internal.R.styleable 504 .AccessibilityService_canRequestTouchExplorationMode, false)) { 505 mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION; 506 } 507 if (asAttributes.getBoolean(com.android.internal.R.styleable 508 .AccessibilityService_canRequestEnhancedWebAccessibility, false)) { 509 mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY; 510 } 511 if (asAttributes.getBoolean(com.android.internal.R.styleable 512 .AccessibilityService_canRequestFilterKeyEvents, false)) { 513 mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS; 514 } 515 if (asAttributes.getBoolean(com.android.internal.R.styleable 516 .AccessibilityService_canControlMagnification, false)) { 517 mCapabilities |= CAPABILITY_CAN_CONTROL_MAGNIFICATION; 518 } 519 TypedValue peekedValue = asAttributes.peekValue( 520 com.android.internal.R.styleable.AccessibilityService_description); 521 if (peekedValue != null) { 522 mDescriptionResId = peekedValue.resourceId; 523 CharSequence nonLocalizedDescription = peekedValue.coerceToString(); 524 if (nonLocalizedDescription != null) { 525 mNonLocalizedDescription = nonLocalizedDescription.toString().trim(); 526 } 527 } 528 asAttributes.recycle(); 529 } catch (NameNotFoundException e) { 530 throw new XmlPullParserException( "Unable to create context for: " 531 + serviceInfo.packageName); 532 } finally { 533 if (parser != null) { 534 parser.close(); 535 } 536 } 537 } 538 539 /** 540 * Updates the properties that an AccessibilitySerivice can change dynamically. 541 * 542 * @param other The info from which to update the properties. 543 * 544 * @hide 545 */ 546 public void updateDynamicallyConfigurableProperties(AccessibilityServiceInfo other) { 547 eventTypes = other.eventTypes; 548 packageNames = other.packageNames; 549 feedbackType = other.feedbackType; 550 notificationTimeout = other.notificationTimeout; 551 flags = other.flags; 552 } 553 554 /** 555 * @hide 556 */ 557 public void setComponentName(ComponentName component) { 558 mId = component.flattenToShortString(); 559 } 560 561 /** 562 * The accessibility service id. 563 * <p> 564 * <strong>Generated by the system.</strong> 565 * </p> 566 * @return The id. 567 */ 568 public String getId() { 569 return mId; 570 } 571 572 /** 573 * The service {@link ResolveInfo}. 574 * <p> 575 * <strong>Generated by the system.</strong> 576 * </p> 577 * @return The info. 578 */ 579 public ResolveInfo getResolveInfo() { 580 return mResolveInfo; 581 } 582 583 /** 584 * The settings activity name. 585 * <p> 586 * <strong>Statically set from 587 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 588 * </p> 589 * @return The settings activity name. 590 */ 591 public String getSettingsActivityName() { 592 return mSettingsActivityName; 593 } 594 595 /** 596 * Whether this service can retrieve the current window's content. 597 * <p> 598 * <strong>Statically set from 599 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 600 * </p> 601 * @return True if window content can be retrieved. 602 * 603 * @deprecated Use {@link #getCapabilities()}. 604 */ 605 public boolean getCanRetrieveWindowContent() { 606 return (mCapabilities & CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 607 } 608 609 /** 610 * Returns the bit mask of capabilities this accessibility service has such as 611 * being able to retrieve the active window content, etc. 612 * 613 * @return The capability bit mask. 614 * 615 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 616 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 617 * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY 618 * @see #CAPABILITY_FILTER_KEY_EVENTS 619 */ 620 public int getCapabilities() { 621 return mCapabilities; 622 } 623 624 /** 625 * Sets the bit mask of capabilities this accessibility service has such as 626 * being able to retrieve the active window content, etc. 627 * 628 * @param capabilities The capability bit mask. 629 * 630 * @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT 631 * @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION 632 * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY 633 * @see #CAPABILITY_FILTER_KEY_EVENTS 634 * 635 * @hide 636 */ 637 public void setCapabilities(int capabilities) { 638 mCapabilities = capabilities; 639 } 640 641 /** 642 * Gets the non-localized description of the accessibility service. 643 * <p> 644 * <strong>Statically set from 645 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 646 * </p> 647 * @return The description. 648 * 649 * @deprecated Use {@link #loadDescription(PackageManager)}. 650 */ 651 public String getDescription() { 652 return mNonLocalizedDescription; 653 } 654 655 /** 656 * The localized description of the accessibility service. 657 * <p> 658 * <strong>Statically set from 659 * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong> 660 * </p> 661 * @return The localized description. 662 */ 663 public String loadDescription(PackageManager packageManager) { 664 if (mDescriptionResId == 0) { 665 return mNonLocalizedDescription; 666 } 667 ServiceInfo serviceInfo = mResolveInfo.serviceInfo; 668 CharSequence description = packageManager.getText(serviceInfo.packageName, 669 mDescriptionResId, serviceInfo.applicationInfo); 670 if (description != null) { 671 return description.toString().trim(); 672 } 673 return null; 674 } 675 676 /** 677 * {@inheritDoc} 678 */ 679 public int describeContents() { 680 return 0; 681 } 682 683 public void writeToParcel(Parcel parcel, int flagz) { 684 parcel.writeInt(eventTypes); 685 parcel.writeStringArray(packageNames); 686 parcel.writeInt(feedbackType); 687 parcel.writeLong(notificationTimeout); 688 parcel.writeInt(flags); 689 parcel.writeString(mId); 690 parcel.writeParcelable(mResolveInfo, 0); 691 parcel.writeString(mSettingsActivityName); 692 parcel.writeInt(mCapabilities); 693 parcel.writeInt(mDescriptionResId); 694 parcel.writeString(mNonLocalizedDescription); 695 } 696 697 private void initFromParcel(Parcel parcel) { 698 eventTypes = parcel.readInt(); 699 packageNames = parcel.readStringArray(); 700 feedbackType = parcel.readInt(); 701 notificationTimeout = parcel.readLong(); 702 flags = parcel.readInt(); 703 mId = parcel.readString(); 704 mResolveInfo = parcel.readParcelable(null); 705 mSettingsActivityName = parcel.readString(); 706 mCapabilities = parcel.readInt(); 707 mDescriptionResId = parcel.readInt(); 708 mNonLocalizedDescription = parcel.readString(); 709 } 710 711 @Override 712 public int hashCode() { 713 return 31 * 1 + ((mId == null) ? 0 : mId.hashCode()); 714 } 715 716 @Override 717 public boolean equals(Object obj) { 718 if (this == obj) { 719 return true; 720 } 721 if (obj == null) { 722 return false; 723 } 724 if (getClass() != obj.getClass()) { 725 return false; 726 } 727 AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj; 728 if (mId == null) { 729 if (other.mId != null) { 730 return false; 731 } 732 } else if (!mId.equals(other.mId)) { 733 return false; 734 } 735 return true; 736 } 737 738 @Override 739 public String toString() { 740 StringBuilder stringBuilder = new StringBuilder(); 741 appendEventTypes(stringBuilder, eventTypes); 742 stringBuilder.append(", "); 743 appendPackageNames(stringBuilder, packageNames); 744 stringBuilder.append(", "); 745 appendFeedbackTypes(stringBuilder, feedbackType); 746 stringBuilder.append(", "); 747 stringBuilder.append("notificationTimeout: ").append(notificationTimeout); 748 stringBuilder.append(", "); 749 appendFlags(stringBuilder, flags); 750 stringBuilder.append(", "); 751 stringBuilder.append("id: ").append(mId); 752 stringBuilder.append(", "); 753 stringBuilder.append("resolveInfo: ").append(mResolveInfo); 754 stringBuilder.append(", "); 755 stringBuilder.append("settingsActivityName: ").append(mSettingsActivityName); 756 stringBuilder.append(", "); 757 appendCapabilities(stringBuilder, mCapabilities); 758 return stringBuilder.toString(); 759 } 760 761 private static void appendFeedbackTypes(StringBuilder stringBuilder, int feedbackTypes) { 762 stringBuilder.append("feedbackTypes:"); 763 stringBuilder.append("["); 764 while (feedbackTypes != 0) { 765 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackTypes)); 766 stringBuilder.append(feedbackTypeToString(feedbackTypeBit)); 767 feedbackTypes &= ~feedbackTypeBit; 768 if (feedbackTypes != 0) { 769 stringBuilder.append(", "); 770 } 771 } 772 stringBuilder.append("]"); 773 } 774 775 private static void appendPackageNames(StringBuilder stringBuilder, String[] packageNames) { 776 stringBuilder.append("packageNames:"); 777 stringBuilder.append("["); 778 if (packageNames != null) { 779 final int packageNameCount = packageNames.length; 780 for (int i = 0; i < packageNameCount; i++) { 781 stringBuilder.append(packageNames[i]); 782 if (i < packageNameCount - 1) { 783 stringBuilder.append(", "); 784 } 785 } 786 } 787 stringBuilder.append("]"); 788 } 789 790 private static void appendEventTypes(StringBuilder stringBuilder, int eventTypes) { 791 stringBuilder.append("eventTypes:"); 792 stringBuilder.append("["); 793 while (eventTypes != 0) { 794 final int eventTypeBit = (1 << Integer.numberOfTrailingZeros(eventTypes)); 795 stringBuilder.append(AccessibilityEvent.eventTypeToString(eventTypeBit)); 796 eventTypes &= ~eventTypeBit; 797 if (eventTypes != 0) { 798 stringBuilder.append(", "); 799 } 800 } 801 stringBuilder.append("]"); 802 } 803 804 private static void appendFlags(StringBuilder stringBuilder, int flags) { 805 stringBuilder.append("flags:"); 806 stringBuilder.append("["); 807 while (flags != 0) { 808 final int flagBit = (1 << Integer.numberOfTrailingZeros(flags)); 809 stringBuilder.append(flagToString(flagBit)); 810 flags &= ~flagBit; 811 if (flags != 0) { 812 stringBuilder.append(", "); 813 } 814 } 815 stringBuilder.append("]"); 816 } 817 818 private static void appendCapabilities(StringBuilder stringBuilder, int capabilities) { 819 stringBuilder.append("capabilities:"); 820 stringBuilder.append("["); 821 while (capabilities != 0) { 822 final int capabilityBit = (1 << Integer.numberOfTrailingZeros(capabilities)); 823 stringBuilder.append(capabilityToString(capabilityBit)); 824 capabilities &= ~capabilityBit; 825 if (capabilities != 0) { 826 stringBuilder.append(", "); 827 } 828 } 829 stringBuilder.append("]"); 830 } 831 832 /** 833 * Returns the string representation of a feedback type. For example, 834 * {@link #FEEDBACK_SPOKEN} is represented by the string FEEDBACK_SPOKEN. 835 * 836 * @param feedbackType The feedback type. 837 * @return The string representation. 838 */ 839 public static String feedbackTypeToString(int feedbackType) { 840 StringBuilder builder = new StringBuilder(); 841 builder.append("["); 842 while (feedbackType != 0) { 843 final int feedbackTypeFlag = 1 << Integer.numberOfTrailingZeros(feedbackType); 844 feedbackType &= ~feedbackTypeFlag; 845 switch (feedbackTypeFlag) { 846 case FEEDBACK_AUDIBLE: 847 if (builder.length() > 1) { 848 builder.append(", "); 849 } 850 builder.append("FEEDBACK_AUDIBLE"); 851 break; 852 case FEEDBACK_HAPTIC: 853 if (builder.length() > 1) { 854 builder.append(", "); 855 } 856 builder.append("FEEDBACK_HAPTIC"); 857 break; 858 case FEEDBACK_GENERIC: 859 if (builder.length() > 1) { 860 builder.append(", "); 861 } 862 builder.append("FEEDBACK_GENERIC"); 863 break; 864 case FEEDBACK_SPOKEN: 865 if (builder.length() > 1) { 866 builder.append(", "); 867 } 868 builder.append("FEEDBACK_SPOKEN"); 869 break; 870 case FEEDBACK_VISUAL: 871 if (builder.length() > 1) { 872 builder.append(", "); 873 } 874 builder.append("FEEDBACK_VISUAL"); 875 break; 876 case FEEDBACK_BRAILLE: 877 if (builder.length() > 1) { 878 builder.append(", "); 879 } 880 builder.append("FEEDBACK_BRAILLE"); 881 break; 882 } 883 } 884 builder.append("]"); 885 return builder.toString(); 886 } 887 888 /** 889 * Returns the string representation of a flag. For example, 890 * {@link #DEFAULT} is represented by the string DEFAULT. 891 * 892 * @param flag The flag. 893 * @return The string representation. 894 */ 895 public static String flagToString(int flag) { 896 switch (flag) { 897 case DEFAULT: 898 return "DEFAULT"; 899 case FLAG_INCLUDE_NOT_IMPORTANT_VIEWS: 900 return "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS"; 901 case FLAG_REQUEST_TOUCH_EXPLORATION_MODE: 902 return "FLAG_REQUEST_TOUCH_EXPLORATION_MODE"; 903 case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 904 return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 905 case FLAG_REPORT_VIEW_IDS: 906 return "FLAG_REPORT_VIEW_IDS"; 907 case FLAG_REQUEST_FILTER_KEY_EVENTS: 908 return "FLAG_REQUEST_FILTER_KEY_EVENTS"; 909 case FLAG_RETRIEVE_INTERACTIVE_WINDOWS: 910 return "FLAG_RETRIEVE_INTERACTIVE_WINDOWS"; 911 default: 912 return null; 913 } 914 } 915 916 /** 917 * Returns the string representation of a capability. For example, 918 * {@link #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT} is represented 919 * by the string CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT. 920 * 921 * @param capability The capability. 922 * @return The string representation. 923 */ 924 public static String capabilityToString(int capability) { 925 switch (capability) { 926 case CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT: 927 return "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT"; 928 case CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION: 929 return "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION"; 930 case CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY: 931 return "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; 932 case CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS: 933 return "CAPABILITY_CAN_FILTER_KEY_EVENTS"; 934 case CAPABILITY_CAN_CONTROL_MAGNIFICATION: 935 return "CAPABILITY_CAN_CONTROL_MAGNIFICATION"; 936 default: 937 return "UNKNOWN"; 938 } 939 } 940 941 /** 942 * @hide 943 * @return The list of {@link CapabilityInfo} objects. 944 */ 945 public List<CapabilityInfo> getCapabilityInfos() { 946 if (mCapabilities == 0) { 947 return Collections.emptyList(); 948 } 949 int capabilities = mCapabilities; 950 List<CapabilityInfo> capabilityInfos = new ArrayList<CapabilityInfo>(); 951 while (capabilities != 0) { 952 final int capabilityBit = 1 << Integer.numberOfTrailingZeros(capabilities); 953 capabilities &= ~capabilityBit; 954 CapabilityInfo capabilityInfo = sAvailableCapabilityInfos.get(capabilityBit); 955 if (capabilityInfo != null) { 956 capabilityInfos.add(capabilityInfo); 957 } 958 } 959 return capabilityInfos; 960 } 961 962 /** 963 * @hide 964 */ 965 public static final class CapabilityInfo { 966 public final int capability; 967 public final int titleResId; 968 public final int descResId; 969 970 public CapabilityInfo(int capability, int titleResId, int descResId) { 971 this.capability = capability; 972 this.titleResId = titleResId; 973 this.descResId = descResId; 974 } 975 } 976 977 /** 978 * @see Parcelable.Creator 979 */ 980 public static final Parcelable.Creator<AccessibilityServiceInfo> CREATOR = 981 new Parcelable.Creator<AccessibilityServiceInfo>() { 982 public AccessibilityServiceInfo createFromParcel(Parcel parcel) { 983 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 984 info.initFromParcel(parcel); 985 return info; 986 } 987 988 public AccessibilityServiceInfo[] newArray(int size) { 989 return new AccessibilityServiceInfo[size]; 990 } 991 }; 992} 993