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