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.view.accessibility; 18 19 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME; 20 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 21 22 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; 23 24 import android.Manifest; 25 import android.accessibilityservice.AccessibilityService; 26 import android.accessibilityservice.AccessibilityServiceInfo; 27 import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType; 28 import android.accessibilityservice.AccessibilityShortcutInfo; 29 import android.annotation.CallbackExecutor; 30 import android.annotation.ColorInt; 31 import android.annotation.FlaggedApi; 32 import android.annotation.IntDef; 33 import android.annotation.NonNull; 34 import android.annotation.Nullable; 35 import android.annotation.RequiresPermission; 36 import android.annotation.SdkConstant; 37 import android.annotation.SystemApi; 38 import android.annotation.SystemService; 39 import android.annotation.TestApi; 40 import android.annotation.UserIdInt; 41 import android.app.RemoteAction; 42 import android.compat.annotation.UnsupportedAppUsage; 43 import android.content.ComponentName; 44 import android.content.Context; 45 import android.content.Intent; 46 import android.content.pm.ActivityInfo; 47 import android.content.pm.PackageManager; 48 import android.content.pm.ResolveInfo; 49 import android.content.pm.ServiceInfo; 50 import android.content.res.Resources; 51 import android.os.Binder; 52 import android.os.Build; 53 import android.os.Bundle; 54 import android.os.Handler; 55 import android.os.HandlerExecutor; 56 import android.os.IBinder; 57 import android.os.Looper; 58 import android.os.Message; 59 import android.os.Process; 60 import android.os.RemoteException; 61 import android.os.ServiceManager; 62 import android.os.SystemClock; 63 import android.os.UserHandle; 64 import android.util.ArrayMap; 65 import android.util.Log; 66 import android.util.SparseArray; 67 import android.view.Display; 68 import android.view.IWindow; 69 import android.view.SurfaceControl; 70 import android.view.View; 71 import android.view.accessibility.AccessibilityEvent.EventType; 72 73 import com.android.internal.R; 74 import com.android.internal.accessibility.common.ShortcutConstants; 75 import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; 76 import com.android.internal.annotations.VisibleForTesting; 77 import com.android.internal.util.IntPair; 78 79 import org.xmlpull.v1.XmlPullParserException; 80 81 import java.io.IOException; 82 import java.lang.annotation.Retention; 83 import java.lang.annotation.RetentionPolicy; 84 import java.util.ArrayList; 85 import java.util.Collections; 86 import java.util.List; 87 import java.util.Map; 88 import java.util.Set; 89 import java.util.concurrent.Executor; 90 91 /** 92 * System level service that serves as an event dispatch for {@link AccessibilityEvent}s, 93 * and provides facilities for querying the accessibility state of the system. 94 * Accessibility events are generated when something notable happens in the user interface, 95 * for example an {@link android.app.Activity} starts, the focus or selection of a 96 * {@link android.view.View} changes etc. Parties interested in handling accessibility 97 * events implement and register an accessibility service which extends 98 * {@link android.accessibilityservice.AccessibilityService}. 99 * 100 * @see AccessibilityEvent 101 * @see AccessibilityNodeInfo 102 * @see android.accessibilityservice.AccessibilityService 103 * @see Context#getSystemService 104 * @see Context#ACCESSIBILITY_SERVICE 105 */ 106 @SystemService(Context.ACCESSIBILITY_SERVICE) 107 public final class AccessibilityManager { 108 private static final boolean DEBUG = false; 109 110 private static final String LOG_TAG = "AccessibilityManager"; 111 112 /** @hide */ 113 public static final int STATE_FLAG_ACCESSIBILITY_ENABLED = 1 /* << 0 */; 114 115 /** @hide */ 116 public static final int STATE_FLAG_TOUCH_EXPLORATION_ENABLED = 1 << 1; 117 118 /** @hide */ 119 public static final int STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED = 1 << 2; 120 121 /** @hide */ 122 public static final int STATE_FLAG_DISPATCH_DOUBLE_TAP = 1 << 3; 123 124 /** @hide */ 125 public static final int STATE_FLAG_REQUEST_MULTI_FINGER_GESTURES = 1 << 4; 126 127 /** @hide */ 128 public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED = 1 << 8; 129 /** @hide */ 130 public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED = 1 << 9; 131 /** @hide */ 132 public static final int STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED = 1 << 10; 133 /** @hide */ 134 public static final int STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED = 1 << 11; 135 /** @hide */ 136 public static final int STATE_FLAG_AUDIO_DESCRIPTION_BY_DEFAULT_ENABLED = 1 << 12; 137 138 /** @hide */ 139 public static final int DALTONIZER_DISABLED = -1; 140 141 /** @hide */ 142 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 143 public static final int DALTONIZER_SIMULATE_MONOCHROMACY = 0; 144 145 /** @hide */ 146 public static final int DALTONIZER_CORRECT_DEUTERANOMALY = 12; 147 148 /** @hide */ 149 public static final int AUTOCLICK_DELAY_DEFAULT = 600; 150 151 /** @hide */ 152 public static final int AUTOCLICK_CURSOR_AREA_SIZE_DEFAULT = 60; 153 154 /** @hide */ 155 public static final int AUTOCLICK_CURSOR_AREA_SIZE_MIN = 20; 156 157 /** @hide */ 158 public static final int AUTOCLICK_CURSOR_AREA_SIZE_MAX = 100; 159 160 /** @hide */ 161 public static final int AUTOCLICK_CURSOR_AREA_INCREMENT_SIZE = 20; 162 163 /** @hide */ 164 public static final boolean AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT_DEFAULT = false; 165 166 /** @hide */ 167 public static final boolean AUTOCLICK_REVERT_TO_LEFT_CLICK_DEFAULT = true; 168 169 /** 170 * Activity action: Launch UI to manage which accessibility service or feature is assigned 171 * to the navigation bar Accessibility button. 172 * <p> 173 * Input: Nothing. 174 * </p> 175 * <p> 176 * Output: Nothing. 177 * </p> 178 * 179 * @hide 180 */ 181 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) 182 public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON = 183 "com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON"; 184 185 /** @hide */ 186 public static final int FLASH_REASON_CALL = 1; 187 188 /** @hide */ 189 public static final int FLASH_REASON_ALARM = 2; 190 191 /** @hide */ 192 public static final int FLASH_REASON_NOTIFICATION = 3; 193 194 /** @hide */ 195 public static final int FLASH_REASON_PREVIEW = 4; 196 197 /** 198 * Annotations for content flag of UI. 199 * @hide 200 */ 201 @Retention(RetentionPolicy.SOURCE) 202 @IntDef(flag = true, prefix = { "FLAG_CONTENT_" }, value = { 203 FLAG_CONTENT_ICONS, 204 FLAG_CONTENT_TEXT, 205 FLAG_CONTENT_CONTROLS 206 }) 207 public @interface ContentFlag {} 208 209 /** 210 * Annotations for reason of Flash notification. 211 * @hide 212 */ 213 @Retention(RetentionPolicy.SOURCE) 214 @IntDef(prefix = { "FLASH_REASON_" }, value = { 215 FLASH_REASON_CALL, 216 FLASH_REASON_ALARM, 217 FLASH_REASON_NOTIFICATION, 218 FLASH_REASON_PREVIEW 219 }) 220 public @interface FlashNotificationReason {} 221 222 /** 223 * Use this flag to indicate the content of a UI that times out contains icons. 224 * 225 * @see #getRecommendedTimeoutMillis(int, int) 226 */ 227 public static final int FLAG_CONTENT_ICONS = 1; 228 229 /** 230 * Use this flag to indicate the content of a UI that times out contains text. 231 * 232 * @see #getRecommendedTimeoutMillis(int, int) 233 */ 234 public static final int FLAG_CONTENT_TEXT = 2; 235 236 /** 237 * Use this flag to indicate the content of a UI that times out contains interactive controls. 238 * 239 * @see #getRecommendedTimeoutMillis(int, int) 240 */ 241 public static final int FLAG_CONTENT_CONTROLS = 4; 242 243 @UnsupportedAppUsage 244 static final Object sInstanceSync = new Object(); 245 246 @UnsupportedAppUsage 247 private static AccessibilityManager sInstance; 248 249 @UnsupportedAppUsage 250 private final Object mLock = new Object(); 251 252 @UnsupportedAppUsage 253 private IAccessibilityManager mService; 254 255 @UnsupportedAppUsage 256 final int mUserId; 257 258 @UnsupportedAppUsage 259 final Handler mHandler; 260 261 final Handler.Callback mCallback; 262 263 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 264 boolean mIsEnabled; 265 266 int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK; 267 268 int mInteractiveUiTimeout; 269 int mNonInteractiveUiTimeout; 270 271 boolean mIsTouchExplorationEnabled; 272 273 @UnsupportedAppUsage(trackingBug = 123768939L) 274 boolean mIsHighContrastTextEnabled; 275 276 boolean mIsAudioDescriptionByDefaultRequested; 277 278 // accessibility tracing state 279 int mAccessibilityTracingState = 0; 280 281 AccessibilityPolicy mAccessibilityPolicy; 282 283 private int mPerformingAction = 0; 284 285 /** The stroke width of the focus rectangle in pixels */ 286 private int mFocusStrokeWidth; 287 /** The color of the focus rectangle */ 288 private int mFocusColor; 289 290 @UnsupportedAppUsage 291 private final ArrayMap<AccessibilityStateChangeListener, Handler> 292 mAccessibilityStateChangeListeners = new ArrayMap<>(); 293 294 private final ArrayMap<TouchExplorationStateChangeListener, Handler> 295 mTouchExplorationStateChangeListeners = new ArrayMap<>(); 296 297 private final ArrayMap<HighContrastTextStateChangeListener, Executor> 298 mHighContrastTextStateChangeListeners = new ArrayMap<>(); 299 300 private final ArrayMap<AccessibilityServicesStateChangeListener, Executor> 301 mServicesStateChangeListeners = new ArrayMap<>(); 302 303 private final ArrayMap<AudioDescriptionRequestedChangeListener, Executor> 304 mAudioDescriptionRequestedChangeListeners = new ArrayMap<>(); 305 306 private boolean mRequestFromAccessibilityTool; 307 308 /** 309 * Map from a view's accessibility id to the list of request preparers set for that view 310 */ 311 private SparseArray<List<AccessibilityRequestPreparer>> mRequestPreparerLists; 312 313 /** 314 * Binder for flash notification. 315 * 316 * @see #startFlashNotificationSequence(Context, int) 317 */ 318 private final Binder mBinder = new Binder(); 319 320 /** 321 * Listener for the system accessibility state. To listen for changes to the 322 * accessibility state on the device, implement this interface and register 323 * it with the system by calling {@link #addAccessibilityStateChangeListener}. 324 */ 325 public interface AccessibilityStateChangeListener { 326 327 /** 328 * Called when the accessibility enabled state changes. 329 * 330 * @param enabled Whether accessibility is enabled. 331 */ onAccessibilityStateChanged(boolean enabled)332 void onAccessibilityStateChanged(boolean enabled); 333 } 334 335 /** 336 * Listener for the system touch exploration state. To listen for changes to 337 * the touch exploration state on the device, implement this interface and 338 * register it with the system by calling 339 * {@link #addTouchExplorationStateChangeListener}. 340 */ 341 public interface TouchExplorationStateChangeListener { 342 343 /** 344 * Called when the touch exploration enabled state changes. 345 * 346 * @param enabled Whether touch exploration is enabled. 347 */ onTouchExplorationStateChanged(boolean enabled)348 void onTouchExplorationStateChanged(boolean enabled); 349 } 350 351 /** 352 * Listener for changes to the state of accessibility services. 353 * 354 * <p> 355 * This refers to changes to {@link AccessibilityServiceInfo}, including: 356 * <ul> 357 * <li>Whenever a service is enabled or disabled, or its info has been set or removed.</li> 358 * <li>Whenever a metadata attribute of any running service's info changes.</li> 359 * </ul> 360 * 361 * @see #getEnabledAccessibilityServiceList for a list of infos of the enabled accessibility 362 * services. 363 * @see #addAccessibilityServicesStateChangeListener 364 * 365 */ 366 public interface AccessibilityServicesStateChangeListener { 367 368 /** 369 * Called when the state of accessibility services changes. 370 * 371 * @param manager The manager that is calling back 372 */ onAccessibilityServicesStateChanged(@onNull AccessibilityManager manager)373 void onAccessibilityServicesStateChanged(@NonNull AccessibilityManager manager); 374 } 375 376 /** 377 * Listener for the system high contrast text state. To listen for changes to 378 * the high contrast text state on the device, implement this interface and 379 * register it with the system by calling 380 * {@link #addHighContrastTextStateChangeListener}. 381 */ 382 @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) 383 public interface HighContrastTextStateChangeListener { 384 385 /** 386 * Called when the high contrast text enabled state changes. 387 * 388 * @param enabled Whether high contrast text is enabled. 389 */ onHighContrastTextStateChanged(boolean enabled)390 void onHighContrastTextStateChanged(boolean enabled); 391 } 392 393 /** 394 * Listener for the audio description by default state. To listen for 395 * changes to the audio description by default state on the device, 396 * implement this interface and register it with the system by calling 397 * {@link #addAudioDescriptionRequestedChangeListener}. 398 */ 399 public interface AudioDescriptionRequestedChangeListener { 400 /** 401 * Called when the audio description enabled state changes. 402 * 403 * @param enabled Whether audio description by default is enabled. 404 */ onAudioDescriptionRequestedChanged(boolean enabled)405 void onAudioDescriptionRequestedChanged(boolean enabled); 406 } 407 408 /** 409 * Policy to inject behavior into the accessibility manager. 410 * 411 * @hide 412 */ 413 public interface AccessibilityPolicy { 414 /** 415 * Checks whether accessibility is enabled. 416 * 417 * @param accessibilityEnabled Whether the accessibility layer is enabled. 418 * @return whether accessibility is enabled. 419 */ isEnabled(boolean accessibilityEnabled)420 boolean isEnabled(boolean accessibilityEnabled); 421 422 /** 423 * Notifies the policy for an accessibility event. 424 * 425 * @param event The event. 426 * @param accessibilityEnabled Whether the accessibility layer is enabled. 427 * @param relevantEventTypes The events relevant events. 428 * @return The event to dispatch or null. 429 */ onAccessibilityEvent(@onNull AccessibilityEvent event, boolean accessibilityEnabled, @EventType int relevantEventTypes)430 @Nullable AccessibilityEvent onAccessibilityEvent(@NonNull AccessibilityEvent event, 431 boolean accessibilityEnabled, @EventType int relevantEventTypes); 432 433 /** 434 * Gets the list of relevant events. 435 * 436 * @param relevantEventTypes The relevant events. 437 * @return The relevant events to report. 438 */ getRelevantEventTypes(@ventType int relevantEventTypes)439 @EventType int getRelevantEventTypes(@EventType int relevantEventTypes); 440 441 /** 442 * Gets the list of installed services to report. 443 * 444 * @param installedService The installed services. 445 * @return The services to report. 446 */ getInstalledAccessibilityServiceList( @ullable List<AccessibilityServiceInfo> installedService)447 @NonNull List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList( 448 @Nullable List<AccessibilityServiceInfo> installedService); 449 450 /** 451 * Gets the list of enabled accessibility services. 452 * 453 * @param feedbackTypeFlags The feedback type to query for. 454 * @param enabledService The enabled services. 455 * @return The services to report. 456 */ getEnabledAccessibilityServiceList( @eedbackType int feedbackTypeFlags, @Nullable List<AccessibilityServiceInfo> enabledService)457 @Nullable List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList( 458 @FeedbackType int feedbackTypeFlags, 459 @Nullable List<AccessibilityServiceInfo> enabledService); 460 } 461 462 private final IAccessibilityManagerClient.Stub mClient = 463 new IAccessibilityManagerClient.Stub() { 464 @Override 465 public void setState(int state) { 466 // We do not want to change this immediately as the application may 467 // have already checked that accessibility is on and fired an event, 468 // that is now propagating up the view tree, Hence, if accessibility 469 // is now off an exception will be thrown. We want to have the exception 470 // enforcement to guard against apps that fire unnecessary accessibility 471 // events when accessibility is off. 472 mHandler.obtainMessage(MyCallback.MSG_SET_STATE, state, 0).sendToTarget(); 473 } 474 475 @Override 476 public void notifyServicesStateChanged(long updatedUiTimeout) { 477 updateUiTimeout(updatedUiTimeout); 478 479 final ArrayMap<AccessibilityServicesStateChangeListener, Executor> listeners; 480 synchronized (mLock) { 481 if (mServicesStateChangeListeners.isEmpty()) { 482 return; 483 } 484 listeners = new ArrayMap<>(mServicesStateChangeListeners); 485 } 486 487 int numListeners = listeners.size(); 488 for (int i = 0; i < numListeners; i++) { 489 final AccessibilityServicesStateChangeListener listener = 490 mServicesStateChangeListeners.keyAt(i); 491 mServicesStateChangeListeners.valueAt(i).execute(() -> listener 492 .onAccessibilityServicesStateChanged(AccessibilityManager.this)); 493 } 494 } 495 496 @Override 497 public void setRelevantEventTypes(int eventTypes) { 498 mRelevantEventTypes = eventTypes; 499 } 500 501 @Override 502 public void setFocusAppearance(int strokeWidth, int color) { 503 synchronized (mLock) { 504 updateFocusAppearanceLocked(strokeWidth, color); 505 } 506 } 507 }; 508 509 /** 510 * Get an AccessibilityManager instance (create one if necessary). 511 * 512 * @param context Context in which this manager operates. 513 * 514 * @hide 515 */ 516 @UnsupportedAppUsage getInstance(Context context)517 public static AccessibilityManager getInstance(Context context) { 518 synchronized (sInstanceSync) { 519 if (sInstance == null) { 520 final int userId; 521 if (Binder.getCallingUid() == Process.SYSTEM_UID 522 || context.checkCallingOrSelfPermission( 523 Manifest.permission.INTERACT_ACROSS_USERS) 524 == PackageManager.PERMISSION_GRANTED 525 || context.checkCallingOrSelfPermission( 526 Manifest.permission.INTERACT_ACROSS_USERS_FULL) 527 == PackageManager.PERMISSION_GRANTED) { 528 userId = UserHandle.USER_CURRENT; 529 } else { 530 userId = context.getUserId(); 531 } 532 sInstance = new AccessibilityManager(context, null, userId); 533 } 534 } 535 return sInstance; 536 } 537 538 /** 539 * Create an instance. 540 * 541 * @param context A {@link Context}. 542 * @param service An interface to the backing service. 543 * @param userId User id under which to run. 544 * 545 * @hide 546 */ AccessibilityManager(Context context, IAccessibilityManager service, int userId)547 public AccessibilityManager(Context context, IAccessibilityManager service, int userId) { 548 // Constructor can't be chained because we can't create an instance of an inner class 549 // before calling another constructor. 550 mCallback = new MyCallback(); 551 mHandler = new Handler(context.getMainLooper(), mCallback); 552 mUserId = userId; 553 synchronized (mLock) { 554 initialFocusAppearanceLocked(context.getResources()); 555 tryConnectToServiceLocked(service); 556 } 557 } 558 559 /** 560 * Create an instance. 561 * 562 * @param context A {@link Context}. 563 * @param handler The handler to use 564 * @param service An interface to the backing service. 565 * @param userId User id under which to run. 566 * @param serviceConnect {@code true} to connect the service or 567 * {@code false} not to connect the service. 568 * 569 * @hide 570 */ 571 @VisibleForTesting AccessibilityManager(Context context, Handler handler, IAccessibilityManager service, int userId, boolean serviceConnect)572 public AccessibilityManager(Context context, Handler handler, IAccessibilityManager service, 573 int userId, boolean serviceConnect) { 574 mCallback = new MyCallback(); 575 mHandler = handler; 576 mUserId = userId; 577 synchronized (mLock) { 578 initialFocusAppearanceLocked(context.getResources()); 579 if (serviceConnect) { 580 tryConnectToServiceLocked(service); 581 } 582 } 583 } 584 585 /** 586 * @hide 587 */ getClient()588 public IAccessibilityManagerClient getClient() { 589 return mClient; 590 } 591 592 /** 593 * Unregisters the IAccessibilityManagerClient from the backing service 594 * @hide 595 */ removeClient()596 public boolean removeClient() { 597 synchronized (mLock) { 598 IAccessibilityManager service = getServiceLocked(); 599 if (service == null) { 600 return false; 601 } 602 try { 603 return service.removeClient(mClient, mUserId); 604 } catch (RemoteException re) { 605 Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); 606 } 607 } 608 return false; 609 } 610 611 /** 612 * @hide 613 */ 614 @VisibleForTesting getCallback()615 public Handler.Callback getCallback() { 616 return mCallback; 617 } 618 619 /** 620 * Returns if the accessibility in the system is enabled. 621 * <p> 622 * <b>Note:</b> This query is used for sending {@link AccessibilityEvent}s, since events are 623 * only needed if accessibility is on. Avoid changing UI or app behavior based on the state of 624 * accessibility. While well-intentioned, doing this creates brittle, less 625 * well-maintained code that works for some users but not others. Shared code leads to more 626 * equitable experiences and less technical debt. 627 * 628 *<p> 629 * For example, if you want to expose a unique interaction with your app, use 630 * ViewCompat#addAccessibilityAction in AndroidX to make this interaction - ideally 631 * with the same code path used for non-accessibility users - available to accessibility 632 * services. Services can then expose this action in the way best fit for their users. 633 * 634 * @return True if accessibility is enabled, false otherwise. 635 */ isEnabled()636 public boolean isEnabled() { 637 synchronized (mLock) { 638 return mIsEnabled || hasAnyDirectConnection() 639 || (mAccessibilityPolicy != null && mAccessibilityPolicy.isEnabled(mIsEnabled)); 640 } 641 } 642 643 /** 644 * @see AccessibilityInteractionClient#hasAnyDirectConnection 645 * @hide 646 */ 647 @TestApi hasAnyDirectConnection()648 public boolean hasAnyDirectConnection() { 649 return AccessibilityInteractionClient.hasAnyDirectConnection(); 650 } 651 652 /** 653 * Returns if the touch exploration in the system is enabled. 654 * <p> 655 * <b>Note:</b> This query is used for dispatching hover events, such as 656 * {@link android.view.MotionEvent#ACTION_HOVER_ENTER}, to accessibility services to manage 657 * touch exploration. Avoid changing UI or app behavior based on the state of accessibility. 658 * While well-intentioned, doing this creates brittle, less well-maintained code that works for 659 * som users but not others. Shared code leads to more equitable experiences and less technical 660 * debt. 661 * 662 * @return True if touch exploration is enabled, false otherwise. 663 */ isTouchExplorationEnabled()664 public boolean isTouchExplorationEnabled() { 665 synchronized (mLock) { 666 IAccessibilityManager service = getServiceLocked(); 667 if (service == null) { 668 return false; 669 } 670 return mIsTouchExplorationEnabled; 671 } 672 } 673 674 /** 675 * Returns if high contrast text in the system is enabled. 676 * <p> 677 * <strong>Note:</strong> You need to query this only if you application is 678 * doing its own rendering and does not rely on the platform rendering pipeline. 679 * </p> 680 * 681 * @return True if high contrast text is enabled, false otherwise. 682 * 683 */ 684 @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) isHighContrastTextEnabled()685 public boolean isHighContrastTextEnabled() { 686 synchronized (mLock) { 687 IAccessibilityManager service = getServiceLocked(); 688 if (service == null) { 689 return false; 690 } 691 return mIsHighContrastTextEnabled; 692 } 693 } 694 695 /** 696 * Sends an {@link AccessibilityEvent}. 697 * 698 * @param event The event to send. 699 * 700 * @throws IllegalStateException if accessibility is not enabled. 701 * 702 * <strong>Note:</strong> The preferred mechanism for sending custom accessibility 703 * events is through calling 704 * {@link android.view.ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 705 * instead of this method to allow predecessors to augment/filter events sent by 706 * their descendants. 707 */ sendAccessibilityEvent(AccessibilityEvent event)708 public void sendAccessibilityEvent(AccessibilityEvent event) { 709 final IAccessibilityManager service; 710 final int userId; 711 final AccessibilityEvent dispatchedEvent; 712 synchronized (mLock) { 713 service = getServiceLocked(); 714 if (service == null) { 715 return; 716 } 717 event.setEventTime(SystemClock.uptimeMillis()); 718 if (event.getAction() == 0) { 719 event.setAction(mPerformingAction); 720 } 721 if (mAccessibilityPolicy != null) { 722 dispatchedEvent = mAccessibilityPolicy.onAccessibilityEvent(event, 723 mIsEnabled, mRelevantEventTypes); 724 if (dispatchedEvent == null) { 725 return; 726 } 727 } else { 728 dispatchedEvent = event; 729 } 730 if (!isEnabled()) { 731 Looper myLooper = Looper.myLooper(); 732 if (myLooper == Looper.getMainLooper()) { 733 throw new IllegalStateException( 734 "Accessibility off. Did you forget to check that?"); 735 } else { 736 // If we're not running on the thread with the main looper, it's possible for 737 // the state of accessibility to change between checking isEnabled and 738 // calling this method. So just log the error rather than throwing the 739 // exception. 740 Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled"); 741 return; 742 } 743 } 744 if ((dispatchedEvent.getEventType() & mRelevantEventTypes) == 0) { 745 if (DEBUG) { 746 Log.i(LOG_TAG, "Not dispatching irrelevant event: " + dispatchedEvent 747 + " that is not among " 748 + AccessibilityEvent.eventTypeToString(mRelevantEventTypes)); 749 } 750 return; 751 } 752 userId = mUserId; 753 } 754 try { 755 // it is possible that this manager is in the same process as the service but 756 // client using it is called through Binder from another process. Example: MMS 757 // app adds a SMS notification and the NotificationManagerService calls this method 758 final long identityToken = Binder.clearCallingIdentity(); 759 try { 760 service.sendAccessibilityEvent(dispatchedEvent, userId); 761 } finally { 762 Binder.restoreCallingIdentity(identityToken); 763 } 764 if (DEBUG) { 765 Log.i(LOG_TAG, dispatchedEvent + " sent"); 766 } 767 } catch (RemoteException re) { 768 Log.e(LOG_TAG, "Error during sending " + dispatchedEvent + " ", re); 769 } finally { 770 if (event != dispatchedEvent) { 771 event.recycle(); 772 } 773 dispatchedEvent.recycle(); 774 } 775 } 776 777 /** 778 * Requests feedback interruption from all accessibility services. 779 */ interrupt()780 public void interrupt() { 781 final IAccessibilityManager service; 782 final int userId; 783 synchronized (mLock) { 784 service = getServiceLocked(); 785 if (service == null) { 786 return; 787 } 788 if (!isEnabled()) { 789 Looper myLooper = Looper.myLooper(); 790 if (myLooper == Looper.getMainLooper()) { 791 throw new IllegalStateException( 792 "Accessibility off. Did you forget to check that?"); 793 } else { 794 // If we're not running on the thread with the main looper, it's possible for 795 // the state of accessibility to change between checking isEnabled and 796 // calling this method. So just log the error rather than throwing the 797 // exception. 798 Log.e(LOG_TAG, "Interrupt called with accessibility disabled"); 799 return; 800 } 801 } 802 userId = mUserId; 803 } 804 try { 805 service.interrupt(userId); 806 if (DEBUG) { 807 Log.i(LOG_TAG, "Requested interrupt from all services"); 808 } 809 } catch (RemoteException re) { 810 Log.e(LOG_TAG, "Error while requesting interrupt from all services. ", re); 811 } 812 } 813 814 /** 815 * Returns the {@link ServiceInfo}s of the installed accessibility services. 816 * 817 * @return An unmodifiable list with {@link ServiceInfo}s. 818 * 819 * @deprecated Use {@link #getInstalledAccessibilityServiceList()} 820 */ 821 @Deprecated getAccessibilityServiceList()822 public List<ServiceInfo> getAccessibilityServiceList() { 823 List<AccessibilityServiceInfo> infos = getInstalledAccessibilityServiceList(); 824 List<ServiceInfo> services = new ArrayList<>(); 825 final int infoCount = infos.size(); 826 for (int i = 0; i < infoCount; i++) { 827 AccessibilityServiceInfo info = infos.get(i); 828 services.add(info.getResolveInfo().serviceInfo); 829 } 830 return Collections.unmodifiableList(services); 831 } 832 833 /** 834 * Returns the {@link AccessibilityServiceInfo}s of the installed accessibility services. 835 * 836 * @return An unmodifiable list with {@link AccessibilityServiceInfo}s. 837 */ getInstalledAccessibilityServiceList()838 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { 839 final IAccessibilityManager service; 840 final int userId; 841 synchronized (mLock) { 842 service = getServiceLocked(); 843 if (service == null) { 844 return Collections.emptyList(); 845 } 846 userId = mUserId; 847 } 848 849 List<AccessibilityServiceInfo> services = null; 850 try { 851 services = service.getInstalledAccessibilityServiceList(userId).getList(); 852 if (DEBUG) { 853 Log.i(LOG_TAG, "Installed AccessibilityServices " + services); 854 } 855 } catch (RemoteException re) { 856 Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re); 857 } 858 if (mAccessibilityPolicy != null) { 859 services = mAccessibilityPolicy.getInstalledAccessibilityServiceList(services); 860 } 861 if (services != null) { 862 return Collections.unmodifiableList(services); 863 } else { 864 return Collections.emptyList(); 865 } 866 } 867 868 /** 869 * @see #getEnabledAccessibilityServiceList(int) 870 * @hide 871 */ getEnabledAccessibilityServiceList( int feedbackTypeFlags, int userId)872 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList( 873 int feedbackTypeFlags, int userId) { 874 final IAccessibilityManager service; 875 synchronized (mLock) { 876 service = getServiceLocked(); 877 if (service == null) { 878 return Collections.emptyList(); 879 } 880 } 881 List<AccessibilityServiceInfo> services = null; 882 try { 883 services = service.getEnabledAccessibilityServiceList(feedbackTypeFlags, userId); 884 if (DEBUG) { 885 Log.i(LOG_TAG, "Enabled AccessibilityServices " + services); 886 } 887 } catch (RemoteException re) { 888 Log.e(LOG_TAG, "Error while obtaining the enabled AccessibilityServices. ", re); 889 } 890 if (mAccessibilityPolicy != null) { 891 services = mAccessibilityPolicy.getEnabledAccessibilityServiceList( 892 feedbackTypeFlags, services); 893 } 894 if (services != null) { 895 return Collections.unmodifiableList(services); 896 } else { 897 return Collections.emptyList(); 898 } 899 } 900 901 /** 902 * Returns the {@link AccessibilityServiceInfo}s of the enabled accessibility services 903 * for a given feedback type. 904 * 905 * @param feedbackTypeFlags The feedback type flags. 906 * @return An unmodifiable list with {@link AccessibilityServiceInfo}s. 907 * 908 * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE 909 * @see AccessibilityServiceInfo#FEEDBACK_GENERIC 910 * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC 911 * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN 912 * @see AccessibilityServiceInfo#FEEDBACK_VISUAL 913 * @see AccessibilityServiceInfo#FEEDBACK_BRAILLE 914 */ getEnabledAccessibilityServiceList( int feedbackTypeFlags)915 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList( 916 int feedbackTypeFlags) { 917 final int userId; 918 synchronized (mLock) { 919 userId = mUserId; 920 } 921 return getEnabledAccessibilityServiceList(feedbackTypeFlags, userId); 922 } 923 924 /** 925 * Returns whether the user must be shown the AccessibilityService warning dialog 926 * before the AccessibilityService (or any shortcut for the service) can be enabled. 927 * @hide 928 */ 929 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) isAccessibilityServiceWarningRequired(@onNull AccessibilityServiceInfo info)930 public boolean isAccessibilityServiceWarningRequired(@NonNull AccessibilityServiceInfo info) { 931 final IAccessibilityManager service; 932 synchronized (mLock) { 933 service = getServiceLocked(); 934 if (service == null) { 935 return true; 936 } 937 } 938 try { 939 return service.isAccessibilityServiceWarningRequired(info); 940 } catch (RemoteException re) { 941 Log.e(LOG_TAG, "Error while checking isAccessibilityServiceWarningRequired: ", re); 942 return true; 943 } 944 } 945 946 /** 947 * Registers an {@link AccessibilityStateChangeListener} for changes in 948 * the global accessibility state of the system. Equivalent to calling 949 * {@link #addAccessibilityStateChangeListener(AccessibilityStateChangeListener, Handler)} 950 * with a null handler. 951 * 952 * @param listener The listener. 953 * @return Always returns {@code true}. 954 */ addAccessibilityStateChangeListener( @onNull AccessibilityStateChangeListener listener)955 public boolean addAccessibilityStateChangeListener( 956 @NonNull AccessibilityStateChangeListener listener) { 957 addAccessibilityStateChangeListener(listener, null); 958 return true; 959 } 960 961 /** 962 * Registers an {@link AccessibilityStateChangeListener} for changes in 963 * the global accessibility state of the system. If the listener has already been registered, 964 * the handler used to call it back is updated. 965 * 966 * @param listener The listener. 967 * @param handler The handler on which the listener should be called back, or {@code null} 968 * for a callback on the process's main handler. 969 */ addAccessibilityStateChangeListener( @onNull AccessibilityStateChangeListener listener, @Nullable Handler handler)970 public void addAccessibilityStateChangeListener( 971 @NonNull AccessibilityStateChangeListener listener, @Nullable Handler handler) { 972 synchronized (mLock) { 973 mAccessibilityStateChangeListeners 974 .put(listener, (handler == null) ? mHandler : handler); 975 } 976 } 977 978 /** 979 * Unregisters an {@link AccessibilityStateChangeListener}. 980 * 981 * @param listener The listener. 982 * @return True if the listener was previously registered. 983 */ removeAccessibilityStateChangeListener( @onNull AccessibilityStateChangeListener listener)984 public boolean removeAccessibilityStateChangeListener( 985 @NonNull AccessibilityStateChangeListener listener) { 986 synchronized (mLock) { 987 int index = mAccessibilityStateChangeListeners.indexOfKey(listener); 988 mAccessibilityStateChangeListeners.remove(listener); 989 return (index >= 0); 990 } 991 } 992 993 /** 994 * Registers a {@link TouchExplorationStateChangeListener} for changes in 995 * the global touch exploration state of the system. Equivalent to calling 996 * {@link #addTouchExplorationStateChangeListener(TouchExplorationStateChangeListener, Handler)} 997 * with a null handler. 998 * 999 * @param listener The listener. 1000 * @return Always returns {@code true}. 1001 */ addTouchExplorationStateChangeListener( @onNull TouchExplorationStateChangeListener listener)1002 public boolean addTouchExplorationStateChangeListener( 1003 @NonNull TouchExplorationStateChangeListener listener) { 1004 addTouchExplorationStateChangeListener(listener, null); 1005 return true; 1006 } 1007 1008 /** 1009 * Registers an {@link TouchExplorationStateChangeListener} for changes in 1010 * the global touch exploration state of the system. If the listener has already been 1011 * registered, the handler used to call it back is updated. 1012 * 1013 * @param listener The listener. 1014 * @param handler The handler on which the listener should be called back, or {@code null} 1015 * for a callback on the process's main handler. 1016 */ addTouchExplorationStateChangeListener( @onNull TouchExplorationStateChangeListener listener, @Nullable Handler handler)1017 public void addTouchExplorationStateChangeListener( 1018 @NonNull TouchExplorationStateChangeListener listener, @Nullable Handler handler) { 1019 synchronized (mLock) { 1020 mTouchExplorationStateChangeListeners 1021 .put(listener, (handler == null) ? mHandler : handler); 1022 } 1023 } 1024 1025 /** 1026 * Unregisters a {@link TouchExplorationStateChangeListener}. 1027 * 1028 * @param listener The listener. 1029 * @return True if listener was previously registered. 1030 */ removeTouchExplorationStateChangeListener( @onNull TouchExplorationStateChangeListener listener)1031 public boolean removeTouchExplorationStateChangeListener( 1032 @NonNull TouchExplorationStateChangeListener listener) { 1033 synchronized (mLock) { 1034 int index = mTouchExplorationStateChangeListeners.indexOfKey(listener); 1035 mTouchExplorationStateChangeListeners.remove(listener); 1036 return (index >= 0); 1037 } 1038 } 1039 1040 /** 1041 * Registers a {@link AccessibilityServicesStateChangeListener}. 1042 * 1043 * @param executor The executor. 1044 * @param listener The listener. 1045 */ addAccessibilityServicesStateChangeListener( @onNull @allbackExecutor Executor executor, @NonNull AccessibilityServicesStateChangeListener listener)1046 public void addAccessibilityServicesStateChangeListener( 1047 @NonNull @CallbackExecutor Executor executor, 1048 @NonNull AccessibilityServicesStateChangeListener listener) { 1049 synchronized (mLock) { 1050 mServicesStateChangeListeners.put(listener, executor); 1051 } 1052 } 1053 1054 /** 1055 * Registers a {@link AccessibilityServicesStateChangeListener}. This will execute a callback on 1056 * the process's main handler. 1057 * 1058 * @param listener The listener. 1059 * 1060 */ addAccessibilityServicesStateChangeListener( @onNull AccessibilityServicesStateChangeListener listener)1061 public void addAccessibilityServicesStateChangeListener( 1062 @NonNull AccessibilityServicesStateChangeListener listener) { 1063 addAccessibilityServicesStateChangeListener(new HandlerExecutor(mHandler), listener); 1064 } 1065 1066 /** 1067 * Unregisters a {@link AccessibilityServicesStateChangeListener}. 1068 * 1069 * @param listener The listener. 1070 * @return {@code true} if the listener was previously registered. 1071 */ removeAccessibilityServicesStateChangeListener( @onNull AccessibilityServicesStateChangeListener listener)1072 public boolean removeAccessibilityServicesStateChangeListener( 1073 @NonNull AccessibilityServicesStateChangeListener listener) { 1074 synchronized (mLock) { 1075 return mServicesStateChangeListeners.remove(listener) != null; 1076 } 1077 } 1078 1079 /** 1080 * Registers callback for when user initialization has completed. 1081 * Does nothing if the same callback is already registered. 1082 * 1083 * @param callback The callback to be registered 1084 * @hide 1085 */ registerUserInitializationCompleteCallback( @onNull IUserInitializationCompleteCallback callback)1086 public void registerUserInitializationCompleteCallback( 1087 @NonNull IUserInitializationCompleteCallback callback) { 1088 IAccessibilityManager service; 1089 synchronized (mLock) { 1090 service = getServiceLocked(); 1091 if (service == null) { 1092 return; 1093 } 1094 } 1095 try { 1096 service.registerUserInitializationCompleteCallback(callback); 1097 } catch (RemoteException re) { 1098 Log.e(LOG_TAG, "Error while registering userInitializationCompleteCallback. ", re); 1099 } 1100 } 1101 1102 /** 1103 * Unregisters callback for when user initialization has completed. 1104 * 1105 * @param callback The callback to be unregistered 1106 * @hide 1107 */ unregisterUserInitializationCompleteCallback( @onNull IUserInitializationCompleteCallback callback)1108 public void unregisterUserInitializationCompleteCallback( 1109 @NonNull IUserInitializationCompleteCallback callback) { 1110 IAccessibilityManager service; 1111 synchronized (mLock) { 1112 service = getServiceLocked(); 1113 if (service == null) { 1114 return; 1115 } 1116 } 1117 try { 1118 service.unregisterUserInitializationCompleteCallback(callback); 1119 } catch (RemoteException re) { 1120 Log.e(LOG_TAG, 1121 "Error while unregistering userInitializationCompleteCallback. ", re); 1122 } 1123 } 1124 1125 /** 1126 * Whether the current accessibility request comes from an 1127 * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool} 1128 * property set to true. 1129 * 1130 * <p> 1131 * You can use this method inside {@link AccessibilityNodeProvider} to decide how to populate 1132 * your nodes. 1133 * </p> 1134 * 1135 * <p> 1136 * <strong>Note:</strong> The return value is valid only when an {@link AccessibilityNodeInfo} 1137 * request is in progress, can change from one request to another, and has no meaning when a 1138 * request is not in progress. 1139 * </p> 1140 * 1141 * @return True if the current request is from a tool that sets isAccessibilityTool. 1142 */ isRequestFromAccessibilityTool()1143 public boolean isRequestFromAccessibilityTool() { 1144 return mRequestFromAccessibilityTool; 1145 } 1146 1147 /** 1148 * Specifies whether the current accessibility request comes from an 1149 * {@link AccessibilityService} with the {@link AccessibilityServiceInfo#isAccessibilityTool} 1150 * property set to true. 1151 * 1152 * @hide 1153 */ setRequestFromAccessibilityTool(boolean requestFromAccessibilityTool)1154 public void setRequestFromAccessibilityTool(boolean requestFromAccessibilityTool) { 1155 mRequestFromAccessibilityTool = requestFromAccessibilityTool; 1156 } 1157 1158 /** 1159 * Registers a {@link AccessibilityRequestPreparer}. 1160 */ addAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer)1161 public void addAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer) { 1162 if (mRequestPreparerLists == null) { 1163 mRequestPreparerLists = new SparseArray<>(1); 1164 } 1165 int id = preparer.getAccessibilityViewId(); 1166 List<AccessibilityRequestPreparer> requestPreparerList = mRequestPreparerLists.get(id); 1167 if (requestPreparerList == null) { 1168 requestPreparerList = new ArrayList<>(1); 1169 mRequestPreparerLists.put(id, requestPreparerList); 1170 } 1171 requestPreparerList.add(preparer); 1172 } 1173 1174 /** 1175 * Unregisters a {@link AccessibilityRequestPreparer}. 1176 */ removeAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer)1177 public void removeAccessibilityRequestPreparer(AccessibilityRequestPreparer preparer) { 1178 if (mRequestPreparerLists == null) { 1179 return; 1180 } 1181 int viewId = preparer.getAccessibilityViewId(); 1182 List<AccessibilityRequestPreparer> requestPreparerList = mRequestPreparerLists.get(viewId); 1183 if (requestPreparerList != null) { 1184 requestPreparerList.remove(preparer); 1185 if (requestPreparerList.isEmpty()) { 1186 mRequestPreparerLists.remove(viewId); 1187 } 1188 } 1189 } 1190 1191 /** 1192 * Get the recommended timeout for changes to the UI needed by this user. Controls should remain 1193 * on the screen for at least this long to give users time to react. Some users may need 1194 * extra time to review the controls, or to reach them, or to activate assistive technology 1195 * to activate the controls automatically. 1196 * <p> 1197 * Use the combination of content flags to indicate contents of UI. For example, use 1198 * {@code FLAG_CONTENT_ICONS | FLAG_CONTENT_TEXT} for message notification which contains 1199 * icons and text, or use {@code FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS} for button dialog 1200 * which contains text and button controls. 1201 * <p/> 1202 * 1203 * @param originalTimeout The timeout appropriate for users with no accessibility needs. 1204 * @param uiContentFlags The combination of flags {@link #FLAG_CONTENT_ICONS}, 1205 * {@link #FLAG_CONTENT_TEXT} or {@link #FLAG_CONTENT_CONTROLS} to 1206 * indicate the contents of UI. 1207 * @return The recommended UI timeout for the current user in milliseconds. 1208 */ getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags)1209 public int getRecommendedTimeoutMillis(int originalTimeout, @ContentFlag int uiContentFlags) { 1210 boolean hasControls = (uiContentFlags & FLAG_CONTENT_CONTROLS) != 0; 1211 boolean hasIconsOrText = (uiContentFlags & FLAG_CONTENT_ICONS) != 0 1212 || (uiContentFlags & FLAG_CONTENT_TEXT) != 0; 1213 int recommendedTimeout = originalTimeout; 1214 if (hasControls) { 1215 recommendedTimeout = Math.max(recommendedTimeout, mInteractiveUiTimeout); 1216 } 1217 if (hasIconsOrText) { 1218 recommendedTimeout = Math.max(recommendedTimeout, mNonInteractiveUiTimeout); 1219 } 1220 return recommendedTimeout; 1221 } 1222 1223 /** 1224 * Gets the strokeWidth of the focus rectangle. This value can be set by 1225 * {@link AccessibilityService}. 1226 * 1227 * @return The strokeWidth of the focus rectangle in pixels. 1228 * 1229 */ getAccessibilityFocusStrokeWidth()1230 public int getAccessibilityFocusStrokeWidth() { 1231 synchronized (mLock) { 1232 return mFocusStrokeWidth; 1233 } 1234 } 1235 1236 /** 1237 * Gets the color of the focus rectangle. This value can be set by 1238 * {@link AccessibilityService}. 1239 * 1240 * @return The color of the focus rectangle. 1241 * 1242 */ getAccessibilityFocusColor()1243 public @ColorInt int getAccessibilityFocusColor() { 1244 synchronized (mLock) { 1245 return mFocusColor; 1246 } 1247 } 1248 1249 /** 1250 * Gets accessibility interaction connection tracing enabled state. 1251 * 1252 * @hide 1253 */ isA11yInteractionConnectionTraceEnabled()1254 public boolean isA11yInteractionConnectionTraceEnabled() { 1255 synchronized (mLock) { 1256 return ((mAccessibilityTracingState 1257 & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_ENABLED) != 0); 1258 } 1259 } 1260 1261 /** 1262 * Gets accessibility interaction connection callback tracing enabled state. 1263 * 1264 * @hide 1265 */ isA11yInteractionConnectionCBTraceEnabled()1266 public boolean isA11yInteractionConnectionCBTraceEnabled() { 1267 synchronized (mLock) { 1268 return ((mAccessibilityTracingState 1269 & STATE_FLAG_TRACE_A11Y_INTERACTION_CONNECTION_CB_ENABLED) != 0); 1270 } 1271 } 1272 1273 /** 1274 * Gets accessibility interaction client tracing enabled state. 1275 * 1276 * @hide 1277 */ isA11yInteractionClientTraceEnabled()1278 public boolean isA11yInteractionClientTraceEnabled() { 1279 synchronized (mLock) { 1280 return ((mAccessibilityTracingState 1281 & STATE_FLAG_TRACE_A11Y_INTERACTION_CLIENT_ENABLED) != 0); 1282 } 1283 } 1284 1285 /** 1286 * Gets accessibility service tracing enabled state. 1287 * 1288 * @hide 1289 */ isA11yServiceTraceEnabled()1290 public boolean isA11yServiceTraceEnabled() { 1291 synchronized (mLock) { 1292 return ((mAccessibilityTracingState 1293 & STATE_FLAG_TRACE_A11Y_SERVICE_ENABLED) != 0); 1294 } 1295 } 1296 1297 /** 1298 * Get the preparers that are registered for an accessibility ID 1299 * 1300 * @param id The ID of interest 1301 * @return The list of preparers, or {@code null} if there are none. 1302 * 1303 * @hide 1304 */ getRequestPreparersForAccessibilityId(int id)1305 public List<AccessibilityRequestPreparer> getRequestPreparersForAccessibilityId(int id) { 1306 if (mRequestPreparerLists == null) { 1307 return null; 1308 } 1309 return mRequestPreparerLists.get(id); 1310 } 1311 1312 /** 1313 * Set the currently performing accessibility action in views. 1314 * 1315 * @param actionId the action id of {@link AccessibilityNodeInfo.AccessibilityAction}. 1316 * @hide 1317 */ notifyPerformingAction(int actionId)1318 public void notifyPerformingAction(int actionId) { 1319 mPerformingAction = actionId; 1320 } 1321 1322 /** 1323 * Get the id of {@link AccessibilityNodeInfo.AccessibilityAction} currently being performed. 1324 * 1325 * @hide 1326 */ getPerformingAction()1327 public int getPerformingAction() { 1328 return mPerformingAction; 1329 } 1330 1331 /** 1332 * Registers a {@link HighContrastTextStateChangeListener} for changes in 1333 * the global high contrast text state of the system. 1334 * 1335 * @param executor a executor to call the listener from 1336 * @param listener The listener to be called 1337 */ 1338 @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) addHighContrastTextStateChangeListener( @onNull @allbackExecutor Executor executor, @NonNull HighContrastTextStateChangeListener listener )1339 public void addHighContrastTextStateChangeListener( 1340 @NonNull @CallbackExecutor Executor executor, 1341 @NonNull HighContrastTextStateChangeListener listener 1342 ) { 1343 synchronized (mLock) { 1344 mHighContrastTextStateChangeListeners.put(listener, executor); 1345 } 1346 } 1347 1348 /** 1349 * Unregisters a {@link HighContrastTextStateChangeListener}. 1350 * 1351 * @param listener The listener. 1352 */ 1353 @FlaggedApi(com.android.graphics.hwui.flags.Flags.FLAG_HIGH_CONTRAST_TEXT_SMALL_TEXT_RECT) removeHighContrastTextStateChangeListener( @onNull HighContrastTextStateChangeListener listener)1354 public void removeHighContrastTextStateChangeListener( 1355 @NonNull HighContrastTextStateChangeListener listener) { 1356 synchronized (mLock) { 1357 mHighContrastTextStateChangeListeners.remove(listener); 1358 } 1359 } 1360 1361 /** 1362 * Registers a {@link AudioDescriptionRequestedChangeListener} 1363 * for changes in the audio description by default state of the system. 1364 * The value could be read via {@link #isAudioDescriptionRequested}. 1365 * 1366 * @param executor The executor on which the listener should be called back. 1367 * @param listener The listener. 1368 */ addAudioDescriptionRequestedChangeListener( @onNull Executor executor, @NonNull AudioDescriptionRequestedChangeListener listener)1369 public void addAudioDescriptionRequestedChangeListener( 1370 @NonNull Executor executor, 1371 @NonNull AudioDescriptionRequestedChangeListener listener) { 1372 synchronized (mLock) { 1373 mAudioDescriptionRequestedChangeListeners.put(listener, executor); 1374 } 1375 } 1376 1377 /** 1378 * Unregisters a {@link AudioDescriptionRequestedChangeListener}. 1379 * 1380 * @param listener The listener. 1381 * @return True if listener was previously registered. 1382 */ removeAudioDescriptionRequestedChangeListener( @onNull AudioDescriptionRequestedChangeListener listener)1383 public boolean removeAudioDescriptionRequestedChangeListener( 1384 @NonNull AudioDescriptionRequestedChangeListener listener) { 1385 synchronized (mLock) { 1386 return (mAudioDescriptionRequestedChangeListeners.remove(listener) != null); 1387 } 1388 } 1389 1390 /** 1391 * Sets the {@link AccessibilityPolicy} controlling this manager. 1392 * 1393 * @param policy The policy. 1394 * 1395 * @hide 1396 */ setAccessibilityPolicy(@ullable AccessibilityPolicy policy)1397 public void setAccessibilityPolicy(@Nullable AccessibilityPolicy policy) { 1398 synchronized (mLock) { 1399 mAccessibilityPolicy = policy; 1400 } 1401 } 1402 1403 /** 1404 * Check if the accessibility volume stream is active. 1405 * 1406 * @return True if accessibility volume is active (i.e. some service has requested it). False 1407 * otherwise. 1408 * @hide 1409 */ isAccessibilityVolumeStreamActive()1410 public boolean isAccessibilityVolumeStreamActive() { 1411 List<AccessibilityServiceInfo> serviceInfos = 1412 getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); 1413 for (int i = 0; i < serviceInfos.size(); i++) { 1414 if ((serviceInfos.get(i).flags & FLAG_ENABLE_ACCESSIBILITY_VOLUME) != 0) { 1415 return true; 1416 } 1417 } 1418 return false; 1419 } 1420 1421 /** 1422 * Report a fingerprint gesture to accessibility. Only available for the system process. 1423 * 1424 * @param keyCode The key code of the gesture 1425 * @return {@code true} if accessibility consumes the event. {@code false} if not. 1426 * @hide 1427 */ sendFingerprintGesture(int keyCode)1428 public boolean sendFingerprintGesture(int keyCode) { 1429 final IAccessibilityManager service; 1430 synchronized (mLock) { 1431 service = getServiceLocked(); 1432 if (service == null) { 1433 return false; 1434 } 1435 } 1436 try { 1437 return service.sendFingerprintGesture(keyCode); 1438 } catch (RemoteException e) { 1439 return false; 1440 } 1441 } 1442 1443 /** 1444 * Returns accessibility window id from window token. Accessibility window id is the one 1445 * returned from AccessibilityWindowInfo.getId(). Only available for the system process. 1446 * 1447 * @param windowToken Window token to find accessibility window id. 1448 * @return Accessibility window id for the window token. 1449 * AccessibilityWindowInfo.UNDEFINED_WINDOW_ID if accessibility window id not available for 1450 * the token. 1451 * @hide 1452 */ 1453 @SystemApi getAccessibilityWindowId(@ullable IBinder windowToken)1454 public int getAccessibilityWindowId(@Nullable IBinder windowToken) { 1455 if (windowToken == null) { 1456 return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1457 } 1458 1459 final IAccessibilityManager service; 1460 synchronized (mLock) { 1461 service = getServiceLocked(); 1462 if (service == null) { 1463 return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1464 } 1465 } 1466 try { 1467 return service.getAccessibilityWindowId(windowToken); 1468 } catch (RemoteException e) { 1469 return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1470 } 1471 } 1472 1473 /** 1474 * Associate the connection between the host View and the embedded SurfaceControlViewHost. 1475 * 1476 * @hide 1477 */ associateEmbeddedHierarchy(@onNull IBinder host, @NonNull IBinder embedded)1478 public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) { 1479 final IAccessibilityManager service; 1480 synchronized (mLock) { 1481 service = getServiceLocked(); 1482 if (service == null) { 1483 return; 1484 } 1485 } 1486 try { 1487 service.associateEmbeddedHierarchy(host, embedded); 1488 } catch (RemoteException e) { 1489 return; 1490 } 1491 } 1492 1493 /** 1494 * Disassociate the connection between the host View and the embedded SurfaceControlViewHost. 1495 * The given token could be either from host side or embedded side. 1496 * 1497 * @hide 1498 */ disassociateEmbeddedHierarchy(@onNull IBinder token)1499 public void disassociateEmbeddedHierarchy(@NonNull IBinder token) { 1500 if (token == null) { 1501 return; 1502 } 1503 final IAccessibilityManager service; 1504 synchronized (mLock) { 1505 service = getServiceLocked(); 1506 if (service == null) { 1507 return; 1508 } 1509 } 1510 try { 1511 service.disassociateEmbeddedHierarchy(token); 1512 } catch (RemoteException e) { 1513 return; 1514 } 1515 } 1516 1517 /** 1518 * Sets the current state and notifies listeners, if necessary. 1519 * 1520 * @param stateFlags The state flags. 1521 */ 1522 @UnsupportedAppUsage setStateLocked(int stateFlags)1523 private void setStateLocked(int stateFlags) { 1524 final boolean enabled = (stateFlags & STATE_FLAG_ACCESSIBILITY_ENABLED) != 0; 1525 final boolean touchExplorationEnabled = 1526 (stateFlags & STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0; 1527 final boolean highTextContrastEnabled = 1528 (stateFlags & STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED) != 0; 1529 final boolean audioDescriptionEnabled = 1530 (stateFlags & STATE_FLAG_AUDIO_DESCRIPTION_BY_DEFAULT_ENABLED) != 0; 1531 1532 final boolean wasEnabled = isEnabled(); 1533 final boolean wasTouchExplorationEnabled = mIsTouchExplorationEnabled; 1534 final boolean wasHighTextContrastEnabled = mIsHighContrastTextEnabled; 1535 final boolean wasAudioDescriptionByDefaultRequested = mIsAudioDescriptionByDefaultRequested; 1536 1537 // Ensure listeners get current state from isZzzEnabled() calls. 1538 mIsEnabled = enabled; 1539 mIsTouchExplorationEnabled = touchExplorationEnabled; 1540 mIsHighContrastTextEnabled = highTextContrastEnabled; 1541 mIsAudioDescriptionByDefaultRequested = audioDescriptionEnabled; 1542 1543 if (wasEnabled != isEnabled()) { 1544 notifyAccessibilityStateChanged(); 1545 } 1546 1547 if (wasTouchExplorationEnabled != touchExplorationEnabled) { 1548 notifyTouchExplorationStateChanged(); 1549 } 1550 1551 if (wasHighTextContrastEnabled != highTextContrastEnabled) { 1552 notifyHighContrastTextStateChanged(); 1553 } 1554 1555 if (wasAudioDescriptionByDefaultRequested 1556 != audioDescriptionEnabled) { 1557 notifyAudioDescriptionbyDefaultStateChanged(); 1558 } 1559 1560 updateAccessibilityTracingState(stateFlags); 1561 } 1562 1563 /** 1564 * Find an installed service with the specified {@link ComponentName}. 1565 * 1566 * @param componentName The name to match to the service. 1567 * 1568 * @return The info corresponding to the installed service, or {@code null} if no such service 1569 * is installed. 1570 * @hide 1571 */ getInstalledServiceInfoWithComponentName( ComponentName componentName)1572 public AccessibilityServiceInfo getInstalledServiceInfoWithComponentName( 1573 ComponentName componentName) { 1574 final List<AccessibilityServiceInfo> installedServiceInfos = 1575 getInstalledAccessibilityServiceList(); 1576 if ((installedServiceInfos == null) || (componentName == null)) { 1577 return null; 1578 } 1579 for (int i = 0; i < installedServiceInfos.size(); i++) { 1580 if (componentName.equals(installedServiceInfos.get(i).getComponentName())) { 1581 return installedServiceInfos.get(i); 1582 } 1583 } 1584 return null; 1585 } 1586 1587 /** 1588 * Adds an accessibility interaction connection interface for a given window. 1589 * @param windowToken The window token to which a connection is added. 1590 * @param leashToken The leash token to which a connection is added. 1591 * @param connection The connection. 1592 * 1593 * @hide 1594 */ addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, String packageName, IAccessibilityInteractionConnection connection)1595 public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, 1596 String packageName, IAccessibilityInteractionConnection connection) { 1597 final IAccessibilityManager service; 1598 final int userId; 1599 synchronized (mLock) { 1600 service = getServiceLocked(); 1601 if (service == null) { 1602 return View.NO_ID; 1603 } 1604 userId = mUserId; 1605 } 1606 try { 1607 return service.addAccessibilityInteractionConnection(windowToken, leashToken, 1608 connection, packageName, userId); 1609 } catch (RemoteException re) { 1610 Log.e(LOG_TAG, "Error while adding an accessibility interaction connection. ", re); 1611 } 1612 return View.NO_ID; 1613 } 1614 1615 /** 1616 * Removed an accessibility interaction connection interface for a given window. 1617 * @param windowToken The window token to which a connection is removed. 1618 * 1619 * @hide 1620 */ removeAccessibilityInteractionConnection(IWindow windowToken)1621 public void removeAccessibilityInteractionConnection(IWindow windowToken) { 1622 final IAccessibilityManager service; 1623 synchronized (mLock) { 1624 service = getServiceLocked(); 1625 if (service == null) { 1626 return; 1627 } 1628 } 1629 try { 1630 service.removeAccessibilityInteractionConnection(windowToken); 1631 } catch (RemoteException re) { 1632 Log.e(LOG_TAG, "Error while removing an accessibility interaction connection. ", re); 1633 } 1634 } 1635 1636 /** 1637 * Perform the accessibility shortcut if the caller has permission. 1638 * 1639 * @hide 1640 */ 1641 @SystemApi 1642 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) performAccessibilityShortcut()1643 public void performAccessibilityShortcut() { 1644 performAccessibilityShortcut(Display.DEFAULT_DISPLAY, HARDWARE, null); 1645 } 1646 1647 /** 1648 * Perform the accessibility shortcut for the given target which is assigned to the shortcut. 1649 * 1650 * @param targetName The flattened {@link ComponentName} string or the class name of a system 1651 * class implementing a supported accessibility feature, or {@code null} if there's no 1652 * specified target. 1653 * @hide 1654 */ 1655 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) performAccessibilityShortcut( int displayId, @UserShortcutType int shortcutType, @Nullable String targetName)1656 public void performAccessibilityShortcut( 1657 int displayId, @UserShortcutType int shortcutType, @Nullable String targetName) { 1658 final IAccessibilityManager service; 1659 synchronized (mLock) { 1660 service = getServiceLocked(); 1661 if (service == null) { 1662 return; 1663 } 1664 } 1665 try { 1666 service.performAccessibilityShortcut(displayId, shortcutType, targetName); 1667 } catch (RemoteException re) { 1668 Log.e(LOG_TAG, "Error performing accessibility shortcut. ", re); 1669 } 1670 } 1671 1672 /** 1673 * Turns on or off a shortcut type of the accessibility features. The shortcut type is one 1674 * of the shortcut defined in the {@link ShortcutConstants.USER_SHORTCUT_TYPES}. 1675 * 1676 * @throws SecurityException if the app does not hold the 1677 * {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission 1678 * @hide 1679 */ 1680 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) enableShortcutsForTargets(boolean enable, @UserShortcutType int shortcutTypes, @NonNull Set<String> targets, @UserIdInt int userId)1681 public void enableShortcutsForTargets(boolean enable, 1682 @UserShortcutType int shortcutTypes, @NonNull Set<String> targets, 1683 @UserIdInt int userId) { 1684 final IAccessibilityManager service; 1685 synchronized (mLock) { 1686 service = getServiceLocked(); 1687 if (service == null) { 1688 return; 1689 } 1690 } 1691 try { 1692 service.enableShortcutsForTargets( 1693 enable, shortcutTypes, targets.stream().toList(), userId); 1694 } catch (RemoteException re) { 1695 throw re.rethrowFromSystemServer(); 1696 } 1697 } 1698 1699 /** 1700 * Returns accessibility feature's component and the provided tile map. This includes the 1701 * TileService provided by the AccessibilityService or Accessibility Activity and the tile 1702 * component provided by the framework's feature. 1703 * 1704 * @return a map of a feature's component name, and its provided tile's component name. The 1705 * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't 1706 * have an entry in this map. 1707 * @hide 1708 * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE 1709 */ 1710 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) 1711 @NonNull getA11yFeatureToTileMap(@serIdInt int userId)1712 public Map<ComponentName, ComponentName> getA11yFeatureToTileMap(@UserIdInt int userId) { 1713 final IAccessibilityManager service; 1714 Map<ComponentName, ComponentName> a11yFeatureToTileMap = new ArrayMap<>(); 1715 synchronized (mLock) { 1716 service = getServiceLocked(); 1717 if (service == null) { 1718 return a11yFeatureToTileMap; 1719 } 1720 } 1721 try { 1722 Bundle a11yFeatureToTile = service.getA11yFeatureToTileMap(userId); 1723 for (String key : a11yFeatureToTile.keySet()) { 1724 ComponentName feature = ComponentName.unflattenFromString(key); 1725 if (feature == null) { 1726 continue; 1727 } 1728 ComponentName tileService = a11yFeatureToTile.getParcelable(key, 1729 ComponentName.class); 1730 if (tileService != null) { 1731 a11yFeatureToTileMap.put(feature, tileService); 1732 } 1733 } 1734 } catch (RemoteException re) { 1735 throw re.rethrowFromSystemServer(); 1736 } 1737 return a11yFeatureToTileMap; 1738 } 1739 1740 /** 1741 * Register the provided {@link RemoteAction} with the given actionId 1742 * <p> 1743 * To perform established system actions, an accessibility service uses the GLOBAL_ACTION 1744 * constants in {@link android.accessibilityservice.AccessibilityService}. To provide a 1745 * customized implementation for one of these actions, the id of the registered system action 1746 * must match that of the corresponding GLOBAL_ACTION constant. For example, to register a 1747 * Back action, {@code actionId} must be 1748 * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK} 1749 * </p> 1750 * @param action The remote action to be registered with the given actionId as system action. 1751 * @param actionId The id uniquely identify the system action. 1752 * @hide 1753 */ 1754 @SystemApi 1755 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) registerSystemAction(@onNull RemoteAction action, int actionId)1756 public void registerSystemAction(@NonNull RemoteAction action, int actionId) { 1757 final IAccessibilityManager service; 1758 synchronized (mLock) { 1759 service = getServiceLocked(); 1760 if (service == null) { 1761 return; 1762 } 1763 } 1764 try { 1765 service.registerSystemAction(action, actionId); 1766 1767 if (DEBUG) { 1768 Log.i(LOG_TAG, "System action " + action.getTitle() + " is registered."); 1769 } 1770 } catch (RemoteException re) { 1771 Log.e(LOG_TAG, "Error registering system action " + action.getTitle() + " ", re); 1772 } 1773 } 1774 1775 /** 1776 * Unregister a system action with the given actionId 1777 * 1778 * @param actionId The id uniquely identify the system action to be unregistered. 1779 * @hide 1780 */ 1781 @SystemApi 1782 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) unregisterSystemAction(int actionId)1783 public void unregisterSystemAction(int actionId) { 1784 final IAccessibilityManager service; 1785 synchronized (mLock) { 1786 service = getServiceLocked(); 1787 if (service == null) { 1788 return; 1789 } 1790 } 1791 try { 1792 service.unregisterSystemAction(actionId); 1793 1794 if (DEBUG) { 1795 Log.i(LOG_TAG, "System action with actionId " + actionId + " is unregistered."); 1796 } 1797 } catch (RemoteException re) { 1798 Log.e(LOG_TAG, "Error unregistering system action with actionId " + actionId + " ", re); 1799 } 1800 } 1801 1802 /** 1803 * Notifies that the accessibility button in the system's navigation area has been clicked, 1804 * or a gesture shortcut input has been performed. 1805 * 1806 * @param displayId The logical display id. 1807 * @hide 1808 */ 1809 @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) notifyAccessibilityButtonClicked(int displayId)1810 public void notifyAccessibilityButtonClicked(int displayId) { 1811 notifyAccessibilityButtonClicked(displayId, null); 1812 } 1813 1814 /** 1815 * Perform the accessibility button or gesture 1816 * for the given target which is assigned to the button. 1817 * 1818 * @param displayId displayId The logical display id. 1819 * @param targetName The flattened {@link ComponentName} string or the class name of a system 1820 * class implementing a supported accessibility feature, or {@code null} if there's no 1821 * specified target. 1822 * @hide 1823 */ 1824 @RequiresPermission(android.Manifest.permission.STATUS_BAR_SERVICE) notifyAccessibilityButtonClicked(int displayId, @Nullable String targetName)1825 public void notifyAccessibilityButtonClicked(int displayId, @Nullable String targetName) { 1826 final IAccessibilityManager service; 1827 synchronized (mLock) { 1828 service = getServiceLocked(); 1829 if (service == null) { 1830 return; 1831 } 1832 } 1833 try { 1834 service.notifyAccessibilityButtonClicked(displayId, targetName); 1835 } catch (RemoteException re) { 1836 Log.e(LOG_TAG, "Error while dispatching accessibility button click", re); 1837 } 1838 } 1839 1840 /** 1841 * Notifies that a shortcut was long-clicked. 1842 * This displays the dialog used to select which target the given shortcut will use, 1843 * from its list of targets. 1844 * The current shortcut type is determined by the current navigation mode. 1845 * 1846 * @param displayId The id of the display to show the dialog on. 1847 * @hide 1848 */ 1849 @RequiresPermission(Manifest.permission.STATUS_BAR_SERVICE) notifyAccessibilityButtonLongClicked(int displayId)1850 public void notifyAccessibilityButtonLongClicked(int displayId) { 1851 final IAccessibilityManager service; 1852 synchronized (mLock) { 1853 service = getServiceLocked(); 1854 if (service == null) { 1855 return; 1856 } 1857 } 1858 try { 1859 service.notifyAccessibilityButtonLongClicked(displayId); 1860 } catch (RemoteException re) { 1861 Log.e(LOG_TAG, "Error while dispatching accessibility button long click. ", re); 1862 } 1863 } 1864 1865 /** 1866 * Notifies that the visibility of the accessibility button in the system's navigation area 1867 * has changed. 1868 * 1869 * @param shown {@code true} if the accessibility button is visible within the system 1870 * navigation area, {@code false} otherwise 1871 * @hide 1872 */ notifyAccessibilityButtonVisibilityChanged(boolean shown)1873 public void notifyAccessibilityButtonVisibilityChanged(boolean shown) { 1874 final IAccessibilityManager service; 1875 synchronized (mLock) { 1876 service = getServiceLocked(); 1877 if (service == null) { 1878 return; 1879 } 1880 } 1881 try { 1882 service.notifyAccessibilityButtonVisibilityChanged(shown); 1883 } catch (RemoteException re) { 1884 Log.e(LOG_TAG, "Error while dispatching accessibility button visibility change", re); 1885 } 1886 } 1887 1888 /** 1889 * Set an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture 1890 * window. Intended for use by the System UI only. 1891 * 1892 * @param connection The connection to handle the actions. Set to {@code null} to avoid 1893 * affecting the actions. 1894 * 1895 * @hide 1896 */ setPictureInPictureActionReplacingConnection( @ullable IAccessibilityInteractionConnection connection)1897 public void setPictureInPictureActionReplacingConnection( 1898 @Nullable IAccessibilityInteractionConnection connection) { 1899 final IAccessibilityManager service; 1900 synchronized (mLock) { 1901 service = getServiceLocked(); 1902 if (service == null) { 1903 return; 1904 } 1905 } 1906 try { 1907 service.setPictureInPictureActionReplacingConnection(connection); 1908 } catch (RemoteException re) { 1909 Log.e(LOG_TAG, "Error setting picture in picture action replacement", re); 1910 } 1911 } 1912 1913 /** 1914 * Returns the list of shortcut target names currently assigned to the given shortcut. 1915 * 1916 * @param shortcutType The shortcut type. 1917 * @return The list of shortcut target names. 1918 * @hide 1919 */ 1920 @TestApi 1921 @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) 1922 @NonNull getAccessibilityShortcutTargets( @serShortcutType int shortcutType)1923 public List<String> getAccessibilityShortcutTargets( 1924 @UserShortcutType int shortcutType) { 1925 final IAccessibilityManager service; 1926 synchronized (mLock) { 1927 service = getServiceLocked(); 1928 } 1929 if (service != null) { 1930 try { 1931 return service.getAccessibilityShortcutTargets(shortcutType); 1932 } catch (RemoteException re) { 1933 re.rethrowFromSystemServer(); 1934 } 1935 } 1936 return Collections.emptyList(); 1937 } 1938 1939 /** 1940 * Returns the {@link AccessibilityShortcutInfo}s of the installed accessibility shortcut 1941 * targets, for specific user. 1942 * 1943 * @param context The context of the application. 1944 * @param userId The user id. 1945 * @return A list with {@link AccessibilityShortcutInfo}s. 1946 * @hide 1947 */ 1948 @NonNull getInstalledAccessibilityShortcutListAsUser( @onNull Context context, @UserIdInt int userId)1949 public List<AccessibilityShortcutInfo> getInstalledAccessibilityShortcutListAsUser( 1950 @NonNull Context context, @UserIdInt int userId) { 1951 final List<AccessibilityShortcutInfo> shortcutInfos = new ArrayList<>(); 1952 final int flags = PackageManager.GET_ACTIVITIES 1953 | PackageManager.GET_META_DATA 1954 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS 1955 | PackageManager.MATCH_DIRECT_BOOT_AWARE 1956 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 1957 final Intent actionMain = new Intent(Intent.ACTION_MAIN); 1958 actionMain.addCategory(Intent.CATEGORY_ACCESSIBILITY_SHORTCUT_TARGET); 1959 1960 final PackageManager packageManager = context.getPackageManager(); 1961 final List<ResolveInfo> installedShortcutList = 1962 packageManager.queryIntentActivitiesAsUser(actionMain, flags, userId); 1963 for (int i = 0; i < installedShortcutList.size(); i++) { 1964 final AccessibilityShortcutInfo shortcutInfo = 1965 getShortcutInfo(context, installedShortcutList.get(i)); 1966 if (shortcutInfo != null) { 1967 shortcutInfos.add(shortcutInfo); 1968 } 1969 } 1970 return shortcutInfos; 1971 } 1972 1973 /** 1974 * Returns an {@link AccessibilityShortcutInfo} according to the given {@link ResolveInfo} of 1975 * an activity. 1976 * 1977 * @param context The context of the application. 1978 * @param resolveInfo The resolve info of an activity. 1979 * @return The AccessibilityShortcutInfo. 1980 */ 1981 @Nullable getShortcutInfo(@onNull Context context, @NonNull ResolveInfo resolveInfo)1982 private AccessibilityShortcutInfo getShortcutInfo(@NonNull Context context, 1983 @NonNull ResolveInfo resolveInfo) { 1984 final ActivityInfo activityInfo = resolveInfo.activityInfo; 1985 if (activityInfo == null || activityInfo.metaData == null 1986 || activityInfo.metaData.getInt(AccessibilityShortcutInfo.META_DATA) == 0) { 1987 return null; 1988 } 1989 try { 1990 return new AccessibilityShortcutInfo(context, activityInfo); 1991 } catch (XmlPullParserException | IOException exp) { 1992 Log.e(LOG_TAG, "Error while initializing AccessibilityShortcutInfo", exp); 1993 } 1994 return null; 1995 } 1996 1997 /** 1998 * 1999 * Sets an {@link IMagnificationConnection} that manipulates magnification in SystemUI. 2000 * 2001 * @param connection The connection that manipulates magnification in SystemUI. 2002 * @hide 2003 */ setMagnificationConnection(@ullable IMagnificationConnection connection)2004 public void setMagnificationConnection(@Nullable 2005 IMagnificationConnection connection) { 2006 final IAccessibilityManager service; 2007 synchronized (mLock) { 2008 service = getServiceLocked(); 2009 if (service == null) { 2010 return; 2011 } 2012 } 2013 try { 2014 service.setMagnificationConnection(connection); 2015 } catch (RemoteException re) { 2016 Log.e(LOG_TAG, "Error setting magnification connection", re); 2017 } 2018 } 2019 2020 /** 2021 * Determines if users want to select sound track with audio description by default. 2022 * <p> 2023 * Audio description, also referred to as a video description, described video, or 2024 * more precisely called a visual description, is a form of narration used to provide 2025 * information surrounding key visual elements in a media work for the benefit of 2026 * blind and visually impaired consumers. 2027 * </p> 2028 * <p> 2029 * The method provides the preference value to content provider apps to select the 2030 * default sound track during playing a video or movie. 2031 * </p> 2032 * <p> 2033 * Add listener to detect the state change via 2034 * {@link #addAudioDescriptionRequestedChangeListener} 2035 * </p> 2036 * @return {@code true} if the audio description is enabled, {@code false} otherwise. 2037 */ isAudioDescriptionRequested()2038 public boolean isAudioDescriptionRequested() { 2039 synchronized (mLock) { 2040 IAccessibilityManager service = getServiceLocked(); 2041 if (service == null) { 2042 return false; 2043 } 2044 return mIsAudioDescriptionByDefaultRequested; 2045 } 2046 } 2047 2048 /** 2049 * Sets the system audio caption enabled state. 2050 * 2051 * @param isEnabled The system audio captioning enabled state. 2052 * @param userId The user Id. 2053 * @hide 2054 */ setSystemAudioCaptioningEnabled(boolean isEnabled, int userId)2055 public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) { 2056 final IAccessibilityManager service; 2057 synchronized (mLock) { 2058 service = getServiceLocked(); 2059 if (service == null) { 2060 return; 2061 } 2062 } 2063 try { 2064 service.setSystemAudioCaptioningEnabled(isEnabled, userId); 2065 } catch (RemoteException re) { 2066 throw re.rethrowFromSystemServer(); 2067 } 2068 } 2069 2070 /** 2071 * Gets the system audio caption UI enabled state. 2072 * 2073 * @param userId The user Id. 2074 * @return the system audio caption UI enabled state. 2075 * @hide 2076 */ isSystemAudioCaptioningUiEnabled(int userId)2077 public boolean isSystemAudioCaptioningUiEnabled(int userId) { 2078 final IAccessibilityManager service; 2079 synchronized (mLock) { 2080 service = getServiceLocked(); 2081 if (service == null) { 2082 return false; 2083 } 2084 } 2085 try { 2086 return service.isSystemAudioCaptioningUiEnabled(userId); 2087 } catch (RemoteException re) { 2088 throw re.rethrowFromSystemServer(); 2089 } 2090 } 2091 2092 /** 2093 * Sets the system audio caption UI enabled state. 2094 * 2095 * @param isEnabled The system audio captioning UI enabled state. 2096 * @param userId The user Id. 2097 * @hide 2098 */ setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId)2099 public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) { 2100 final IAccessibilityManager service; 2101 synchronized (mLock) { 2102 service = getServiceLocked(); 2103 if (service == null) { 2104 return; 2105 } 2106 } 2107 try { 2108 service.setSystemAudioCaptioningUiEnabled(isEnabled, userId); 2109 } catch (RemoteException re) { 2110 throw re.rethrowFromSystemServer(); 2111 } 2112 } 2113 2114 2115 /** 2116 * Sets the {@link AccessibilityWindowAttributes} to the window associated with the given 2117 * window id. 2118 * 2119 * @param displayId The display id of the window. 2120 * @param windowId The id of the window. 2121 * @param attributes The accessibility window attributes. 2122 * @hide 2123 */ setAccessibilityWindowAttributes(int displayId, int windowId, AccessibilityWindowAttributes attributes)2124 public void setAccessibilityWindowAttributes(int displayId, int windowId, 2125 AccessibilityWindowAttributes attributes) { 2126 final IAccessibilityManager service; 2127 synchronized (mLock) { 2128 service = getServiceLocked(); 2129 if (service == null) { 2130 return; 2131 } 2132 } 2133 try { 2134 service.setAccessibilityWindowAttributes(displayId, windowId, mUserId, attributes); 2135 } catch (RemoteException re) { 2136 re.rethrowFromSystemServer(); 2137 } 2138 } 2139 2140 /** 2141 * Registers an {@link AccessibilityDisplayProxy}, so this proxy can access UI content specific 2142 * to its display. 2143 * 2144 * @param proxy the {@link AccessibilityDisplayProxy} to register. 2145 * @return {@code true} if the proxy is successfully registered. 2146 * 2147 * @throws IllegalArgumentException if the proxy's display is not currently tracked by a11y, is 2148 * {@link android.view.Display#DEFAULT_DISPLAY}, is or lower than 2149 * {@link android.view.Display#INVALID_DISPLAY}, or is already being proxy-ed. 2150 * 2151 * @throws SecurityException if the app does not hold the required permissions. 2152 * 2153 * @hide 2154 */ 2155 @SystemApi 2156 @RequiresPermission(allOf = {Manifest.permission.MANAGE_ACCESSIBILITY, 2157 Manifest.permission.CREATE_VIRTUAL_DEVICE}) registerDisplayProxy(@onNull AccessibilityDisplayProxy proxy)2158 public boolean registerDisplayProxy(@NonNull AccessibilityDisplayProxy proxy) { 2159 final IAccessibilityManager service; 2160 synchronized (mLock) { 2161 service = getServiceLocked(); 2162 if (service == null) { 2163 return false; 2164 } 2165 } 2166 2167 try { 2168 return service.registerProxyForDisplay(proxy.mServiceClient, proxy.getDisplayId()); 2169 } catch (RemoteException re) { 2170 throw re.rethrowFromSystemServer(); 2171 } 2172 } 2173 2174 /** 2175 * Unregisters an {@link AccessibilityDisplayProxy}. 2176 * 2177 * @return {@code true} if the proxy is successfully unregistered. 2178 * 2179 * @throws SecurityException if the app does not hold the required permissions. 2180 * 2181 * @hide 2182 */ 2183 @SystemApi 2184 @RequiresPermission(allOf = {Manifest.permission.MANAGE_ACCESSIBILITY, 2185 Manifest.permission.CREATE_VIRTUAL_DEVICE}) unregisterDisplayProxy(@onNull AccessibilityDisplayProxy proxy)2186 public boolean unregisterDisplayProxy(@NonNull AccessibilityDisplayProxy proxy) { 2187 final IAccessibilityManager service; 2188 synchronized (mLock) { 2189 service = getServiceLocked(); 2190 if (service == null) { 2191 return false; 2192 } 2193 } 2194 try { 2195 return service.unregisterProxyForDisplay(proxy.getDisplayId()); 2196 } catch (RemoteException re) { 2197 throw re.rethrowFromSystemServer(); 2198 } 2199 } 2200 2201 /** 2202 * Start sequence (infinite) type of flash notification. Use {@code Context} to retrieve the 2203 * package name as the identifier of this flash notification. 2204 * The notification can be cancelled later by calling {@link #stopFlashNotificationSequence} 2205 * with same {@code Context}. 2206 * If the binder associated with this {@link AccessibilityManager} instance dies then the 2207 * sequence will stop automatically. It is strongly recommended to call 2208 * {@link #stopFlashNotificationSequence} within a reasonable amount of time after calling 2209 * this method. 2210 * 2211 * @param context The context in which this manager operates. 2212 * @param reason The triggering reason of flash notification. 2213 * @return {@code true} if flash notification works properly. 2214 * @hide 2215 */ 2216 @FlaggedApi(Flags.FLAG_FLASH_NOTIFICATION_SYSTEM_API) 2217 @TestApi 2218 @SystemApi(client = MODULE_LIBRARIES) startFlashNotificationSequence(@onNull Context context, @FlashNotificationReason int reason)2219 public boolean startFlashNotificationSequence(@NonNull Context context, 2220 @FlashNotificationReason int reason) { 2221 final IAccessibilityManager service; 2222 synchronized (mLock) { 2223 service = getServiceLocked(); 2224 if (service == null) { 2225 return false; 2226 } 2227 } 2228 2229 try { 2230 return service.startFlashNotificationSequence(context.getOpPackageName(), 2231 reason, mBinder); 2232 } catch (RemoteException | SecurityException e) { 2233 Log.e(LOG_TAG, "Error while start flash notification sequence", e); 2234 return false; 2235 } 2236 } 2237 2238 /** 2239 * Stop sequence (infinite) type of flash notification. The flash notification with the 2240 * package name retrieved from {@code Context} as identifier will be stopped if exist. 2241 * It is strongly recommended to call this method within a reasonable amount of time after 2242 * calling {@link #startFlashNotificationSequence} method. 2243 * 2244 * @param context The context in which this manager operates. 2245 * @return {@code true} if flash notification stops properly. 2246 * @hide 2247 */ 2248 @FlaggedApi(Flags.FLAG_FLASH_NOTIFICATION_SYSTEM_API) 2249 @TestApi 2250 @SystemApi(client = MODULE_LIBRARIES) stopFlashNotificationSequence(@onNull Context context)2251 public boolean stopFlashNotificationSequence(@NonNull Context context) { 2252 final IAccessibilityManager service; 2253 synchronized (mLock) { 2254 service = getServiceLocked(); 2255 if (service == null) { 2256 return false; 2257 } 2258 } 2259 2260 try { 2261 return service.stopFlashNotificationSequence(context.getOpPackageName()); 2262 } catch (RemoteException | SecurityException e) { 2263 Log.e(LOG_TAG, "Error while stop flash notification sequence", e); 2264 return false; 2265 } 2266 } 2267 2268 /** 2269 * Start event (finite) type of flash notification. 2270 * 2271 * @param context The context in which this manager operates. 2272 * @param reason The triggering reason of flash notification. 2273 * @param reasonPkg The package that trigger the flash notification. 2274 * @return {@code true} if flash notification works properly. 2275 * @hide 2276 */ startFlashNotificationEvent(@onNull Context context, @FlashNotificationReason int reason, @Nullable String reasonPkg)2277 public boolean startFlashNotificationEvent(@NonNull Context context, 2278 @FlashNotificationReason int reason, @Nullable String reasonPkg) { 2279 final IAccessibilityManager service; 2280 synchronized (mLock) { 2281 service = getServiceLocked(); 2282 if (service == null) { 2283 return false; 2284 } 2285 } 2286 2287 try { 2288 return service.startFlashNotificationEvent(context.getOpPackageName(), 2289 reason, reasonPkg); 2290 } catch (RemoteException | SecurityException e) { 2291 Log.e(LOG_TAG, "Error while start flash notification event", e); 2292 return false; 2293 } 2294 } 2295 2296 /** 2297 * Determines if the accessibility target is allowed. 2298 * 2299 * @param packageName The name of the application attempting to perform the operation. 2300 * @param uid The user id of the application attempting to perform the operation. 2301 * @param userId The id of the user for whom to perform the operation. 2302 * @return {@code true} the accessibility target is allowed. 2303 * @hide 2304 */ isAccessibilityTargetAllowed(String packageName, int uid, int userId)2305 public boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId) { 2306 final IAccessibilityManager service; 2307 synchronized (mLock) { 2308 service = getServiceLocked(); 2309 if (service == null) { 2310 return false; 2311 } 2312 } 2313 2314 try { 2315 return service.isAccessibilityTargetAllowed(packageName, uid, userId); 2316 } catch (RemoteException re) { 2317 Log.e(LOG_TAG, "Error while check accessibility target status", re); 2318 return false; 2319 } 2320 } 2321 2322 /** 2323 * Sends restricted dialog intent if the accessibility target is disallowed. 2324 * 2325 * @param packageName The name of the application attempting to perform the operation. 2326 * @param uid The user id of the application attempting to perform the operation. 2327 * @param userId The id of the user for whom to perform the operation. 2328 * @return {@code true} if the restricted dialog is shown. 2329 * @hide 2330 */ sendRestrictedDialogIntent(String packageName, int uid, int userId)2331 public boolean sendRestrictedDialogIntent(String packageName, int uid, int userId) { 2332 final IAccessibilityManager service; 2333 synchronized (mLock) { 2334 service = getServiceLocked(); 2335 if (service == null) { 2336 return false; 2337 } 2338 } 2339 2340 try { 2341 return service.sendRestrictedDialogIntent(packageName, uid, userId); 2342 } catch (RemoteException re) { 2343 Log.e(LOG_TAG, "Error while show restricted dialog", re); 2344 return false; 2345 } 2346 } 2347 getServiceLocked()2348 private IAccessibilityManager getServiceLocked() { 2349 if (mService == null) { 2350 tryConnectToServiceLocked(null); 2351 } 2352 return mService; 2353 } 2354 tryConnectToServiceLocked(IAccessibilityManager service)2355 private void tryConnectToServiceLocked(IAccessibilityManager service) { 2356 if (service == null) { 2357 IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE); 2358 if (iBinder == null) { 2359 return; 2360 } 2361 service = IAccessibilityManager.Stub.asInterface(iBinder); 2362 } 2363 2364 try { 2365 final long userStateAndRelevantEvents = service.addClient(mClient, mUserId); 2366 setStateLocked(IntPair.first(userStateAndRelevantEvents)); 2367 mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents); 2368 updateUiTimeout(service.getRecommendedTimeoutMillis()); 2369 updateFocusAppearanceLocked(service.getFocusStrokeWidth(), service.getFocusColor()); 2370 mService = service; 2371 } catch (RemoteException re) { 2372 Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); 2373 } 2374 } 2375 2376 /** 2377 * Notifies the registered {@link AccessibilityStateChangeListener}s. 2378 * 2379 * Note: this method notifies only the listeners of this single instance. 2380 * AccessibilityManagerService is responsible for calling this method on all of 2381 * its AccessibilityManager clients in order to notify all listeners. 2382 * @hide 2383 */ notifyAccessibilityStateChanged()2384 public void notifyAccessibilityStateChanged() { 2385 final boolean isEnabled; 2386 final ArrayMap<AccessibilityStateChangeListener, Handler> listeners; 2387 synchronized (mLock) { 2388 if (mAccessibilityStateChangeListeners.isEmpty()) { 2389 return; 2390 } 2391 isEnabled = isEnabled(); 2392 listeners = new ArrayMap<>(mAccessibilityStateChangeListeners); 2393 } 2394 2395 final int numListeners = listeners.size(); 2396 for (int i = 0; i < numListeners; i++) { 2397 final AccessibilityStateChangeListener listener = listeners.keyAt(i); 2398 listeners.valueAt(i).post(() -> 2399 listener.onAccessibilityStateChanged(isEnabled)); 2400 } 2401 } 2402 2403 /** 2404 * Notifies the registered {@link TouchExplorationStateChangeListener}s. 2405 */ notifyTouchExplorationStateChanged()2406 private void notifyTouchExplorationStateChanged() { 2407 final boolean isTouchExplorationEnabled; 2408 final ArrayMap<TouchExplorationStateChangeListener, Handler> listeners; 2409 synchronized (mLock) { 2410 if (mTouchExplorationStateChangeListeners.isEmpty()) { 2411 return; 2412 } 2413 isTouchExplorationEnabled = mIsTouchExplorationEnabled; 2414 listeners = new ArrayMap<>(mTouchExplorationStateChangeListeners); 2415 } 2416 2417 final int numListeners = listeners.size(); 2418 for (int i = 0; i < numListeners; i++) { 2419 final TouchExplorationStateChangeListener listener = listeners.keyAt(i); 2420 listeners.valueAt(i).post(() -> 2421 listener.onTouchExplorationStateChanged(isTouchExplorationEnabled)); 2422 } 2423 } 2424 2425 /** 2426 * Notifies the registered {@link HighContrastTextStateChangeListener}s. 2427 */ notifyHighContrastTextStateChanged()2428 private void notifyHighContrastTextStateChanged() { 2429 final boolean isHighTextContrastEnabled; 2430 final ArrayMap<HighContrastTextStateChangeListener, Executor> listeners; 2431 synchronized (mLock) { 2432 if (mHighContrastTextStateChangeListeners.isEmpty()) { 2433 return; 2434 } 2435 isHighTextContrastEnabled = mIsHighContrastTextEnabled; 2436 listeners = new ArrayMap<>(mHighContrastTextStateChangeListeners); 2437 } 2438 2439 final int numListeners = listeners.size(); 2440 for (int i = 0; i < numListeners; i++) { 2441 final HighContrastTextStateChangeListener listener = listeners.keyAt(i); 2442 listeners.valueAt(i).execute(() -> 2443 listener.onHighContrastTextStateChanged(isHighTextContrastEnabled)); 2444 } 2445 } 2446 2447 /** 2448 * Notifies the registered {@link AudioDescriptionStateChangeListener}s. 2449 */ notifyAudioDescriptionbyDefaultStateChanged()2450 private void notifyAudioDescriptionbyDefaultStateChanged() { 2451 final boolean isAudioDescriptionByDefaultRequested; 2452 final ArrayMap<AudioDescriptionRequestedChangeListener, Executor> listeners; 2453 synchronized (mLock) { 2454 if (mAudioDescriptionRequestedChangeListeners.isEmpty()) { 2455 return; 2456 } 2457 isAudioDescriptionByDefaultRequested = mIsAudioDescriptionByDefaultRequested; 2458 listeners = new ArrayMap<>(mAudioDescriptionRequestedChangeListeners); 2459 } 2460 2461 final int numListeners = listeners.size(); 2462 for (int i = 0; i < numListeners; i++) { 2463 final AudioDescriptionRequestedChangeListener listener = listeners.keyAt(i); 2464 listeners.valueAt(i).execute(() -> 2465 listener.onAudioDescriptionRequestedChanged( 2466 isAudioDescriptionByDefaultRequested)); 2467 } 2468 } 2469 2470 /** 2471 * Update mAccessibilityTracingState. 2472 */ updateAccessibilityTracingState(int stateFlag)2473 private void updateAccessibilityTracingState(int stateFlag) { 2474 synchronized (mLock) { 2475 mAccessibilityTracingState = stateFlag; 2476 } 2477 } 2478 2479 /** 2480 * Update interactive and non-interactive UI timeout. 2481 * 2482 * @param uiTimeout A pair of {@code int}s. First integer for interactive one, and second 2483 * integer for non-interactive one. 2484 */ updateUiTimeout(long uiTimeout)2485 private void updateUiTimeout(long uiTimeout) { 2486 mInteractiveUiTimeout = IntPair.first(uiTimeout); 2487 mNonInteractiveUiTimeout = IntPair.second(uiTimeout); 2488 } 2489 2490 /** 2491 * Updates the stroke width and color of the focus rectangle. 2492 * 2493 * @param strokeWidth The strokeWidth of the focus rectangle. 2494 * @param color The color of the focus rectangle. 2495 */ updateFocusAppearanceLocked(int strokeWidth, int color)2496 private void updateFocusAppearanceLocked(int strokeWidth, int color) { 2497 if (mFocusStrokeWidth == strokeWidth && mFocusColor == color) { 2498 return; 2499 } 2500 mFocusStrokeWidth = strokeWidth; 2501 mFocusColor = color; 2502 } 2503 2504 /** 2505 * Sets the stroke width and color of the focus rectangle to default value. 2506 * 2507 * @param resource The resources. 2508 */ initialFocusAppearanceLocked(Resources resource)2509 private void initialFocusAppearanceLocked(Resources resource) { 2510 try { 2511 mFocusStrokeWidth = resource.getDimensionPixelSize( 2512 R.dimen.accessibility_focus_highlight_stroke_width); 2513 mFocusColor = resource.getColor(R.color.accessibility_focus_highlight_color); 2514 } catch (Resources.NotFoundException re) { 2515 // Sets the stroke width and color to default value by hardcoded for making 2516 // the Talkback can work normally. 2517 mFocusStrokeWidth = (int) (4 * resource.getDisplayMetrics().density); 2518 mFocusColor = 0xbf39b500; 2519 Log.e(LOG_TAG, "Error while initialing the focus appearance data then setting to" 2520 + " default value by hardcoded", re); 2521 } 2522 } 2523 2524 /** 2525 * Determines if the accessibility button within the system navigation area is supported. 2526 * 2527 * @return {@code true} if the accessibility button is supported on this device, 2528 * {@code false} otherwise 2529 */ isAccessibilityButtonSupported()2530 public static boolean isAccessibilityButtonSupported() { 2531 final Resources res = Resources.getSystem(); 2532 return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); 2533 } 2534 2535 private final class MyCallback implements Handler.Callback { 2536 public static final int MSG_SET_STATE = 1; 2537 2538 @Override handleMessage(Message message)2539 public boolean handleMessage(Message message) { 2540 switch (message.what) { 2541 case MSG_SET_STATE: { 2542 // See comment at mClient 2543 final int state = message.arg1; 2544 synchronized (mLock) { 2545 setStateLocked(state); 2546 } 2547 } break; 2548 } 2549 return true; 2550 } 2551 } 2552 2553 /** 2554 * Retrieves the window's transformation matrix and magnification spec. 2555 * 2556 * <p> 2557 * Used by callers outside of the AccessibilityManagerService process which need 2558 * this information, like {@link android.view.accessibility.DirectAccessibilityConnection}. 2559 * </p> 2560 * 2561 * @return The transformation spec 2562 * @hide 2563 */ getWindowTransformationSpec( int windowId)2564 public IAccessibilityManager.WindowTransformationSpec getWindowTransformationSpec( 2565 int windowId) { 2566 final IAccessibilityManager service; 2567 synchronized (mLock) { 2568 service = getServiceLocked(); 2569 if (service == null) { 2570 return null; 2571 } 2572 } 2573 try { 2574 return service.getWindowTransformationSpec(windowId); 2575 } catch (RemoteException re) { 2576 throw re.rethrowFromSystemServer(); 2577 } 2578 } 2579 2580 /** 2581 * Attaches a {@link android.view.SurfaceControl} containing an accessibility overlay to the 2582 * specified display. 2583 * 2584 * @hide 2585 */ 2586 @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW) attachAccessibilityOverlayToDisplay( int displayId, @NonNull SurfaceControl surfaceControl)2587 public void attachAccessibilityOverlayToDisplay( 2588 int displayId, @NonNull SurfaceControl surfaceControl) { 2589 final IAccessibilityManager service; 2590 synchronized (mLock) { 2591 service = getServiceLocked(); 2592 if (service == null) { 2593 return; 2594 } 2595 } 2596 try { 2597 service.attachAccessibilityOverlayToDisplay( 2598 displayId, surfaceControl); 2599 } catch (RemoteException re) { 2600 throw re.rethrowFromSystemServer(); 2601 } 2602 } 2603 2604 /** 2605 * Notifies that the current a11y tiles in QuickSettings Panel has been changed 2606 * 2607 * @param userId The userId of the user attempts to change the qs panel. 2608 * @param tileComponentNames A list of Accessibility feature's TileServices' component names 2609 * and the a11y platform tiles' component names 2610 * @hide 2611 */ 2612 @RequiresPermission(Manifest.permission.STATUS_BAR_SERVICE) notifyQuickSettingsTilesChanged( @serIdInt int userId, List<ComponentName> tileComponentNames)2613 public void notifyQuickSettingsTilesChanged( 2614 @UserIdInt int userId, List<ComponentName> tileComponentNames) { 2615 final IAccessibilityManager service; 2616 synchronized (mLock) { 2617 service = getServiceLocked(); 2618 if (service == null) { 2619 return; 2620 } 2621 } 2622 try { 2623 service.notifyQuickSettingsTilesChanged(userId, tileComponentNames); 2624 } catch (RemoteException re) { 2625 throw re.rethrowFromSystemServer(); 2626 } 2627 } 2628 } 2629