1 /* 2 ** Copyright 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 com.android.server.accessibility; 18 19 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER; 20 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER_CLIENT; 21 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT; 22 import static android.accessibilityservice.AccessibilityTrace.FLAGS_FINGERPRINT; 23 import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER; 24 import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROADCAST_RECEIVER; 25 import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; 26 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MAGNIFICATION_CONNECTION; 27 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; 28 import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED; 29 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; 30 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY; 31 import static android.view.accessibility.AccessibilityManager.ShortcutType; 32 33 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME; 34 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; 35 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; 36 import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated; 37 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; 38 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 39 import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain; 40 41 import android.Manifest; 42 import android.accessibilityservice.AccessibilityGestureEvent; 43 import android.accessibilityservice.AccessibilityService; 44 import android.accessibilityservice.AccessibilityServiceInfo; 45 import android.accessibilityservice.AccessibilityShortcutInfo; 46 import android.accessibilityservice.IAccessibilityServiceClient; 47 import android.accessibilityservice.MagnificationConfig; 48 import android.accessibilityservice.TouchInteractionController; 49 import android.annotation.NonNull; 50 import android.annotation.Nullable; 51 import android.annotation.RequiresPermission; 52 import android.app.ActivityOptions; 53 import android.app.AlertDialog; 54 import android.app.PendingIntent; 55 import android.app.RemoteAction; 56 import android.appwidget.AppWidgetManagerInternal; 57 import android.content.ActivityNotFoundException; 58 import android.content.BroadcastReceiver; 59 import android.content.ComponentName; 60 import android.content.ContentResolver; 61 import android.content.Context; 62 import android.content.DialogInterface; 63 import android.content.DialogInterface.OnClickListener; 64 import android.content.Intent; 65 import android.content.IntentFilter; 66 import android.content.pm.PackageManager; 67 import android.content.pm.PackageManagerInternal; 68 import android.content.pm.ResolveInfo; 69 import android.content.pm.ServiceInfo; 70 import android.database.ContentObserver; 71 import android.graphics.Matrix; 72 import android.graphics.Point; 73 import android.graphics.Rect; 74 import android.graphics.Region; 75 import android.hardware.display.DisplayManager; 76 import android.hardware.fingerprint.IFingerprintService; 77 import android.media.AudioManagerInternal; 78 import android.net.Uri; 79 import android.os.Binder; 80 import android.os.Build; 81 import android.os.Bundle; 82 import android.os.Handler; 83 import android.os.IBinder; 84 import android.os.Looper; 85 import android.os.Message; 86 import android.os.PowerManager; 87 import android.os.Process; 88 import android.os.RemoteCallbackList; 89 import android.os.RemoteException; 90 import android.os.ResultReceiver; 91 import android.os.ServiceManager; 92 import android.os.ShellCallback; 93 import android.os.SystemClock; 94 import android.os.UserHandle; 95 import android.os.UserManager; 96 import android.provider.Settings; 97 import android.provider.SettingsStringUtil.SettingStringHelper; 98 import android.safetycenter.SafetyCenterManager; 99 import android.text.TextUtils; 100 import android.text.TextUtils.SimpleStringSplitter; 101 import android.util.ArraySet; 102 import android.util.IntArray; 103 import android.util.Pair; 104 import android.util.Slog; 105 import android.util.SparseArray; 106 import android.view.Display; 107 import android.view.IWindow; 108 import android.view.KeyEvent; 109 import android.view.MagnificationSpec; 110 import android.view.MotionEvent; 111 import android.view.WindowInfo; 112 import android.view.WindowManager; 113 import android.view.accessibility.AccessibilityEvent; 114 import android.view.accessibility.AccessibilityInteractionClient; 115 import android.view.accessibility.AccessibilityManager; 116 import android.view.accessibility.AccessibilityNodeInfo; 117 import android.view.accessibility.AccessibilityWindowInfo; 118 import android.view.accessibility.IAccessibilityInteractionConnection; 119 import android.view.accessibility.IAccessibilityManager; 120 import android.view.accessibility.IAccessibilityManagerClient; 121 import android.view.accessibility.IWindowMagnificationConnection; 122 import android.view.inputmethod.EditorInfo; 123 124 import com.android.internal.R; 125 import com.android.internal.accessibility.AccessibilityShortcutController; 126 import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo; 127 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; 128 import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity; 129 import com.android.internal.annotations.GuardedBy; 130 import com.android.internal.annotations.VisibleForTesting; 131 import com.android.internal.content.PackageMonitor; 132 import com.android.internal.inputmethod.IAccessibilityInputMethodSession; 133 import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; 134 import com.android.internal.os.BackgroundThread; 135 import com.android.internal.util.ArrayUtils; 136 import com.android.internal.util.DumpUtils; 137 import com.android.internal.util.IntPair; 138 import com.android.server.AccessibilityManagerInternal; 139 import com.android.server.LocalServices; 140 import com.android.server.SystemService; 141 import com.android.server.accessibility.magnification.MagnificationController; 142 import com.android.server.accessibility.magnification.MagnificationProcessor; 143 import com.android.server.accessibility.magnification.MagnificationScaleProvider; 144 import com.android.server.accessibility.magnification.WindowMagnificationManager; 145 import com.android.server.inputmethod.InputMethodManagerInternal; 146 import com.android.server.pm.UserManagerInternal; 147 import com.android.server.wm.ActivityTaskManagerInternal; 148 import com.android.server.wm.WindowManagerInternal; 149 150 import org.xmlpull.v1.XmlPullParserException; 151 152 import java.io.FileDescriptor; 153 import java.io.IOException; 154 import java.io.PrintWriter; 155 import java.util.ArrayList; 156 import java.util.Arrays; 157 import java.util.Collections; 158 import java.util.HashSet; 159 import java.util.Iterator; 160 import java.util.List; 161 import java.util.Map; 162 import java.util.Set; 163 import java.util.function.Consumer; 164 import java.util.function.Function; 165 import java.util.function.Predicate; 166 167 /** 168 * This class is instantiated by the system as a system level service and can be 169 * accessed only by the system. The task of this service is to be a centralized 170 * event dispatch for {@link AccessibilityEvent}s generated across all processes 171 * on the device. Events are dispatched to {@link AccessibilityService}s. 172 */ 173 public class AccessibilityManagerService extends IAccessibilityManager.Stub 174 implements AbstractAccessibilityServiceConnection.SystemSupport, 175 AccessibilityUserState.ServiceInfoChangeListener, 176 AccessibilityWindowManager.AccessibilityEventSender, 177 AccessibilitySecurityPolicy.AccessibilityUserManager, 178 SystemActionPerformer.SystemActionsChangedListener { 179 180 private static final boolean DEBUG = false; 181 182 private static final String LOG_TAG = "AccessibilityManagerService"; 183 184 // TODO: This is arbitrary. When there is time implement this by watching 185 // when that accessibility services are bound. 186 private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000; 187 188 // TODO: Restructure service initialization so services aren't connected before all of 189 // their capabilities are ready. 190 private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000; 191 192 193 // This postpones state changes events when a window doesn't exist with the expectation that 194 // a race condition will resolve. It is determined by observing elapsed time of the 195 // corresponding window added. 196 //TODO(b/230810909) : Fix it with a better idea. 197 private static final int POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS = 500; 198 199 private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE = 200 "registerUiTestAutomationService"; 201 202 private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED = 203 "temporaryEnableAccessibilityStateUntilKeyguardRemoved"; 204 205 private static final String GET_WINDOW_TOKEN = "getWindowToken"; 206 207 private static final String SET_PIP_ACTION_REPLACEMENT = 208 "setPictureInPictureActionReplacingConnection"; 209 210 private static final char COMPONENT_NAME_SEPARATOR = ':'; 211 212 private static final int OWN_PROCESS_ID = android.os.Process.myPid(); 213 214 public static final int INVALID_SERVICE_ID = -1; 215 216 // Each service has an ID. Also provide one for magnification gesture handling 217 public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0; 218 219 private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1; 220 221 private final Context mContext; 222 223 private final Object mLock = new Object(); 224 225 private final SimpleStringSplitter mStringColonSplitter = 226 new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); 227 228 private final Rect mTempRect = new Rect(); 229 private final Rect mTempRect1 = new Rect(); 230 231 private final PackageManager mPackageManager; 232 233 private final PowerManager mPowerManager; 234 235 private final WindowManagerInternal mWindowManagerService; 236 237 private final AccessibilitySecurityPolicy mSecurityPolicy; 238 239 private final AccessibilityWindowManager mA11yWindowManager; 240 241 private final AccessibilityDisplayListener mA11yDisplayListener; 242 243 private final ActivityTaskManagerInternal mActivityTaskManagerService; 244 245 private final MagnificationController mMagnificationController; 246 private final MagnificationProcessor mMagnificationProcessor; 247 248 private final MainHandler mMainHandler; 249 250 // Lazily initialized - access through getSystemActionPerformer() 251 private SystemActionPerformer mSystemActionPerformer; 252 253 private InteractionBridge mInteractionBridge; 254 255 private AlertDialog mEnableTouchExplorationDialog; 256 257 private AccessibilityInputFilter mInputFilter; 258 259 private boolean mHasInputFilter; 260 261 private KeyEventDispatcher mKeyEventDispatcher; 262 263 private SparseArray<MotionEventInjector> mMotionEventInjectors; 264 265 private FingerprintGestureDispatcher mFingerprintGestureDispatcher; 266 267 private final Set<ComponentName> mTempComponentNameSet = new HashSet<>(); 268 269 private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList = 270 new ArrayList<>(); 271 272 private final IntArray mTempIntArray = new IntArray(0); 273 274 private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients = 275 new RemoteCallbackList<>(); 276 277 @VisibleForTesting 278 final SparseArray<AccessibilityUserState> mUserStates = new SparseArray<>(); 279 280 private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock); 281 private final AccessibilityTraceManager mTraceManager; 282 private final CaptioningManagerImpl mCaptioningManagerImpl; 283 284 private final List<SendWindowStateChangedEventRunnable> mSendWindowStateChangedEventRunnables = 285 new ArrayList<>(); 286 287 private int mCurrentUserId = UserHandle.USER_SYSTEM; 288 289 //TODO: Remove this hack 290 private boolean mInitialized; 291 292 private Point mTempPoint = new Point(); 293 private boolean mIsAccessibilityButtonShown; 294 295 private boolean mInputBound; 296 IRemoteAccessibilityInputConnection mRemoteInputConnection; 297 EditorInfo mEditorInfo; 298 boolean mRestarting; 299 boolean mInputSessionRequested; 300 getCurrentUserStateLocked()301 private AccessibilityUserState getCurrentUserStateLocked() { 302 return getUserStateLocked(mCurrentUserId); 303 } 304 305 /** 306 * Changes the magnification mode on the given display. 307 * 308 * @param displayId the logical display 309 * @param magnificationMode the target magnification mode 310 */ changeMagnificationMode(int displayId, int magnificationMode)311 public void changeMagnificationMode(int displayId, int magnificationMode) { 312 synchronized (mLock) { 313 if (displayId == Display.DEFAULT_DISPLAY) { 314 persistMagnificationModeSettingsLocked(magnificationMode); 315 } else { 316 final AccessibilityUserState userState = getCurrentUserStateLocked(); 317 final int currentMode = userState.getMagnificationModeLocked(displayId); 318 if (magnificationMode != currentMode) { 319 userState.setMagnificationModeLocked(displayId, magnificationMode); 320 updateMagnificationModeChangeSettingsLocked(userState, displayId); 321 } 322 } 323 } 324 } 325 326 private static final class LocalServiceImpl extends AccessibilityManagerInternal { 327 @NonNull 328 private final AccessibilityManagerService mService; 329 LocalServiceImpl(@onNull AccessibilityManagerService service)330 LocalServiceImpl(@NonNull AccessibilityManagerService service) { 331 mService = service; 332 } 333 334 @Override setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)335 public void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, 336 boolean enabled) { 337 mService.scheduleSetImeSessionEnabled(sessions, enabled); 338 } 339 340 @Override unbindInput()341 public void unbindInput() { 342 mService.scheduleUnbindInput(); 343 } 344 345 @Override bindInput()346 public void bindInput() { 347 mService.scheduleBindInput(); 348 } 349 350 @Override createImeSession(ArraySet<Integer> ignoreSet)351 public void createImeSession(ArraySet<Integer> ignoreSet) { 352 mService.scheduleCreateImeSession(ignoreSet); 353 } 354 355 @Override startInput( IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, EditorInfo editorInfo, boolean restarting)356 public void startInput( 357 IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, 358 EditorInfo editorInfo, boolean restarting) { 359 mService.scheduleStartInput(remoteAccessibilityInputConnection, editorInfo, restarting); 360 } 361 } 362 363 public static final class Lifecycle extends SystemService { 364 private final AccessibilityManagerService mService; 365 Lifecycle(Context context)366 public Lifecycle(Context context) { 367 super(context); 368 mService = new AccessibilityManagerService(context); 369 } 370 371 @Override onStart()372 public void onStart() { 373 LocalServices.addService(AccessibilityManagerInternal.class, 374 new LocalServiceImpl(mService)); 375 publishBinderService(Context.ACCESSIBILITY_SERVICE, mService); 376 } 377 378 @Override onBootPhase(int phase)379 public void onBootPhase(int phase) { 380 mService.onBootPhase(phase); 381 } 382 } 383 384 @VisibleForTesting AccessibilityManagerService( Context context, PackageManager packageManager, AccessibilitySecurityPolicy securityPolicy, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager a11yWindowManager, AccessibilityDisplayListener a11yDisplayListener, MagnificationController magnificationController, @Nullable AccessibilityInputFilter inputFilter)385 AccessibilityManagerService( 386 Context context, 387 PackageManager packageManager, 388 AccessibilitySecurityPolicy securityPolicy, 389 SystemActionPerformer systemActionPerformer, 390 AccessibilityWindowManager a11yWindowManager, 391 AccessibilityDisplayListener a11yDisplayListener, 392 MagnificationController magnificationController, 393 @Nullable AccessibilityInputFilter inputFilter) { 394 mContext = context; 395 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 396 mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); 397 mTraceManager = AccessibilityTraceManager.getInstance( 398 mWindowManagerService.getAccessibilityController(), this, mLock); 399 mMainHandler = new MainHandler(mContext.getMainLooper()); 400 mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class); 401 mPackageManager = packageManager; 402 mSecurityPolicy = securityPolicy; 403 mSystemActionPerformer = systemActionPerformer; 404 mA11yWindowManager = a11yWindowManager; 405 mA11yDisplayListener = a11yDisplayListener; 406 mMagnificationController = magnificationController; 407 mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); 408 mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); 409 if (inputFilter != null) { 410 mInputFilter = inputFilter; 411 mHasInputFilter = true; 412 } 413 init(); 414 } 415 416 /** 417 * Creates a new instance. 418 * 419 * @param context A {@link Context} instance. 420 */ AccessibilityManagerService(Context context)421 public AccessibilityManagerService(Context context) { 422 mContext = context; 423 mPowerManager = context.getSystemService(PowerManager.class); 424 mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); 425 mTraceManager = AccessibilityTraceManager.getInstance( 426 mWindowManagerService.getAccessibilityController(), this, mLock); 427 mMainHandler = new MainHandler(mContext.getMainLooper()); 428 mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class); 429 mPackageManager = mContext.getPackageManager(); 430 final PolicyWarningUIController policyWarningUIController = new PolicyWarningUIController( 431 mMainHandler, context, 432 new PolicyWarningUIController.NotificationController(context)); 433 mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext, 434 this); 435 mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, 436 mWindowManagerService, this, mSecurityPolicy, this, mTraceManager); 437 mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); 438 mMagnificationController = new MagnificationController(this, mLock, mContext, 439 new MagnificationScaleProvider(mContext)); 440 mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); 441 mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); 442 init(); 443 } 444 init()445 private void init() { 446 mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager); 447 registerBroadcastReceivers(); 448 new AccessibilityContentObserver(mMainHandler).register( 449 mContext.getContentResolver()); 450 } 451 452 @Override getCurrentUserIdLocked()453 public int getCurrentUserIdLocked() { 454 return mCurrentUserId; 455 } 456 457 @Override isAccessibilityButtonShown()458 public boolean isAccessibilityButtonShown() { 459 return mIsAccessibilityButtonShown; 460 } 461 462 @Override getWindowTransformationMatrixAndMagnificationSpec( int windowId)463 public Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec( 464 int windowId) { 465 WindowInfo windowInfo; 466 synchronized (mLock) { 467 windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(windowId); 468 } 469 if (windowInfo != null) { 470 final MagnificationSpec spec = new MagnificationSpec(); 471 spec.setTo(windowInfo.mMagnificationSpec); 472 return new Pair<>(windowInfo.mTransformMatrix, spec); 473 } else { 474 // If the framework doesn't track windows, we fall back to get the pair of 475 // transformation matrix and MagnificationSpe from the WindowManagerService's 476 // WindowState. 477 IBinder token; 478 synchronized (mLock) { 479 token = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(mCurrentUserId, 480 windowId); 481 } 482 Pair<Matrix, MagnificationSpec> pair = 483 mWindowManagerService.getWindowTransformationMatrixAndMagnificationSpec(token); 484 final float[] outTransformationMatrix = new float[9]; 485 final Matrix tmpMatrix = pair.first; 486 final MagnificationSpec spec = pair.second; 487 if (!spec.isNop()) { 488 tmpMatrix.postScale(spec.scale, spec.scale); 489 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY); 490 } 491 tmpMatrix.getValues(outTransformationMatrix); 492 493 return new Pair<>(outTransformationMatrix, pair.second); 494 } 495 } 496 497 @Override onServiceInfoChangedLocked(AccessibilityUserState userState)498 public void onServiceInfoChangedLocked(AccessibilityUserState userState) { 499 mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId, 500 userState.mBoundServices); 501 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 502 } 503 504 @Nullable getFingerprintGestureDispatcher()505 public FingerprintGestureDispatcher getFingerprintGestureDispatcher() { 506 return mFingerprintGestureDispatcher; 507 } 508 onBootPhase(int phase)509 private void onBootPhase(int phase) { 510 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 511 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) { 512 mSecurityPolicy.setAppWidgetManager( 513 LocalServices.getService(AppWidgetManagerInternal.class)); 514 } 515 } 516 517 // SafetyCenterService is ready after this phase. 518 if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 519 setNonA11yToolNotificationToMatchSafetyCenter(); 520 } 521 } 522 setNonA11yToolNotificationToMatchSafetyCenter()523 private void setNonA11yToolNotificationToMatchSafetyCenter() { 524 final boolean sendNotification = !mContext.getSystemService( 525 SafetyCenterManager.class).isSafetyCenterEnabled(); 526 synchronized (mLock) { 527 mSecurityPolicy.setSendingNonA11yToolNotificationLocked(sendNotification); 528 } 529 } 530 getCurrentUserState()531 AccessibilityUserState getCurrentUserState() { 532 synchronized (mLock) { 533 return getCurrentUserStateLocked(); 534 } 535 } 536 getUserState(int userId)537 private AccessibilityUserState getUserState(int userId) { 538 synchronized (mLock) { 539 return getUserStateLocked(userId); 540 } 541 } 542 543 @NonNull getUserStateLocked(int userId)544 private AccessibilityUserState getUserStateLocked(int userId) { 545 AccessibilityUserState state = mUserStates.get(userId); 546 if (state == null) { 547 state = new AccessibilityUserState(userId, mContext, this); 548 mUserStates.put(userId, state); 549 } 550 return state; 551 } 552 getBindInstantServiceAllowed(int userId)553 boolean getBindInstantServiceAllowed(int userId) { 554 synchronized (mLock) { 555 final AccessibilityUserState userState = getUserStateLocked(userId); 556 return userState.getBindInstantServiceAllowedLocked(); 557 } 558 } 559 setBindInstantServiceAllowed(int userId, boolean allowed)560 void setBindInstantServiceAllowed(int userId, boolean allowed) { 561 mContext.enforceCallingOrSelfPermission( 562 Manifest.permission.MANAGE_BIND_INSTANT_SERVICE, 563 "setBindInstantServiceAllowed"); 564 synchronized (mLock) { 565 final AccessibilityUserState userState = getUserStateLocked(userId); 566 if (allowed != userState.getBindInstantServiceAllowedLocked()) { 567 userState.setBindInstantServiceAllowedLocked(allowed); 568 onUserStateChangedLocked(userState); 569 } 570 } 571 } 572 registerBroadcastReceivers()573 private void registerBroadcastReceivers() { 574 PackageMonitor monitor = new PackageMonitor() { 575 @Override 576 public void onSomePackagesChanged() { 577 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 578 mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged", 579 FLAGS_PACKAGE_BROADCAST_RECEIVER); 580 } 581 582 synchronized (mLock) { 583 // Only the profile parent can install accessibility services. 584 // Therefore we ignore packages from linked profiles. 585 if (getChangingUserId() != mCurrentUserId) { 586 return; 587 } 588 // We will update when the automation service dies. 589 final AccessibilityUserState userState = getCurrentUserStateLocked(); 590 // We have to reload the installed services since some services may 591 // have different attributes, resolve info (does not support equals), 592 // etc. Remove them then to force reload. 593 userState.mInstalledServices.clear(); 594 if (readConfigurationForUserStateLocked(userState)) { 595 onUserStateChangedLocked(userState); 596 } 597 } 598 } 599 600 @Override 601 public void onPackageUpdateFinished(String packageName, int uid) { 602 // The package should already be removed from mBoundServices, and added into 603 // mBindingServices in binderDied() during updating. Remove services from this 604 // package from mBindingServices, and then update the user state to re-bind new 605 // versions of them. 606 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 607 mTraceManager.logTrace(LOG_TAG + ".PM.onPackageUpdateFinished", 608 FLAGS_PACKAGE_BROADCAST_RECEIVER, 609 "packageName=" + packageName + ";uid=" + uid); 610 } 611 synchronized (mLock) { 612 final int userId = getChangingUserId(); 613 if (userId != mCurrentUserId) { 614 return; 615 } 616 final AccessibilityUserState userState = getUserStateLocked(userId); 617 final boolean reboundAService = userState.getBindingServicesLocked().removeIf( 618 component -> component != null 619 && component.getPackageName().equals(packageName)) 620 || userState.mCrashedServices.removeIf(component -> component != null 621 && component.getPackageName().equals(packageName)); 622 // Reloads the installed services info to make sure the rebound service could 623 // get a new one. 624 userState.mInstalledServices.clear(); 625 final boolean configurationChanged = 626 readConfigurationForUserStateLocked(userState); 627 if (reboundAService || configurationChanged) { 628 onUserStateChangedLocked(userState); 629 } 630 // Passing 0 for restoreFromSdkInt to have this migration check execute each 631 // time. It can make sure a11y button settings are correctly if there's an a11y 632 // service updated and modifies the a11y button configuration. 633 migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName, 634 /* restoreFromSdkInt = */0); 635 } 636 } 637 638 @Override 639 public void onPackageRemoved(String packageName, int uid) { 640 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 641 mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved", 642 FLAGS_PACKAGE_BROADCAST_RECEIVER, 643 "packageName=" + packageName + ";uid=" + uid); 644 } 645 646 synchronized (mLock) { 647 final int userId = getChangingUserId(); 648 // Only the profile parent can install accessibility services. 649 // Therefore we ignore packages from linked profiles. 650 if (userId != mCurrentUserId) { 651 return; 652 } 653 final AccessibilityUserState userState = getUserStateLocked(userId); 654 final Predicate<ComponentName> filter = 655 component -> component != null && component.getPackageName().equals( 656 packageName); 657 userState.mBindingServices.removeIf(filter); 658 userState.mCrashedServices.removeIf(filter); 659 final Iterator<ComponentName> it = userState.mEnabledServices.iterator(); 660 boolean anyServiceRemoved = false; 661 while (it.hasNext()) { 662 final ComponentName comp = it.next(); 663 final String compPkg = comp.getPackageName(); 664 if (compPkg.equals(packageName)) { 665 it.remove(); 666 userState.mTouchExplorationGrantedServices.remove(comp); 667 anyServiceRemoved = true; 668 } 669 } 670 if (anyServiceRemoved) { 671 // Update the enabled services setting. 672 persistComponentNamesToSettingLocked( 673 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 674 userState.mEnabledServices, userId); 675 // Update the touch exploration granted services setting. 676 persistComponentNamesToSettingLocked( 677 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 678 userState.mTouchExplorationGrantedServices, userId); 679 onUserStateChangedLocked(userState); 680 } 681 } 682 } 683 684 @Override 685 public boolean onHandleForceStop(Intent intent, String[] packages, 686 int uid, boolean doit) { 687 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 688 mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop", 689 FLAGS_PACKAGE_BROADCAST_RECEIVER, 690 "intent=" + intent + ";packages=" + packages + ";uid=" + uid 691 + ";doit=" + doit); 692 } 693 synchronized (mLock) { 694 final int userId = getChangingUserId(); 695 // Only the profile parent can install accessibility services. 696 // Therefore we ignore packages from linked profiles. 697 if (userId != mCurrentUserId) { 698 return false; 699 } 700 final AccessibilityUserState userState = getUserStateLocked(userId); 701 final Iterator<ComponentName> it = userState.mEnabledServices.iterator(); 702 while (it.hasNext()) { 703 final ComponentName comp = it.next(); 704 final String compPkg = comp.getPackageName(); 705 for (String pkg : packages) { 706 if (compPkg.equals(pkg)) { 707 if (!doit) { 708 return true; 709 } 710 it.remove(); 711 userState.getBindingServicesLocked().remove(comp); 712 userState.getCrashedServicesLocked().remove(comp); 713 persistComponentNamesToSettingLocked( 714 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 715 userState.mEnabledServices, userId); 716 onUserStateChangedLocked(userState); 717 } 718 } 719 } 720 return false; 721 } 722 } 723 }; 724 725 // package changes 726 monitor.register(mContext, null, UserHandle.ALL, true); 727 728 // user change and unlock 729 IntentFilter intentFilter = new IntentFilter(); 730 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 731 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); 732 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 733 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 734 intentFilter.addAction(Intent.ACTION_SETTING_RESTORED); 735 736 mContext.registerReceiverAsUser(new BroadcastReceiver() { 737 @Override 738 public void onReceive(Context context, Intent intent) { 739 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_USER_BROADCAST_RECEIVER)) { 740 mTraceManager.logTrace(LOG_TAG + ".BR.onReceive", FLAGS_USER_BROADCAST_RECEIVER, 741 "context=" + context + ";intent=" + intent); 742 } 743 744 String action = intent.getAction(); 745 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 746 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 747 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { 748 unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 749 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 750 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 751 } else if (Intent.ACTION_USER_PRESENT.equals(action)) { 752 // We will update when the automation service dies. 753 synchronized (mLock) { 754 AccessibilityUserState userState = getCurrentUserStateLocked(); 755 if (readConfigurationForUserStateLocked(userState)) { 756 onUserStateChangedLocked(userState); 757 } 758 } 759 } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { 760 final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); 761 if (Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(which)) { 762 synchronized (mLock) { 763 restoreEnabledAccessibilityServicesLocked( 764 intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE), 765 intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE), 766 intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 767 0)); 768 } 769 } else if (ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(which)) { 770 synchronized (mLock) { 771 restoreLegacyDisplayMagnificationNavBarIfNeededLocked( 772 intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE), 773 intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 774 0)); 775 } 776 } else if (Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS.equals(which)) { 777 synchronized (mLock) { 778 restoreAccessibilityButtonTargetsLocked( 779 intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE), 780 intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE)); 781 } 782 } 783 } 784 } 785 }, UserHandle.ALL, intentFilter, null, null); 786 787 final IntentFilter filter = new IntentFilter(); 788 filter.addAction(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED); 789 final BroadcastReceiver receiver = new BroadcastReceiver() { 790 @Override 791 public void onReceive(Context context, Intent intent) { 792 setNonA11yToolNotificationToMatchSafetyCenter(); 793 } 794 }; 795 mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, mMainHandler, 796 Context.RECEIVER_EXPORTED); 797 } 798 799 // Called only during settings restore; currently supports only the owner user 800 // TODO: b/22388012 restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, int restoreFromSdkInt)801 private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, 802 int restoreFromSdkInt) { 803 if (restoreFromSdkInt >= Build.VERSION_CODES.R) { 804 return; 805 } 806 807 boolean displayMagnificationNavBarEnabled; 808 try { 809 displayMagnificationNavBarEnabled = Integer.parseInt(newSetting) == 1; 810 } catch (NumberFormatException e) { 811 Slog.w(LOG_TAG, "number format is incorrect" + e); 812 return; 813 } 814 815 final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 816 final Set<String> targetsFromSetting = new ArraySet<>(); 817 readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 818 userState.mUserId, str -> str, targetsFromSetting); 819 final boolean targetsContainMagnification = targetsFromSetting.contains( 820 MAGNIFICATION_CONTROLLER_NAME); 821 if (targetsContainMagnification == displayMagnificationNavBarEnabled) { 822 return; 823 } 824 825 if (displayMagnificationNavBarEnabled) { 826 targetsFromSetting.add(MAGNIFICATION_CONTROLLER_NAME); 827 } else { 828 targetsFromSetting.remove(MAGNIFICATION_CONTROLLER_NAME); 829 } 830 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 831 userState.mUserId, targetsFromSetting, str -> str); 832 readAccessibilityButtonTargetsLocked(userState); 833 onUserStateChangedLocked(userState); 834 } 835 836 @Override addClient(IAccessibilityManagerClient callback, int userId)837 public long addClient(IAccessibilityManagerClient callback, int userId) { 838 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 839 mTraceManager.logTrace(LOG_TAG + ".addClient", FLAGS_ACCESSIBILITY_MANAGER, 840 "callback=" + callback + ";userId=" + userId); 841 } 842 843 synchronized (mLock) { 844 // We treat calls from a profile as if made by its parent as profiles 845 // share the accessibility state of the parent. The call below 846 // performs the current profile parent resolution. 847 final int resolvedUserId = mSecurityPolicy 848 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 849 850 // If the client is from a process that runs across users such as 851 // the system UI or the system we add it to the global state that 852 // is shared across users. 853 AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 854 Client client = new Client(callback, Binder.getCallingUid(), userState); 855 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 856 mGlobalClients.register(callback, client); 857 if (DEBUG) { 858 Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); 859 } 860 return IntPair.of( 861 getClientStateLocked(userState), 862 client.mLastSentRelevantEventTypes); 863 } else { 864 userState.mUserClients.register(callback, client); 865 // If this client is not for the current user we do not 866 // return a state since it is not for the foreground user. 867 // We will send the state to the client on a user switch. 868 if (DEBUG) { 869 Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid() 870 + " and userId:" + mCurrentUserId); 871 } 872 return IntPair.of( 873 (resolvedUserId == mCurrentUserId) ? getClientStateLocked(userState) : 0, 874 client.mLastSentRelevantEventTypes); 875 } 876 } 877 } 878 879 @Override removeClient(IAccessibilityManagerClient callback, int userId)880 public boolean removeClient(IAccessibilityManagerClient callback, int userId) { 881 // TODO(b/190216606): Add tracing for removeClient when implementation is the same in master 882 883 synchronized (mLock) { 884 final int resolvedUserId = mSecurityPolicy 885 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 886 887 AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 888 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 889 boolean unregistered = mGlobalClients.unregister(callback); 890 if (DEBUG) { 891 Slog.i(LOG_TAG, 892 "Removed global client for pid:" + Binder.getCallingPid() + "state: " 893 + unregistered); 894 } 895 return unregistered; 896 } else { 897 boolean unregistered = userState.mUserClients.unregister(callback); 898 if (DEBUG) { 899 Slog.i(LOG_TAG, "Removed user client for pid:" + Binder.getCallingPid() 900 + " and userId:" + resolvedUserId + "state: " + unregistered); 901 } 902 return unregistered; 903 } 904 } 905 } 906 907 @Override sendAccessibilityEvent(AccessibilityEvent event, int userId)908 public void sendAccessibilityEvent(AccessibilityEvent event, int userId) { 909 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 910 mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEvent", FLAGS_ACCESSIBILITY_MANAGER, 911 "event=" + event + ";userId=" + userId); 912 } 913 boolean dispatchEvent = false; 914 int resolvedUserId; 915 916 synchronized (mLock) { 917 if (event.getWindowId() == 918 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) { 919 // The replacer window isn't shown to services. Move its events into the pip. 920 AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked(); 921 if (pip != null) { 922 int pipId = pip.getId(); 923 event.setWindowId(pipId); 924 } 925 } 926 927 // We treat calls from a profile as if made by its parent as profiles 928 // share the accessibility state of the parent. The call below 929 // performs the current profile parent resolution. 930 resolvedUserId = mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId); 931 932 // Make sure the reported package is one the caller has access to. 933 event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked( 934 event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId, 935 getCallingPid())); 936 937 // This method does nothing for a background user. 938 if (resolvedUserId == mCurrentUserId) { 939 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(mCurrentUserId, event)) { 940 mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked( 941 mCurrentUserId, event.getWindowId(), event.getSourceNodeId(), 942 event.getEventType(), event.getAction()); 943 mSecurityPolicy.updateEventSourceLocked(event); 944 dispatchEvent = true; 945 } 946 if (mHasInputFilter && mInputFilter != null) { 947 mMainHandler.sendMessage(obtainMessage( 948 AccessibilityManagerService::sendAccessibilityEventToInputFilter, 949 this, AccessibilityEvent.obtain(event))); 950 } 951 } 952 } 953 954 if (dispatchEvent) { 955 // Make sure clients receiving this event will be able to get the 956 // current state of the windows as the window manager may be delaying 957 // the computation for performance reasons. 958 boolean shouldComputeWindows = false; 959 int displayId = Display.INVALID_DISPLAY; 960 synchronized (mLock) { 961 final int windowId = event.getWindowId(); 962 if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { 963 displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked( 964 resolvedUserId, windowId); 965 event.setDisplayId(displayId); 966 } 967 968 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 969 && displayId != Display.INVALID_DISPLAY 970 && mA11yWindowManager.isTrackingWindowsLocked(displayId)) { 971 shouldComputeWindows = true; 972 } 973 } 974 if (shouldComputeWindows) { 975 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) { 976 mTraceManager.logTrace("WindowManagerInternal.computeWindowsForAccessibility", 977 FLAGS_WINDOW_MANAGER_INTERNAL, "display=" + displayId); 978 } 979 final WindowManagerInternal wm = LocalServices.getService( 980 WindowManagerInternal.class); 981 wm.computeWindowsForAccessibility(displayId); 982 // The App side sends a event to notify that the window visible or focused, 983 // but the window information in framework is not updated yet, so we postpone it. 984 if (postponeWindowStateEvent(event)) { 985 return; 986 } 987 } 988 989 synchronized (mLock) { 990 dispatchAccessibilityEventLocked(event); 991 } 992 } 993 994 if (OWN_PROCESS_ID != Binder.getCallingPid()) { 995 event.recycle(); 996 } 997 } 998 dispatchAccessibilityEventLocked(AccessibilityEvent event)999 private void dispatchAccessibilityEventLocked(AccessibilityEvent event) { 1000 notifyAccessibilityServicesDelayedLocked(event, false); 1001 notifyAccessibilityServicesDelayedLocked(event, true); 1002 mUiAutomationManager.sendAccessibilityEventLocked(event); 1003 } 1004 sendAccessibilityEventToInputFilter(AccessibilityEvent event)1005 private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) { 1006 synchronized (mLock) { 1007 if (mHasInputFilter && mInputFilter != null) { 1008 mInputFilter.notifyAccessibilityEvent(event); 1009 } 1010 } 1011 event.recycle(); 1012 } 1013 1014 /** 1015 * This is the implementation of AccessibilityManager system API. 1016 * System UI calls into this method through AccessibilityManager system API to register a 1017 * system action. 1018 */ 1019 @Override registerSystemAction(RemoteAction action, int actionId)1020 public void registerSystemAction(RemoteAction action, int actionId) { 1021 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1022 mTraceManager.logTrace(LOG_TAG + ".registerSystemAction", 1023 FLAGS_ACCESSIBILITY_MANAGER, "action=" + action + ";actionId=" + actionId); 1024 } 1025 mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY); 1026 getSystemActionPerformer().registerSystemAction(actionId, action); 1027 } 1028 1029 /** 1030 * This is the implementation of AccessibilityManager system API. 1031 * System UI calls into this method through AccessibilityManager system API to unregister a 1032 * system action. 1033 */ 1034 @Override unregisterSystemAction(int actionId)1035 public void unregisterSystemAction(int actionId) { 1036 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1037 mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction", 1038 FLAGS_ACCESSIBILITY_MANAGER, "actionId=" + actionId); 1039 } 1040 mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY); 1041 getSystemActionPerformer().unregisterSystemAction(actionId); 1042 } 1043 getSystemActionPerformer()1044 private SystemActionPerformer getSystemActionPerformer() { 1045 if (mSystemActionPerformer == null) { 1046 mSystemActionPerformer = 1047 new SystemActionPerformer(mContext, mWindowManagerService, null, this); 1048 } 1049 return mSystemActionPerformer; 1050 } 1051 1052 @Override getInstalledAccessibilityServiceList(int userId)1053 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { 1054 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1055 mTraceManager.logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList", 1056 FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId); 1057 } 1058 1059 final int resolvedUserId; 1060 final List<AccessibilityServiceInfo> serviceInfos; 1061 synchronized (mLock) { 1062 // We treat calls from a profile as if made by its parent as profiles 1063 // share the accessibility state of the parent. The call below 1064 // performs the current profile parent resolution. 1065 resolvedUserId = mSecurityPolicy 1066 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1067 serviceInfos = new ArrayList<>( 1068 getUserStateLocked(resolvedUserId).mInstalledServices); 1069 } 1070 1071 if (Binder.getCallingPid() == OWN_PROCESS_ID) { 1072 return serviceInfos; 1073 } 1074 final PackageManagerInternal pm = LocalServices.getService( 1075 PackageManagerInternal.class); 1076 final int callingUid = Binder.getCallingUid(); 1077 for (int i = serviceInfos.size() - 1; i >= 0; i--) { 1078 final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i); 1079 if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid, 1080 resolvedUserId)) { 1081 serviceInfos.remove(i); 1082 } 1083 } 1084 return serviceInfos; 1085 } 1086 1087 @Override getEnabledAccessibilityServiceList(int feedbackType, int userId)1088 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, 1089 int userId) { 1090 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1091 mTraceManager.logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList", 1092 FLAGS_ACCESSIBILITY_MANAGER, 1093 "feedbackType=" + feedbackType + ";userId=" + userId); 1094 } 1095 1096 synchronized (mLock) { 1097 // We treat calls from a profile as if made by its parent as profiles 1098 // share the accessibility state of the parent. The call below 1099 // performs the current profile parent resolution. 1100 final int resolvedUserId = mSecurityPolicy 1101 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1102 1103 // The automation service can suppress other services. 1104 final AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 1105 if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) { 1106 return Collections.emptyList(); 1107 } 1108 1109 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 1110 final int serviceCount = services.size(); 1111 final List<AccessibilityServiceInfo> result = new ArrayList<>(serviceCount); 1112 for (int i = 0; i < serviceCount; ++i) { 1113 final AccessibilityServiceConnection service = services.get(i); 1114 if ((service.mFeedbackType & feedbackType) != 0 1115 || feedbackType == AccessibilityServiceInfo.FEEDBACK_ALL_MASK) { 1116 result.add(service.getServiceInfo()); 1117 } 1118 } 1119 return result; 1120 } 1121 } 1122 1123 @Override interrupt(int userId)1124 public void interrupt(int userId) { 1125 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1126 mTraceManager.logTrace(LOG_TAG + ".interrupt", 1127 FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId); 1128 } 1129 1130 List<IAccessibilityServiceClient> interfacesToInterrupt; 1131 synchronized (mLock) { 1132 // We treat calls from a profile as if made by its parent as profiles 1133 // share the accessibility state of the parent. The call below 1134 // performs the current profile parent resolution. 1135 final int resolvedUserId = mSecurityPolicy 1136 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1137 // This method does nothing for a background user. 1138 if (resolvedUserId != mCurrentUserId) { 1139 return; 1140 } 1141 List<AccessibilityServiceConnection> services = 1142 getUserStateLocked(resolvedUserId).mBoundServices; 1143 int numServices = services.size(); 1144 interfacesToInterrupt = new ArrayList<>(numServices); 1145 for (int i = 0; i < numServices; i++) { 1146 AccessibilityServiceConnection service = services.get(i); 1147 IBinder a11yServiceBinder = service.mService; 1148 IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface; 1149 if ((a11yServiceBinder != null) && (a11yServiceInterface != null)) { 1150 interfacesToInterrupt.add(a11yServiceInterface); 1151 } 1152 } 1153 } 1154 for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) { 1155 try { 1156 if (mTraceManager.isA11yTracingEnabledForTypes( 1157 FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 1158 mTraceManager.logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt", 1159 FLAGS_ACCESSIBILITY_SERVICE_CLIENT); 1160 } 1161 interfacesToInterrupt.get(i).onInterrupt(); 1162 } catch (RemoteException re) { 1163 Slog.e(LOG_TAG, "Error sending interrupt request to " 1164 + interfacesToInterrupt.get(i), re); 1165 } 1166 } 1167 } 1168 1169 @Override addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, IAccessibilityInteractionConnection connection, String packageName, int userId)1170 public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, 1171 IAccessibilityInteractionConnection connection, String packageName, 1172 int userId) throws RemoteException { 1173 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1174 mTraceManager.logTrace(LOG_TAG + ".addAccessibilityInteractionConnection", 1175 FLAGS_ACCESSIBILITY_MANAGER, 1176 "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection=" 1177 + connection + "; packageName=" + packageName + ";userId=" + userId); 1178 } 1179 1180 return mA11yWindowManager.addAccessibilityInteractionConnection( 1181 windowToken, leashToken, connection, packageName, userId); 1182 } 1183 1184 @Override removeAccessibilityInteractionConnection(IWindow window)1185 public void removeAccessibilityInteractionConnection(IWindow window) { 1186 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1187 mTraceManager.logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection", 1188 FLAGS_ACCESSIBILITY_MANAGER, "window=" + window); 1189 } 1190 mA11yWindowManager.removeAccessibilityInteractionConnection(window); 1191 } 1192 1193 @Override setPictureInPictureActionReplacingConnection( IAccessibilityInteractionConnection connection)1194 public void setPictureInPictureActionReplacingConnection( 1195 IAccessibilityInteractionConnection connection) throws RemoteException { 1196 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1197 mTraceManager.logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection", 1198 FLAGS_ACCESSIBILITY_MANAGER, "connection=" + connection); 1199 } 1200 mSecurityPolicy.enforceCallingPermission(Manifest.permission.MODIFY_ACCESSIBILITY_DATA, 1201 SET_PIP_ACTION_REPLACEMENT); 1202 mA11yWindowManager.setPictureInPictureActionReplacingConnection(connection); 1203 } 1204 1205 @Override registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo, int flags)1206 public void registerUiTestAutomationService(IBinder owner, 1207 IAccessibilityServiceClient serviceClient, 1208 AccessibilityServiceInfo accessibilityServiceInfo, 1209 int flags) { 1210 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1211 mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService", 1212 FLAGS_ACCESSIBILITY_MANAGER, 1213 "owner=" + owner + ";serviceClient=" + serviceClient 1214 + ";accessibilityServiceInfo=" + accessibilityServiceInfo + ";flags=" + flags); 1215 } 1216 1217 mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, 1218 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE); 1219 1220 synchronized (mLock) { 1221 mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient, 1222 mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler, 1223 mSecurityPolicy, this, getTraceManager(), mWindowManagerService, 1224 getSystemActionPerformer(), mA11yWindowManager, flags); 1225 onUserStateChangedLocked(getCurrentUserStateLocked()); 1226 } 1227 } 1228 1229 @Override unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)1230 public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { 1231 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1232 mTraceManager.logTrace(LOG_TAG + ".unregisterUiTestAutomationService", 1233 FLAGS_ACCESSIBILITY_MANAGER, "serviceClient=" + serviceClient); 1234 } 1235 synchronized (mLock) { 1236 mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient); 1237 } 1238 } 1239 1240 @Override temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled)1241 public void temporaryEnableAccessibilityStateUntilKeyguardRemoved( 1242 ComponentName service, boolean touchExplorationEnabled) { 1243 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1244 mTraceManager.logTrace( 1245 LOG_TAG + ".temporaryEnableAccessibilityStateUntilKeyguardRemoved", 1246 FLAGS_ACCESSIBILITY_MANAGER, 1247 "service=" + service + ";touchExplorationEnabled=" + touchExplorationEnabled); 1248 } 1249 1250 mSecurityPolicy.enforceCallingPermission( 1251 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY, 1252 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED); 1253 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) { 1254 mTraceManager.logTrace("WindowManagerInternal.isKeyguardLocked", 1255 FLAGS_WINDOW_MANAGER_INTERNAL); 1256 } 1257 if (!mWindowManagerService.isKeyguardLocked()) { 1258 return; 1259 } 1260 synchronized (mLock) { 1261 // Set the temporary state. 1262 AccessibilityUserState userState = getCurrentUserStateLocked(); 1263 1264 userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); 1265 userState.setDisplayMagnificationEnabledLocked(false); 1266 userState.disableShortcutMagnificationLocked(); 1267 userState.setAutoclickEnabledLocked(false); 1268 userState.mEnabledServices.clear(); 1269 userState.mEnabledServices.add(service); 1270 userState.getBindingServicesLocked().clear(); 1271 userState.getCrashedServicesLocked().clear(); 1272 userState.mTouchExplorationGrantedServices.clear(); 1273 userState.mTouchExplorationGrantedServices.add(service); 1274 1275 // User the current state instead settings. 1276 onUserStateChangedLocked(userState); 1277 } 1278 } 1279 1280 @Override getWindowToken(int windowId, int userId)1281 public IBinder getWindowToken(int windowId, int userId) { 1282 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1283 mTraceManager.logTrace(LOG_TAG + ".getWindowToken", 1284 FLAGS_ACCESSIBILITY_MANAGER, "windowId=" + windowId + ";userId=" + userId); 1285 } 1286 1287 mSecurityPolicy.enforceCallingPermission( 1288 Manifest.permission.RETRIEVE_WINDOW_TOKEN, 1289 GET_WINDOW_TOKEN); 1290 synchronized (mLock) { 1291 // We treat calls from a profile as if made by its parent as profiles 1292 // share the accessibility state of the parent. The call below 1293 // performs the current profile parent resolution. 1294 final int resolvedUserId = mSecurityPolicy 1295 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1296 if (resolvedUserId != mCurrentUserId) { 1297 return null; 1298 } 1299 final AccessibilityWindowInfo accessibilityWindowInfo = mA11yWindowManager 1300 .findA11yWindowInfoByIdLocked(windowId); 1301 if (accessibilityWindowInfo == null) { 1302 return null; 1303 } 1304 // We use AccessibilityWindowInfo#getId instead of windowId. When the windowId comes 1305 // from an embedded hierarchy, the system can't find correct window token because 1306 // embedded hierarchy doesn't have windowInfo. Calling 1307 // AccessibilityWindowManager#findA11yWindowInfoByIdLocked can look for its parent's 1308 // windowInfo, so it is safer to use AccessibilityWindowInfo#getId 1309 // to get window token to find real window. 1310 return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, 1311 accessibilityWindowInfo.getId()); 1312 } 1313 } 1314 1315 /** 1316 * Invoked remotely over AIDL by SysUi when the accessibility button within the system's 1317 * navigation area has been clicked. 1318 * 1319 * @param displayId The logical display id. 1320 * @param targetName The flattened {@link ComponentName} string or the class name of a system 1321 * class implementing a supported accessibility feature, or {@code null} if there's no 1322 * specified target. 1323 */ 1324 @Override notifyAccessibilityButtonClicked(int displayId, String targetName)1325 public void notifyAccessibilityButtonClicked(int displayId, String targetName) { 1326 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1327 mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked", 1328 FLAGS_ACCESSIBILITY_MANAGER, 1329 "displayId=" + displayId + ";targetName=" + targetName); 1330 } 1331 1332 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE) 1333 != PackageManager.PERMISSION_GRANTED) { 1334 throw new SecurityException("Caller does not hold permission " 1335 + android.Manifest.permission.STATUS_BAR_SERVICE); 1336 } 1337 if (targetName == null) { 1338 synchronized (mLock) { 1339 final AccessibilityUserState userState = getCurrentUserStateLocked(); 1340 targetName = userState.getTargetAssignedToAccessibilityButton(); 1341 } 1342 } 1343 mMainHandler.sendMessage(obtainMessage( 1344 AccessibilityManagerService::performAccessibilityShortcutInternal, this, 1345 displayId, ACCESSIBILITY_BUTTON, targetName)); 1346 } 1347 1348 /** 1349 * Invoked remotely over AIDL by SysUi when the visibility of the accessibility 1350 * button within the system's navigation area has changed. 1351 * 1352 * @param shown {@code true} if the accessibility button is shown to the 1353 * user, {@code false} otherwise 1354 */ 1355 @Override notifyAccessibilityButtonVisibilityChanged(boolean shown)1356 public void notifyAccessibilityButtonVisibilityChanged(boolean shown) { 1357 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1358 mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged", 1359 FLAGS_ACCESSIBILITY_MANAGER, "shown=" + shown); 1360 } 1361 1362 mSecurityPolicy.enforceCallingOrSelfPermission( 1363 android.Manifest.permission.STATUS_BAR_SERVICE); 1364 synchronized (mLock) { 1365 notifyAccessibilityButtonVisibilityChangedLocked(shown); 1366 } 1367 } 1368 1369 /** 1370 * Called when a gesture is detected on a display by the framework. 1371 * 1372 * @param gestureEvent the detail of the gesture. 1373 * @return true if the event is handled. 1374 */ onGesture(AccessibilityGestureEvent gestureEvent)1375 public boolean onGesture(AccessibilityGestureEvent gestureEvent) { 1376 synchronized (mLock) { 1377 boolean handled = notifyGestureLocked(gestureEvent, false); 1378 if (!handled) { 1379 handled = notifyGestureLocked(gestureEvent, true); 1380 } 1381 return handled; 1382 } 1383 } 1384 1385 /** Send a motion event to the service to allow it to perform gesture detection. */ sendMotionEventToListeningServices(MotionEvent event)1386 public boolean sendMotionEventToListeningServices(MotionEvent event) { 1387 boolean result; 1388 event = MotionEvent.obtain(event); 1389 if (DEBUG) { 1390 Slog.d(LOG_TAG, "Sending event to service: " + event); 1391 } 1392 result = scheduleNotifyMotionEvent(event); 1393 return result; 1394 } 1395 1396 /** 1397 * Notifies services that the touch state on a given display has changed. 1398 */ onTouchStateChanged(int displayId, int state)1399 public boolean onTouchStateChanged(int displayId, int state) { 1400 if (DEBUG) { 1401 Slog.d(LOG_TAG, "Notifying touch state:" 1402 + TouchInteractionController.stateToString(state)); 1403 } 1404 return scheduleNotifyTouchState(displayId, state); 1405 } 1406 1407 /** 1408 * Called when the system action list is changed. 1409 */ 1410 @Override onSystemActionsChanged()1411 public void onSystemActionsChanged() { 1412 synchronized (mLock) { 1413 AccessibilityUserState state = getCurrentUserStateLocked(); 1414 notifySystemActionsChangedLocked(state); 1415 } 1416 } 1417 1418 @VisibleForTesting notifySystemActionsChangedLocked(AccessibilityUserState userState)1419 void notifySystemActionsChangedLocked(AccessibilityUserState userState) { 1420 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 1421 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 1422 service.notifySystemActionsChangedLocked(); 1423 } 1424 } 1425 1426 @VisibleForTesting notifyKeyEvent(KeyEvent event, int policyFlags)1427 public boolean notifyKeyEvent(KeyEvent event, int policyFlags) { 1428 synchronized (mLock) { 1429 List<AccessibilityServiceConnection> boundServices = 1430 getCurrentUserStateLocked().mBoundServices; 1431 if (boundServices.isEmpty()) { 1432 return false; 1433 } 1434 return getKeyEventDispatcher().notifyKeyEventLocked(event, policyFlags, boundServices); 1435 } 1436 } 1437 1438 /** 1439 * Called by the MagnificationController when the state of display 1440 * magnification changes. 1441 * 1442 * <p> 1443 * It can notify window magnification change if the service supports controlling all the 1444 * magnification mode. 1445 * </p> 1446 * 1447 * @param displayId The logical display id 1448 * @param region The magnification region. 1449 * If the config mode is 1450 * {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}, 1451 * it is the region of the screen currently active for magnification. 1452 * the returned region will be empty if the magnification is not active 1453 * (e.g. scale is 1. And the magnification is active if magnification 1454 * gestures are enabled or if a service is running that can control 1455 * magnification. 1456 * If the config mode is 1457 * {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, 1458 * it is the region of screen projected on the magnification window. 1459 * The region will be empty if magnification is not activated. 1460 * @param config The magnification config. That has magnification mode, the new scale and the 1461 * new screen-relative center position 1462 */ notifyMagnificationChanged(int displayId, @NonNull Region region, @NonNull MagnificationConfig config)1463 public void notifyMagnificationChanged(int displayId, @NonNull Region region, 1464 @NonNull MagnificationConfig config) { 1465 synchronized (mLock) { 1466 notifyClearAccessibilityCacheLocked(); 1467 notifyMagnificationChangedLocked(displayId, region, config); 1468 } 1469 } 1470 1471 /** 1472 * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector. 1473 * Not using a getter because the AccessibilityInputFilter isn't thread-safe 1474 * 1475 * @param motionEventInjectors The array of motionEventInjectors. May be null. 1476 * 1477 */ setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors)1478 void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) { 1479 synchronized (mLock) { 1480 mMotionEventInjectors = motionEventInjectors; 1481 // We may be waiting on this object being set 1482 mLock.notifyAll(); 1483 } 1484 } 1485 1486 @Override getMotionEventInjectorForDisplayLocked(int displayId)1487 public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) { 1488 final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS; 1489 MotionEventInjector motionEventInjector = null; 1490 while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) { 1491 try { 1492 mLock.wait(endMillis - SystemClock.uptimeMillis()); 1493 } catch (InterruptedException ie) { 1494 /* ignore */ 1495 } 1496 } 1497 if (mMotionEventInjectors == null) { 1498 Slog.e(LOG_TAG, "MotionEventInjector installation timed out"); 1499 } else { 1500 motionEventInjector = mMotionEventInjectors.get(displayId); 1501 } 1502 return motionEventInjector; 1503 } 1504 1505 /** 1506 * Gets a point within the accessibility focused node where we can send down 1507 * and up events to perform a click. 1508 * 1509 * @param outPoint The click point to populate. 1510 * @return Whether accessibility a click point was found and set. 1511 */ 1512 // TODO: (multi-display) Make sure this works for multiple displays. getAccessibilityFocusClickPointInScreen(Point outPoint)1513 public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { 1514 return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint); 1515 } 1516 1517 /** 1518 * Perform an accessibility action on the view that currently has accessibility focus. 1519 * Has no effect if no item has accessibility focus, if the item with accessibility 1520 * focus does not expose the specified action, or if the action fails. 1521 * 1522 * @param action The action to perform. 1523 * 1524 * @return {@code true} if the action was performed. {@code false} if it was not. 1525 */ performActionOnAccessibilityFocusedItem( AccessibilityNodeInfo.AccessibilityAction action)1526 public boolean performActionOnAccessibilityFocusedItem( 1527 AccessibilityNodeInfo.AccessibilityAction action) { 1528 return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); 1529 } 1530 1531 /** 1532 * Returns true if accessibility focus is confined to the active window. 1533 */ accessibilityFocusOnlyInActiveWindow()1534 public boolean accessibilityFocusOnlyInActiveWindow() { 1535 synchronized (mLock) { 1536 return mA11yWindowManager.accessibilityFocusOnlyInActiveWindowLocked(); 1537 } 1538 } 1539 1540 /** 1541 * Gets the bounds of a window. 1542 * 1543 * @param outBounds The output to which to write the bounds. 1544 */ getWindowBounds(int windowId, Rect outBounds)1545 boolean getWindowBounds(int windowId, Rect outBounds) { 1546 IBinder token; 1547 synchronized (mLock) { 1548 token = getWindowToken(windowId, mCurrentUserId); 1549 } 1550 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) { 1551 mTraceManager.logTrace("WindowManagerInternal.getWindowFrame", 1552 FLAGS_WINDOW_MANAGER_INTERNAL, "token=" + token + ";outBounds=" + outBounds); 1553 } 1554 mWindowManagerService.getWindowFrame(token, outBounds); 1555 if (!outBounds.isEmpty()) { 1556 return true; 1557 } 1558 return false; 1559 } 1560 getActiveWindowId()1561 public int getActiveWindowId() { 1562 return mA11yWindowManager.getActiveWindowId(mCurrentUserId); 1563 } 1564 onTouchInteractionStart()1565 public void onTouchInteractionStart() { 1566 mA11yWindowManager.onTouchInteractionStart(); 1567 } 1568 onTouchInteractionEnd()1569 public void onTouchInteractionEnd() { 1570 mA11yWindowManager.onTouchInteractionEnd(); 1571 } 1572 switchUser(int userId)1573 private void switchUser(int userId) { 1574 mMagnificationController.updateUserIdIfNeeded(userId); 1575 synchronized (mLock) { 1576 if (mCurrentUserId == userId && mInitialized) { 1577 return; 1578 } 1579 1580 // Disconnect from services for the old user. 1581 AccessibilityUserState oldUserState = getCurrentUserStateLocked(); 1582 oldUserState.onSwitchToAnotherUserLocked(); 1583 1584 // Disable the local managers for the old user. 1585 if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) { 1586 mMainHandler.sendMessage(obtainMessage( 1587 AccessibilityManagerService::sendStateToClients, 1588 this, 0, oldUserState.mUserId)); 1589 } 1590 1591 // Announce user changes only if more that one exist. 1592 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1593 final boolean announceNewUser = userManager.getUsers().size() > 1; 1594 1595 // The user changed. 1596 mCurrentUserId = userId; 1597 AccessibilityUserState userState = getCurrentUserStateLocked(); 1598 1599 readConfigurationForUserStateLocked(userState); 1600 mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices); 1601 // Even if reading did not yield change, we have to update 1602 // the state since the context in which the current user 1603 // state was used has changed since it was inactive. 1604 onUserStateChangedLocked(userState); 1605 // It's better to have this migration in SettingsProvider. Unfortunately, 1606 // SettingsProvider migrated database in a very early stage which A11yManagerService 1607 // haven't finished or started the initialization. We cannot get enough information from 1608 // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for 1609 // restoreFromSdkInt to have this migration check execute every time, because we did not 1610 // find out a way to detect the device finished the OTA and switch the user. 1611 migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, 1612 /* restoreFromSdkInt = */0); 1613 1614 if (announceNewUser) { 1615 // Schedule announcement of the current user if needed. 1616 mMainHandler.sendMessageDelayed( 1617 obtainMessage(AccessibilityManagerService::announceNewUserIfNeeded, this), 1618 WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS); 1619 } 1620 } 1621 } 1622 announceNewUserIfNeeded()1623 private void announceNewUserIfNeeded() { 1624 synchronized (mLock) { 1625 AccessibilityUserState userState = getCurrentUserStateLocked(); 1626 if (userState.isHandlingAccessibilityEventsLocked()) { 1627 UserManager userManager = (UserManager) mContext.getSystemService( 1628 Context.USER_SERVICE); 1629 String message = mContext.getString(R.string.user_switched, 1630 userManager.getUserInfo(mCurrentUserId).name); 1631 AccessibilityEvent event = AccessibilityEvent.obtain( 1632 AccessibilityEvent.TYPE_ANNOUNCEMENT); 1633 event.getText().add(message); 1634 sendAccessibilityEventLocked(event, mCurrentUserId); 1635 } 1636 } 1637 } 1638 unlockUser(int userId)1639 private void unlockUser(int userId) { 1640 synchronized (mLock) { 1641 int parentUserId = mSecurityPolicy.resolveProfileParentLocked(userId); 1642 if (parentUserId == mCurrentUserId) { 1643 AccessibilityUserState userState = getUserStateLocked(mCurrentUserId); 1644 onUserStateChangedLocked(userState); 1645 } 1646 } 1647 } 1648 removeUser(int userId)1649 private void removeUser(int userId) { 1650 synchronized (mLock) { 1651 mUserStates.remove(userId); 1652 } 1653 getMagnificationController().onUserRemoved(userId); 1654 } 1655 1656 // Called only during settings restore; currently supports only the owner user 1657 // TODO: http://b/22388012 restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting, int restoreFromSdkInt)1658 void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting, 1659 int restoreFromSdkInt) { 1660 readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false); 1661 readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true); 1662 1663 AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 1664 userState.mEnabledServices.clear(); 1665 userState.mEnabledServices.addAll(mTempComponentNameSet); 1666 persistComponentNamesToSettingLocked( 1667 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 1668 userState.mEnabledServices, 1669 UserHandle.USER_SYSTEM); 1670 onUserStateChangedLocked(userState); 1671 migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt); 1672 } 1673 1674 /** 1675 * User could enable accessibility services and configure accessibility button during the SUW. 1676 * Merges current value of accessibility button settings into the restored one to make sure 1677 * user's preferences of accessibility button updated in SUW are not lost. 1678 * 1679 * Called only during settings restore; currently supports only the owner user 1680 * TODO: http://b/22388012 1681 */ restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting)1682 void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) { 1683 final Set<String> targetsFromSetting = new ArraySet<>(); 1684 readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting, 1685 /* doMerge = */false); 1686 readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting, 1687 /* doMerge = */true); 1688 1689 final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 1690 userState.mAccessibilityButtonTargets.clear(); 1691 userState.mAccessibilityButtonTargets.addAll(targetsFromSetting); 1692 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 1693 UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str); 1694 1695 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 1696 onUserStateChangedLocked(userState); 1697 } 1698 getClientStateLocked(AccessibilityUserState userState)1699 private int getClientStateLocked(AccessibilityUserState userState) { 1700 return userState.getClientStateLocked( 1701 mUiAutomationManager.isUiAutomationRunningLocked(), 1702 mTraceManager.getTraceStateForAccessibilityManagerClientState()); 1703 } 1704 getInteractionBridge()1705 private InteractionBridge getInteractionBridge() { 1706 synchronized (mLock) { 1707 if (mInteractionBridge == null) { 1708 mInteractionBridge = new InteractionBridge(); 1709 } 1710 return mInteractionBridge; 1711 } 1712 } 1713 notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault)1714 private boolean notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault) { 1715 // TODO: Now we are giving the gestures to the last enabled 1716 // service that can handle them which is the last one 1717 // in our list since we write the last enabled as the 1718 // last record in the enabled services setting. Ideally, 1719 // the user should make the call which service handles 1720 // gestures. However, only one service should handle 1721 // gestures to avoid user frustration when different 1722 // behavior is observed from different combinations of 1723 // enabled accessibility services. 1724 AccessibilityUserState state = getCurrentUserStateLocked(); 1725 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 1726 AccessibilityServiceConnection service = state.mBoundServices.get(i); 1727 if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) { 1728 service.notifyGesture(gestureEvent); 1729 return true; 1730 } 1731 } 1732 return false; 1733 } 1734 scheduleNotifyMotionEvent(MotionEvent event)1735 private boolean scheduleNotifyMotionEvent(MotionEvent event) { 1736 synchronized (mLock) { 1737 AccessibilityUserState state = getCurrentUserStateLocked(); 1738 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 1739 AccessibilityServiceConnection service = state.mBoundServices.get(i); 1740 if (service.mRequestTouchExplorationMode) { 1741 service.notifyMotionEvent(event); 1742 return true; 1743 } 1744 } 1745 } 1746 return false; 1747 } 1748 scheduleNotifyTouchState(int displayId, int touchState)1749 private boolean scheduleNotifyTouchState(int displayId, int touchState) { 1750 synchronized (mLock) { 1751 AccessibilityUserState state = getCurrentUserStateLocked(); 1752 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 1753 AccessibilityServiceConnection service = state.mBoundServices.get(i); 1754 if (service.mRequestTouchExplorationMode) { 1755 service.notifyTouchState(displayId, touchState); 1756 return true; 1757 } 1758 } 1759 } 1760 return false; 1761 } 1762 notifyClearAccessibilityCacheLocked()1763 private void notifyClearAccessibilityCacheLocked() { 1764 AccessibilityUserState state = getCurrentUserStateLocked(); 1765 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 1766 AccessibilityServiceConnection service = state.mBoundServices.get(i); 1767 service.notifyClearAccessibilityNodeInfoCache(); 1768 } 1769 } 1770 notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config)1771 private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, 1772 @NonNull MagnificationConfig config) { 1773 final AccessibilityUserState state = getCurrentUserStateLocked(); 1774 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 1775 final AccessibilityServiceConnection service = state.mBoundServices.get(i); 1776 service.notifyMagnificationChangedLocked(displayId, region, config); 1777 } 1778 } 1779 sendAccessibilityButtonToInputFilter(int displayId)1780 private void sendAccessibilityButtonToInputFilter(int displayId) { 1781 synchronized (mLock) { 1782 if (mHasInputFilter && mInputFilter != null) { 1783 mInputFilter.notifyAccessibilityButtonClicked(displayId); 1784 } 1785 } 1786 } 1787 showAccessibilityTargetsSelection(int displayId, @ShortcutType int shortcutType)1788 private void showAccessibilityTargetsSelection(int displayId, 1789 @ShortcutType int shortcutType) { 1790 final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); 1791 final String chooserClassName = (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) 1792 ? AccessibilityShortcutChooserActivity.class.getName() 1793 : AccessibilityButtonChooserActivity.class.getName(); 1794 intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); 1795 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 1796 final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); 1797 mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); 1798 } 1799 launchShortcutTargetActivity(int displayId, ComponentName name)1800 private void launchShortcutTargetActivity(int displayId, ComponentName name) { 1801 final Intent intent = new Intent(); 1802 final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); 1803 intent.setComponent(name); 1804 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1805 try { 1806 mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); 1807 } catch (ActivityNotFoundException ignore) { 1808 // ignore the exception 1809 } 1810 } 1811 notifyAccessibilityButtonVisibilityChangedLocked(boolean available)1812 private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) { 1813 final AccessibilityUserState state = getCurrentUserStateLocked(); 1814 mIsAccessibilityButtonShown = available; 1815 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 1816 final AccessibilityServiceConnection clientConnection = state.mBoundServices.get(i); 1817 if (clientConnection.mRequestAccessibilityButton) { 1818 clientConnection.notifyAccessibilityButtonAvailabilityChangedLocked( 1819 clientConnection.isAccessibilityButtonAvailableLocked(state)); 1820 } 1821 } 1822 } 1823 readInstalledAccessibilityServiceLocked(AccessibilityUserState userState)1824 private boolean readInstalledAccessibilityServiceLocked(AccessibilityUserState userState) { 1825 mTempAccessibilityServiceInfoList.clear(); 1826 1827 int flags = PackageManager.GET_SERVICES 1828 | PackageManager.GET_META_DATA 1829 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS 1830 | PackageManager.MATCH_DIRECT_BOOT_AWARE 1831 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 1832 1833 if (userState.getBindInstantServiceAllowedLocked()) { 1834 flags |= PackageManager.MATCH_INSTANT; 1835 } 1836 1837 List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( 1838 new Intent(AccessibilityService.SERVICE_INTERFACE), flags, mCurrentUserId); 1839 1840 for (int i = 0, count = installedServices.size(); i < count; i++) { 1841 ResolveInfo resolveInfo = installedServices.get(i); 1842 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 1843 1844 if (!mSecurityPolicy.canRegisterService(serviceInfo)) { 1845 continue; 1846 } 1847 1848 AccessibilityServiceInfo accessibilityServiceInfo; 1849 try { 1850 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); 1851 if (!accessibilityServiceInfo.isWithinParcelableSize()) { 1852 Slog.e(LOG_TAG, "Skipping service " 1853 + accessibilityServiceInfo.getResolveInfo().getComponentInfo() 1854 + " because service info size is larger than safe parcelable limits."); 1855 continue; 1856 } 1857 if (userState.mCrashedServices.contains(serviceInfo.getComponentName())) { 1858 // Restore the crashed attribute. 1859 accessibilityServiceInfo.crashed = true; 1860 } 1861 mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo); 1862 } catch (XmlPullParserException | IOException xppe) { 1863 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); 1864 } 1865 } 1866 1867 if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) { 1868 userState.mInstalledServices.clear(); 1869 userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList); 1870 mTempAccessibilityServiceInfoList.clear(); 1871 return true; 1872 } 1873 1874 mTempAccessibilityServiceInfoList.clear(); 1875 return false; 1876 } 1877 readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState)1878 private boolean readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState) { 1879 final List<AccessibilityShortcutInfo> shortcutInfos = AccessibilityManager 1880 .getInstance(mContext).getInstalledAccessibilityShortcutListAsUser( 1881 mContext, mCurrentUserId); 1882 if (!shortcutInfos.equals(userState.mInstalledShortcuts)) { 1883 userState.mInstalledShortcuts.clear(); 1884 userState.mInstalledShortcuts.addAll(shortcutInfos); 1885 return true; 1886 } 1887 return false; 1888 } 1889 readEnabledAccessibilityServicesLocked(AccessibilityUserState userState)1890 private boolean readEnabledAccessibilityServicesLocked(AccessibilityUserState userState) { 1891 mTempComponentNameSet.clear(); 1892 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 1893 userState.mUserId, mTempComponentNameSet); 1894 if (!mTempComponentNameSet.equals(userState.mEnabledServices)) { 1895 userState.mEnabledServices.clear(); 1896 userState.mEnabledServices.addAll(mTempComponentNameSet); 1897 mTempComponentNameSet.clear(); 1898 return true; 1899 } 1900 mTempComponentNameSet.clear(); 1901 return false; 1902 } 1903 readTouchExplorationGrantedAccessibilityServicesLocked( AccessibilityUserState userState)1904 private boolean readTouchExplorationGrantedAccessibilityServicesLocked( 1905 AccessibilityUserState userState) { 1906 mTempComponentNameSet.clear(); 1907 readComponentNamesFromSettingLocked( 1908 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 1909 userState.mUserId, mTempComponentNameSet); 1910 if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) { 1911 userState.mTouchExplorationGrantedServices.clear(); 1912 userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet); 1913 mTempComponentNameSet.clear(); 1914 return true; 1915 } 1916 mTempComponentNameSet.clear(); 1917 return false; 1918 } 1919 1920 /** 1921 * Performs {@link AccessibilityService}s delayed notification. The delay is configurable 1922 * and denotes the period after the last event before notifying the service. 1923 * 1924 * @param event The event. 1925 * @param isDefault True to notify default listeners, not default services. 1926 */ notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)1927 private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, 1928 boolean isDefault) { 1929 try { 1930 AccessibilityUserState state = getCurrentUserStateLocked(); 1931 for (int i = 0, count = state.mBoundServices.size(); i < count; i++) { 1932 AccessibilityServiceConnection service = state.mBoundServices.get(i); 1933 1934 if (service.mIsDefault == isDefault) { 1935 service.notifyAccessibilityEvent(event); 1936 } 1937 } 1938 } catch (IndexOutOfBoundsException oobe) { 1939 // An out of bounds exception can happen if services are going away 1940 // as the for loop is running. If that happens, just bail because 1941 // there are no more services to notify. 1942 } 1943 } 1944 updateRelevantEventsLocked(AccessibilityUserState userState)1945 private void updateRelevantEventsLocked(AccessibilityUserState userState) { 1946 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 1947 mTraceManager.logTrace(LOG_TAG + ".updateRelevantEventsLocked", 1948 FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState); 1949 } 1950 mMainHandler.post(() -> { 1951 broadcastToClients(userState, ignoreRemoteException(client -> { 1952 int relevantEventTypes; 1953 boolean changed = false; 1954 synchronized (mLock) { 1955 relevantEventTypes = computeRelevantEventTypesLocked(userState, client); 1956 1957 if (client.mLastSentRelevantEventTypes != relevantEventTypes) { 1958 client.mLastSentRelevantEventTypes = relevantEventTypes; 1959 changed = true; 1960 } 1961 } 1962 if (changed) { 1963 client.mCallback.setRelevantEventTypes(relevantEventTypes); 1964 } 1965 })); 1966 }); 1967 } 1968 computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client)1969 private int computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client) { 1970 int relevantEventTypes = 0; 1971 1972 int serviceCount = userState.mBoundServices.size(); 1973 for (int i = 0; i < serviceCount; i++) { 1974 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 1975 relevantEventTypes |= isClientInPackageAllowlist(service.getServiceInfo(), client) 1976 ? service.getRelevantEventTypes() 1977 : 0; 1978 } 1979 1980 relevantEventTypes |= isClientInPackageAllowlist( 1981 mUiAutomationManager.getServiceInfo(), client) 1982 ? mUiAutomationManager.getRelevantEventTypes() 1983 : 0; 1984 return relevantEventTypes; 1985 } 1986 updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState, int displayId)1987 private void updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState, 1988 int displayId) { 1989 if (userState.mUserId != mCurrentUserId) { 1990 return; 1991 } 1992 // New mode is invalid, so ignore and restore it. 1993 if (fallBackMagnificationModeSettingsLocked(userState, displayId)) { 1994 return; 1995 } 1996 mMagnificationController.transitionMagnificationModeLocked( 1997 displayId, userState.getMagnificationModeLocked(displayId), 1998 this::onMagnificationTransitionEndedLocked); 1999 } 2000 2001 /** 2002 * Called when the magnification mode transition is completed. If the given display is default 2003 * display, we also need to fall back the mode in user settings. 2004 */ onMagnificationTransitionEndedLocked(int displayId, boolean success)2005 void onMagnificationTransitionEndedLocked(int displayId, boolean success) { 2006 final AccessibilityUserState userState = getCurrentUserStateLocked(); 2007 final int previousMode = userState.getMagnificationModeLocked(displayId) 2008 ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; 2009 if (!success && previousMode != 0) { 2010 userState.setMagnificationModeLocked(displayId, previousMode); 2011 if (displayId == Display.DEFAULT_DISPLAY) { 2012 persistMagnificationModeSettingsLocked(previousMode); 2013 } 2014 } else { 2015 mMainHandler.sendMessage(obtainMessage( 2016 AccessibilityManagerService::notifyRefreshMagnificationModeToInputFilter, 2017 this, displayId)); 2018 } 2019 } 2020 notifyRefreshMagnificationModeToInputFilter(int displayId)2021 private void notifyRefreshMagnificationModeToInputFilter(int displayId) { 2022 synchronized (mLock) { 2023 if (!mHasInputFilter) { 2024 return; 2025 } 2026 final ArrayList<Display> displays = getValidDisplayList(); 2027 for (int i = 0; i < displays.size(); i++) { 2028 final Display display = displays.get(i); 2029 if (display != null && display.getDisplayId() == displayId) { 2030 mInputFilter.refreshMagnificationMode(display); 2031 return; 2032 } 2033 } 2034 } 2035 } 2036 isClientInPackageAllowlist( @ullable AccessibilityServiceInfo serviceInfo, Client client)2037 private static boolean isClientInPackageAllowlist( 2038 @Nullable AccessibilityServiceInfo serviceInfo, Client client) { 2039 if (serviceInfo == null) return false; 2040 2041 String[] clientPackages = client.mPackageNames; 2042 boolean result = ArrayUtils.isEmpty(serviceInfo.packageNames); 2043 if (!result && clientPackages != null) { 2044 for (String packageName : clientPackages) { 2045 if (ArrayUtils.contains(serviceInfo.packageNames, packageName)) { 2046 result = true; 2047 break; 2048 } 2049 } 2050 } 2051 if (!result) { 2052 if (DEBUG) { 2053 Slog.d(LOG_TAG, "Dropping events: " 2054 + Arrays.toString(clientPackages) + " -> " 2055 + serviceInfo.getComponentName().flattenToShortString() 2056 + " due to not being in package allowlist " 2057 + Arrays.toString(serviceInfo.packageNames)); 2058 } 2059 } 2060 2061 return result; 2062 } 2063 broadcastToClients( AccessibilityUserState userState, Consumer<Client> clientAction)2064 private void broadcastToClients( 2065 AccessibilityUserState userState, Consumer<Client> clientAction) { 2066 mGlobalClients.broadcastForEachCookie(clientAction); 2067 userState.mUserClients.broadcastForEachCookie(clientAction); 2068 } 2069 2070 /** 2071 * Populates a set with the {@link ComponentName}s stored in a colon 2072 * separated value setting for a given user. 2073 * 2074 * @param settingName The setting to parse. 2075 * @param userId The user id. 2076 * @param outComponentNames The output component names. 2077 */ readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)2078 private void readComponentNamesFromSettingLocked(String settingName, int userId, 2079 Set<ComponentName> outComponentNames) { 2080 readColonDelimitedSettingToSet(settingName, userId, 2081 str -> ComponentName.unflattenFromString(str), outComponentNames); 2082 } 2083 2084 /** 2085 * Populates a set with the {@link ComponentName}s contained in a colon-delimited string. 2086 * 2087 * @param names The colon-delimited string to parse. 2088 * @param outComponentNames The set of component names to be populated based on 2089 * the contents of the <code>names</code> string. 2090 * @param doMerge If true, the parsed component names will be merged into the output 2091 * set, rather than replacing the set's existing contents entirely. 2092 */ readComponentNamesFromStringLocked(String names, Set<ComponentName> outComponentNames, boolean doMerge)2093 private void readComponentNamesFromStringLocked(String names, 2094 Set<ComponentName> outComponentNames, 2095 boolean doMerge) { 2096 readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str), 2097 outComponentNames, doMerge); 2098 } 2099 2100 @Override persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)2101 public void persistComponentNamesToSettingLocked(String settingName, 2102 Set<ComponentName> componentNames, int userId) { 2103 persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames, 2104 componentName -> componentName.flattenToShortString()); 2105 } 2106 readColonDelimitedSettingToSet(String settingName, int userId, Function<String, T> toItem, Set<T> outSet)2107 private <T> void readColonDelimitedSettingToSet(String settingName, int userId, 2108 Function<String, T> toItem, Set<T> outSet) { 2109 final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 2110 settingName, userId); 2111 readColonDelimitedStringToSet(settingValue, toItem, outSet, false); 2112 } 2113 readColonDelimitedStringToSet(String names, Function<String, T> toItem, Set<T> outSet, boolean doMerge)2114 private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem, 2115 Set<T> outSet, boolean doMerge) { 2116 if (!doMerge) { 2117 outSet.clear(); 2118 } 2119 if (!TextUtils.isEmpty(names)) { 2120 final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; 2121 splitter.setString(names); 2122 while (splitter.hasNext()) { 2123 final String str = splitter.next(); 2124 if (TextUtils.isEmpty(str)) { 2125 continue; 2126 } 2127 final T item = toItem.apply(str); 2128 if (item != null) { 2129 outSet.add(item); 2130 } 2131 } 2132 } 2133 } 2134 persistColonDelimitedSetToSettingLocked(String settingName, int userId, Set<T> set, Function<T, String> toString)2135 private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId, 2136 Set<T> set, Function<T, String> toString) { 2137 final StringBuilder builder = new StringBuilder(); 2138 for (T item : set) { 2139 final String str = (item != null ? toString.apply(item) : null); 2140 if (TextUtils.isEmpty(str)) { 2141 continue; 2142 } 2143 if (builder.length() > 0) { 2144 builder.append(COMPONENT_NAME_SEPARATOR); 2145 } 2146 builder.append(str); 2147 } 2148 final long identity = Binder.clearCallingIdentity(); 2149 try { 2150 final String settingValue = builder.toString(); 2151 Settings.Secure.putStringForUser(mContext.getContentResolver(), 2152 settingName, TextUtils.isEmpty(settingValue) ? null : settingValue, userId); 2153 } finally { 2154 Binder.restoreCallingIdentity(identity); 2155 } 2156 } 2157 updateServicesLocked(AccessibilityUserState userState)2158 private void updateServicesLocked(AccessibilityUserState userState) { 2159 Map<ComponentName, AccessibilityServiceConnection> componentNameToServiceMap = 2160 userState.mComponentNameToServiceMap; 2161 boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class) 2162 .isUserUnlockingOrUnlocked(userState.mUserId); 2163 2164 for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { 2165 AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); 2166 ComponentName componentName = ComponentName.unflattenFromString( 2167 installedService.getId()); 2168 2169 AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName); 2170 2171 // Ignore non-encryption-aware services until user is unlocked 2172 if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) { 2173 Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName); 2174 continue; 2175 } 2176 2177 // Skip the component since it may be in process or crashed. 2178 if (userState.getBindingServicesLocked().contains(componentName) 2179 || userState.getCrashedServicesLocked().contains(componentName)) { 2180 continue; 2181 } 2182 if (userState.mEnabledServices.contains(componentName) 2183 && !mUiAutomationManager.suppressingAccessibilityServicesLocked()) { 2184 if (service == null) { 2185 service = new AccessibilityServiceConnection(userState, mContext, componentName, 2186 installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, 2187 this, getTraceManager(), mWindowManagerService, 2188 getSystemActionPerformer(), mA11yWindowManager, 2189 mActivityTaskManagerService); 2190 } else if (userState.mBoundServices.contains(service)) { 2191 continue; 2192 } 2193 service.bindLocked(); 2194 } else { 2195 if (service != null) { 2196 service.unbindLocked(); 2197 removeShortcutTargetForUnboundServiceLocked(userState, service); 2198 } 2199 } 2200 } 2201 2202 final int count = userState.mBoundServices.size(); 2203 mTempIntArray.clear(); 2204 for (int i = 0; i < count; i++) { 2205 final ResolveInfo resolveInfo = 2206 userState.mBoundServices.get(i).mAccessibilityServiceInfo.getResolveInfo(); 2207 if (resolveInfo != null) { 2208 mTempIntArray.add(resolveInfo.serviceInfo.applicationInfo.uid); 2209 } 2210 } 2211 // Calling out with lock held, but to lower-level services 2212 final AudioManagerInternal audioManager = 2213 LocalServices.getService(AudioManagerInternal.class); 2214 if (audioManager != null) { 2215 audioManager.setAccessibilityServiceUids(mTempIntArray); 2216 } 2217 mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray); 2218 updateAccessibilityEnabledSettingLocked(userState); 2219 } 2220 scheduleUpdateClientsIfNeeded(AccessibilityUserState userState)2221 void scheduleUpdateClientsIfNeeded(AccessibilityUserState userState) { 2222 synchronized (mLock) { 2223 scheduleUpdateClientsIfNeededLocked(userState); 2224 } 2225 } 2226 scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState)2227 void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) { 2228 final int clientState = getClientStateLocked(userState); 2229 if (userState.getLastSentClientStateLocked() != clientState 2230 && (mGlobalClients.getRegisteredCallbackCount() > 0 2231 || userState.mUserClients.getRegisteredCallbackCount() > 0)) { 2232 userState.setLastSentClientStateLocked(clientState); 2233 mMainHandler.sendMessage(obtainMessage( 2234 AccessibilityManagerService::sendStateToAllClients, 2235 this, clientState, userState.mUserId)); 2236 } 2237 } 2238 sendStateToAllClients(int clientState, int userId)2239 private void sendStateToAllClients(int clientState, int userId) { 2240 sendStateToClients(clientState, mGlobalClients); 2241 sendStateToClients(clientState, userId); 2242 } 2243 sendStateToClients(int clientState, int userId)2244 private void sendStateToClients(int clientState, int userId) { 2245 sendStateToClients(clientState, getUserState(userId).mUserClients); 2246 } 2247 sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)2248 private void sendStateToClients(int clientState, 2249 RemoteCallbackList<IAccessibilityManagerClient> clients) { 2250 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) { 2251 mTraceManager.logTrace(LOG_TAG + ".sendStateToClients", 2252 FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "clientState=" + clientState); 2253 } 2254 clients.broadcast(ignoreRemoteException( 2255 client -> client.setState(clientState))); 2256 } 2257 scheduleNotifyClientsOfServicesStateChangeLocked( AccessibilityUserState userState)2258 private void scheduleNotifyClientsOfServicesStateChangeLocked( 2259 AccessibilityUserState userState) { 2260 updateRecommendedUiTimeoutLocked(userState); 2261 mMainHandler.sendMessage(obtainMessage( 2262 AccessibilityManagerService::sendServicesStateChanged, 2263 this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState))); 2264 } 2265 sendServicesStateChanged( RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout)2266 private void sendServicesStateChanged( 2267 RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) { 2268 notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout); 2269 notifyClientsOfServicesStateChange(userClients, uiTimeout); 2270 } 2271 notifyClientsOfServicesStateChange( RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout)2272 private void notifyClientsOfServicesStateChange( 2273 RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) { 2274 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) { 2275 mTraceManager.logTrace(LOG_TAG + ".notifyClientsOfServicesStateChange", 2276 FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "uiTimeout=" + uiTimeout); 2277 } 2278 clients.broadcast(ignoreRemoteException( 2279 client -> client.notifyServicesStateChanged(uiTimeout))); 2280 } 2281 scheduleUpdateInputFilter(AccessibilityUserState userState)2282 private void scheduleUpdateInputFilter(AccessibilityUserState userState) { 2283 mMainHandler.sendMessage(obtainMessage( 2284 AccessibilityManagerService::updateInputFilter, this, userState)); 2285 } 2286 scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState)2287 private void scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState) { 2288 mMainHandler.sendMessage(obtainMessage( 2289 AccessibilityManagerService::updateFingerprintGestureHandling, 2290 this, userState)); 2291 } 2292 updateInputFilter(AccessibilityUserState userState)2293 private void updateInputFilter(AccessibilityUserState userState) { 2294 if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return; 2295 2296 boolean setInputFilter = false; 2297 AccessibilityInputFilter inputFilter = null; 2298 synchronized (mLock) { 2299 int flags = 0; 2300 if (userState.isDisplayMagnificationEnabledLocked()) { 2301 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER; 2302 } 2303 if (userState.isShortcutMagnificationEnabledLocked()) { 2304 flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; 2305 } 2306 if (userHasMagnificationServicesLocked(userState)) { 2307 flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER; 2308 } 2309 // Touch exploration without accessibility makes no sense. 2310 if (userState.isHandlingAccessibilityEventsLocked() 2311 && userState.isTouchExplorationEnabledLocked()) { 2312 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; 2313 if (userState.isServiceHandlesDoubleTapEnabledLocked()) { 2314 flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP; 2315 } 2316 if (userState.isMultiFingerGesturesEnabledLocked()) { 2317 flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES; 2318 } 2319 if (userState.isTwoFingerPassthroughEnabledLocked()) { 2320 flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH; 2321 } 2322 } 2323 if (userState.isFilterKeyEventsEnabledLocked()) { 2324 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; 2325 } 2326 if (userState.isSendMotionEventsEnabled()) { 2327 flags |= AccessibilityInputFilter.FLAG_SEND_MOTION_EVENTS; 2328 } 2329 if (userState.isAutoclickEnabledLocked()) { 2330 flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK; 2331 } 2332 if (userState.isPerformGesturesEnabledLocked()) { 2333 flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS; 2334 } 2335 if (flags != 0) { 2336 if (!mHasInputFilter) { 2337 mHasInputFilter = true; 2338 if (mInputFilter == null) { 2339 mInputFilter = new AccessibilityInputFilter(mContext, 2340 AccessibilityManagerService.this); 2341 } 2342 inputFilter = mInputFilter; 2343 setInputFilter = true; 2344 } 2345 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags); 2346 } else { 2347 if (mHasInputFilter) { 2348 mHasInputFilter = false; 2349 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0); 2350 inputFilter = null; 2351 setInputFilter = true; 2352 } 2353 } 2354 } 2355 if (setInputFilter) { 2356 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL 2357 | FLAGS_INPUT_FILTER)) { 2358 mTraceManager.logTrace("WindowManagerInternal.setInputFilter", 2359 FLAGS_WINDOW_MANAGER_INTERNAL | FLAGS_INPUT_FILTER, 2360 "inputFilter=" + inputFilter); 2361 } 2362 mWindowManagerService.setInputFilter(inputFilter); 2363 } 2364 } 2365 showEnableTouchExplorationDialog(final AccessibilityServiceConnection service)2366 private void showEnableTouchExplorationDialog(final AccessibilityServiceConnection service) { 2367 synchronized (mLock) { 2368 String label = service.getServiceInfo().getResolveInfo() 2369 .loadLabel(mContext.getPackageManager()).toString(); 2370 2371 final AccessibilityUserState userState = getCurrentUserStateLocked(); 2372 if (userState.isTouchExplorationEnabledLocked()) { 2373 return; 2374 } 2375 if (mEnableTouchExplorationDialog != null 2376 && mEnableTouchExplorationDialog.isShowing()) { 2377 return; 2378 } 2379 mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) 2380 .setIconAttribute(android.R.attr.alertDialogIcon) 2381 .setPositiveButton(android.R.string.ok, new OnClickListener() { 2382 @Override 2383 public void onClick(DialogInterface dialog, int which) { 2384 // The user allowed the service to toggle touch exploration. 2385 userState.mTouchExplorationGrantedServices.add(service.mComponentName); 2386 persistComponentNamesToSettingLocked( 2387 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 2388 userState.mTouchExplorationGrantedServices, userState.mUserId); 2389 // Enable touch exploration. 2390 userState.setTouchExplorationEnabledLocked(true); 2391 final long identity = Binder.clearCallingIdentity(); 2392 try { 2393 Settings.Secure.putIntForUser(mContext.getContentResolver(), 2394 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, 2395 userState.mUserId); 2396 } finally { 2397 Binder.restoreCallingIdentity(identity); 2398 } 2399 onUserStateChangedLocked(userState); 2400 } 2401 }) 2402 .setNegativeButton(android.R.string.cancel, new OnClickListener() { 2403 @Override 2404 public void onClick(DialogInterface dialog, int which) { 2405 dialog.dismiss(); 2406 } 2407 }) 2408 .setTitle(R.string.enable_explore_by_touch_warning_title) 2409 .setMessage(mContext.getString( 2410 R.string.enable_explore_by_touch_warning_message, label)) 2411 .create(); 2412 mEnableTouchExplorationDialog.getWindow().setType( 2413 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2414 mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags 2415 |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; 2416 mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); 2417 mEnableTouchExplorationDialog.show(); 2418 } 2419 } 2420 2421 /** 2422 * Called when any property of the user state has changed. 2423 * 2424 * @param userState the new user state 2425 */ onUserStateChangedLocked(AccessibilityUserState userState)2426 private void onUserStateChangedLocked(AccessibilityUserState userState) { 2427 // TODO: Remove this hack 2428 mInitialized = true; 2429 updateLegacyCapabilitiesLocked(userState); 2430 updateServicesLocked(userState); 2431 updateWindowsForAccessibilityCallbackLocked(userState); 2432 updateFilterKeyEventsLocked(userState); 2433 updateTouchExplorationLocked(userState); 2434 updatePerformGesturesLocked(userState); 2435 updateMagnificationLocked(userState); 2436 scheduleUpdateFingerprintGestureHandling(userState); 2437 scheduleUpdateInputFilter(userState); 2438 updateRelevantEventsLocked(userState); 2439 scheduleUpdateClientsIfNeededLocked(userState); 2440 updateAccessibilityShortcutKeyTargetsLocked(userState); 2441 updateAccessibilityButtonTargetsLocked(userState); 2442 // Update the capabilities before the mode because we will check the current mode is 2443 // invalid or not.. 2444 updateMagnificationCapabilitiesSettingsChangeLocked(userState); 2445 updateMagnificationModeChangeSettingsForAllDisplaysLocked(userState); 2446 updateFocusAppearanceDataLocked(userState); 2447 } 2448 updateMagnificationModeChangeSettingsForAllDisplaysLocked( AccessibilityUserState userState)2449 private void updateMagnificationModeChangeSettingsForAllDisplaysLocked( 2450 AccessibilityUserState userState) { 2451 final ArrayList<Display> displays = getValidDisplayList(); 2452 for (int i = 0; i < displays.size(); i++) { 2453 final int displayId = displays.get(i).getDisplayId(); 2454 updateMagnificationModeChangeSettingsLocked(userState, displayId); 2455 } 2456 } 2457 updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState)2458 private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) { 2459 // We observe windows for accessibility only if there is at least 2460 // one bound service that can retrieve window content that specified 2461 // it is interested in accessing such windows. For services that are 2462 // binding we do an update pass after each bind event, so we run this 2463 // code and register the callback if needed. 2464 2465 boolean observingWindows = mUiAutomationManager.canRetrieveInteractiveWindowsLocked(); 2466 List<AccessibilityServiceConnection> boundServices = userState.mBoundServices; 2467 final int boundServiceCount = boundServices.size(); 2468 for (int i = 0; !observingWindows && (i < boundServiceCount); i++) { 2469 AccessibilityServiceConnection boundService = boundServices.get(i); 2470 if (boundService.canRetrieveInteractiveWindowsLocked()) { 2471 userState.setAccessibilityFocusOnlyInActiveWindow(false); 2472 observingWindows = true; 2473 } 2474 } 2475 userState.setAccessibilityFocusOnlyInActiveWindow(true); 2476 2477 // Gets all valid displays and start tracking windows of each display if there is at least 2478 // one bound service that can retrieve window content. 2479 final ArrayList<Display> displays = getValidDisplayList(); 2480 for (int i = 0; i < displays.size(); i++) { 2481 final Display display = displays.get(i); 2482 if (display != null) { 2483 if (observingWindows) { 2484 mA11yWindowManager.startTrackingWindows(display.getDisplayId()); 2485 } else { 2486 mA11yWindowManager.stopTrackingWindows(display.getDisplayId()); 2487 } 2488 } 2489 } 2490 } 2491 updateLegacyCapabilitiesLocked(AccessibilityUserState userState)2492 private void updateLegacyCapabilitiesLocked(AccessibilityUserState userState) { 2493 // Up to JB-MR1 we had a allowlist with services that can enable touch 2494 // exploration. When a service is first started we show a dialog to the 2495 // use to get a permission to allowlist the service. 2496 final int installedServiceCount = userState.mInstalledServices.size(); 2497 for (int i = 0; i < installedServiceCount; i++) { 2498 AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i); 2499 ResolveInfo resolveInfo = serviceInfo.getResolveInfo(); 2500 if ((serviceInfo.getCapabilities() 2501 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0 2502 && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion 2503 <= Build.VERSION_CODES.JELLY_BEAN_MR1) { 2504 ComponentName componentName = new ComponentName( 2505 resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 2506 if (userState.mTouchExplorationGrantedServices.contains(componentName)) { 2507 serviceInfo.setCapabilities(serviceInfo.getCapabilities() 2508 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION); 2509 } 2510 } 2511 } 2512 } 2513 updatePerformGesturesLocked(AccessibilityUserState userState)2514 private void updatePerformGesturesLocked(AccessibilityUserState userState) { 2515 final int serviceCount = userState.mBoundServices.size(); 2516 for (int i = 0; i < serviceCount; i++) { 2517 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 2518 if ((service.getCapabilities() 2519 & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) { 2520 userState.setPerformGesturesEnabledLocked(true); 2521 return; 2522 } 2523 } 2524 userState.setPerformGesturesEnabledLocked(false); 2525 } 2526 updateFilterKeyEventsLocked(AccessibilityUserState userState)2527 private void updateFilterKeyEventsLocked(AccessibilityUserState userState) { 2528 final int serviceCount = userState.mBoundServices.size(); 2529 for (int i = 0; i < serviceCount; i++) { 2530 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 2531 if (service.mRequestFilterKeyEvents 2532 && (service.getCapabilities() 2533 & AccessibilityServiceInfo 2534 .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) { 2535 userState.setFilterKeyEventsEnabledLocked(true); 2536 return; 2537 } 2538 } 2539 userState.setFilterKeyEventsEnabledLocked(false); 2540 } 2541 readConfigurationForUserStateLocked(AccessibilityUserState userState)2542 private boolean readConfigurationForUserStateLocked(AccessibilityUserState userState) { 2543 boolean somethingChanged = readInstalledAccessibilityServiceLocked(userState); 2544 somethingChanged |= readInstalledAccessibilityShortcutLocked(userState); 2545 somethingChanged |= readEnabledAccessibilityServicesLocked(userState); 2546 somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState); 2547 somethingChanged |= readTouchExplorationEnabledSettingLocked(userState); 2548 somethingChanged |= readHighTextContrastEnabledSettingLocked(userState); 2549 somethingChanged |= readAudioDescriptionEnabledSettingLocked(userState); 2550 somethingChanged |= readMagnificationEnabledSettingsLocked(userState); 2551 somethingChanged |= readAutoclickEnabledSettingLocked(userState); 2552 somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState); 2553 somethingChanged |= readAccessibilityButtonTargetsLocked(userState); 2554 somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState); 2555 somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState); 2556 somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState); 2557 somethingChanged |= readMagnificationCapabilitiesLocked(userState); 2558 somethingChanged |= readMagnificationFollowTypingLocked(userState); 2559 return somethingChanged; 2560 } 2561 updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState)2562 private void updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState) { 2563 final boolean isA11yEnabled = mUiAutomationManager.isUiAutomationRunningLocked() 2564 || userState.isHandlingAccessibilityEventsLocked(); 2565 final long identity = Binder.clearCallingIdentity(); 2566 try { 2567 Settings.Secure.putIntForUser(mContext.getContentResolver(), 2568 Settings.Secure.ACCESSIBILITY_ENABLED, 2569 (isA11yEnabled) ? 1 : 0, 2570 userState.mUserId); 2571 } finally { 2572 Binder.restoreCallingIdentity(identity); 2573 } 2574 } 2575 readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState)2576 private boolean readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState) { 2577 final boolean touchExplorationEnabled = Settings.Secure.getIntForUser( 2578 mContext.getContentResolver(), 2579 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; 2580 if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) { 2581 userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); 2582 return true; 2583 } 2584 return false; 2585 } 2586 readMagnificationEnabledSettingsLocked(AccessibilityUserState userState)2587 private boolean readMagnificationEnabledSettingsLocked(AccessibilityUserState userState) { 2588 final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser( 2589 mContext.getContentResolver(), 2590 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 2591 0, userState.mUserId) == 1; 2592 if ((displayMagnificationEnabled != userState.isDisplayMagnificationEnabledLocked())) { 2593 userState.setDisplayMagnificationEnabledLocked(displayMagnificationEnabled); 2594 return true; 2595 } 2596 return false; 2597 } 2598 readAutoclickEnabledSettingLocked(AccessibilityUserState userState)2599 private boolean readAutoclickEnabledSettingLocked(AccessibilityUserState userState) { 2600 final boolean autoclickEnabled = Settings.Secure.getIntForUser( 2601 mContext.getContentResolver(), 2602 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, 2603 0, userState.mUserId) == 1; 2604 if (autoclickEnabled != userState.isAutoclickEnabledLocked()) { 2605 userState.setAutoclickEnabledLocked(autoclickEnabled); 2606 return true; 2607 } 2608 return false; 2609 } 2610 readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState)2611 private boolean readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState) { 2612 final boolean highTextContrastEnabled = Settings.Secure.getIntForUser( 2613 mContext.getContentResolver(), 2614 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0, 2615 userState.mUserId) == 1; 2616 if (highTextContrastEnabled != userState.isTextHighContrastEnabledLocked()) { 2617 userState.setTextHighContrastEnabledLocked(highTextContrastEnabled); 2618 return true; 2619 } 2620 return false; 2621 } 2622 readAudioDescriptionEnabledSettingLocked(AccessibilityUserState userState)2623 private boolean readAudioDescriptionEnabledSettingLocked(AccessibilityUserState userState) { 2624 final boolean audioDescriptionByDefaultEnabled = Settings.Secure.getIntForUser( 2625 mContext.getContentResolver(), 2626 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, 0, 2627 userState.mUserId) == 1; 2628 if (audioDescriptionByDefaultEnabled 2629 != userState.isAudioDescriptionByDefaultEnabledLocked()) { 2630 userState.setAudioDescriptionByDefaultEnabledLocked(audioDescriptionByDefaultEnabled); 2631 return true; 2632 } 2633 return false; 2634 } 2635 updateTouchExplorationLocked(AccessibilityUserState userState)2636 private void updateTouchExplorationLocked(AccessibilityUserState userState) { 2637 boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); 2638 boolean serviceHandlesDoubleTapEnabled = false; 2639 boolean requestMultiFingerGestures = false; 2640 boolean requestTwoFingerPassthrough = false; 2641 boolean sendMotionEvents = false; 2642 final int serviceCount = userState.mBoundServices.size(); 2643 for (int i = 0; i < serviceCount; i++) { 2644 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 2645 if (canRequestAndRequestsTouchExplorationLocked(service, userState)) { 2646 touchExplorationEnabled = true; 2647 serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled(); 2648 requestMultiFingerGestures = service.isMultiFingerGesturesEnabled(); 2649 requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled(); 2650 sendMotionEvents = service.isSendMotionEventsEnabled(); 2651 break; 2652 } 2653 } 2654 if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) { 2655 userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); 2656 final long identity = Binder.clearCallingIdentity(); 2657 try { 2658 Settings.Secure.putIntForUser(mContext.getContentResolver(), 2659 Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0, 2660 userState.mUserId); 2661 } finally { 2662 Binder.restoreCallingIdentity(identity); 2663 } 2664 } 2665 userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); 2666 userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); 2667 userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough); 2668 userState.setSendMotionEventsEnabled(sendMotionEvents); 2669 } 2670 readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState)2671 private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) { 2672 final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 2673 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId); 2674 final Set<String> targetsFromSetting = new ArraySet<>(); 2675 readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false); 2676 // Fall back to device's default a11y service, only when setting is never updated. 2677 if (settingValue == null) { 2678 final String defaultService = mContext.getString( 2679 R.string.config_defaultAccessibilityService); 2680 if (!TextUtils.isEmpty(defaultService)) { 2681 targetsFromSetting.add(defaultService); 2682 } 2683 } 2684 2685 final Set<String> currentTargets = 2686 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY); 2687 if (targetsFromSetting.equals(currentTargets)) { 2688 return false; 2689 } 2690 currentTargets.clear(); 2691 currentTargets.addAll(targetsFromSetting); 2692 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2693 return true; 2694 } 2695 readAccessibilityButtonTargetsLocked(AccessibilityUserState userState)2696 private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) { 2697 final Set<String> targetsFromSetting = new ArraySet<>(); 2698 readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 2699 userState.mUserId, str -> str, targetsFromSetting); 2700 2701 final Set<String> currentTargets = 2702 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON); 2703 if (targetsFromSetting.equals(currentTargets)) { 2704 return false; 2705 } 2706 currentTargets.clear(); 2707 currentTargets.addAll(targetsFromSetting); 2708 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2709 return true; 2710 } 2711 readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState)2712 private boolean readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState) { 2713 final String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(), 2714 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId); 2715 if (TextUtils.isEmpty(componentId)) { 2716 if (userState.getTargetAssignedToAccessibilityButton() == null) { 2717 return false; 2718 } 2719 userState.setTargetAssignedToAccessibilityButton(null); 2720 return true; 2721 } 2722 if (componentId.equals(userState.getTargetAssignedToAccessibilityButton())) { 2723 return false; 2724 } 2725 userState.setTargetAssignedToAccessibilityButton(componentId); 2726 return true; 2727 } 2728 readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState)2729 private boolean readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState) { 2730 final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser( 2731 mContext.getContentResolver(), 2732 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0, 2733 userState.mUserId); 2734 final int interactiveUiTimeout = Settings.Secure.getIntForUser( 2735 mContext.getContentResolver(), 2736 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0, 2737 userState.mUserId); 2738 if (nonInteractiveUiTimeout != userState.getUserNonInteractiveUiTimeoutLocked() 2739 || interactiveUiTimeout != userState.getUserInteractiveUiTimeoutLocked()) { 2740 userState.setUserNonInteractiveUiTimeoutLocked(nonInteractiveUiTimeout); 2741 userState.setUserInteractiveUiTimeoutLocked(interactiveUiTimeout); 2742 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2743 return true; 2744 } 2745 return false; 2746 } 2747 2748 /** 2749 * Check if the target that will be enabled by the accessibility shortcut key is installed. 2750 * If it isn't, remove it from the list and associated setting so a side loaded service can't 2751 * spoof the package name of the default service. 2752 */ updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState)2753 private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) { 2754 final Set<String> currentTargets = 2755 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY); 2756 final int lastSize = currentTargets.size(); 2757 if (lastSize == 0) { 2758 return; 2759 } 2760 currentTargets.removeIf( 2761 name -> !userState.isShortcutTargetInstalledLocked(name)); 2762 if (lastSize == currentTargets.size()) { 2763 return; 2764 } 2765 2766 // Update setting key with new value. 2767 persistColonDelimitedSetToSettingLocked( 2768 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, 2769 userState.mUserId, currentTargets, str -> str); 2770 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2771 } 2772 canRequestAndRequestsTouchExplorationLocked( AccessibilityServiceConnection service, AccessibilityUserState userState)2773 private boolean canRequestAndRequestsTouchExplorationLocked( 2774 AccessibilityServiceConnection service, AccessibilityUserState userState) { 2775 // Service not ready or cannot request the feature - well nothing to do. 2776 if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) { 2777 return false; 2778 } 2779 if (service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 2780 <= Build.VERSION_CODES.JELLY_BEAN_MR1) { 2781 // Up to JB-MR1 we had a allowlist with services that can enable touch 2782 // exploration. When a service is first started we show a dialog to the 2783 // use to get a permission to allowlist the service. 2784 if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) { 2785 return true; 2786 } else if (mEnableTouchExplorationDialog == null 2787 || !mEnableTouchExplorationDialog.isShowing()) { 2788 mMainHandler.sendMessage(obtainMessage( 2789 AccessibilityManagerService::showEnableTouchExplorationDialog, 2790 this, service)); 2791 } 2792 } else { 2793 // Starting in JB-MR2 we request an accessibility service to declare 2794 // certain capabilities in its meta-data to allow it to enable the 2795 // corresponding features. 2796 if ((service.getCapabilities() 2797 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) { 2798 return true; 2799 } 2800 } 2801 return false; 2802 } 2803 updateMagnificationLocked(AccessibilityUserState userState)2804 private void updateMagnificationLocked(AccessibilityUserState userState) { 2805 if (userState.mUserId != mCurrentUserId) { 2806 return; 2807 } 2808 2809 if (mUiAutomationManager.suppressingAccessibilityServicesLocked() 2810 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) { 2811 getMagnificationController().getFullScreenMagnificationController().unregisterAll(); 2812 return; 2813 } 2814 2815 // Get all valid displays and register them if global magnification is enabled. 2816 // We would skip overlay display because it uses overlay window to simulate secondary 2817 // displays in one display. It's not a real display and there's no input events for it. 2818 final ArrayList<Display> displays = getValidDisplayList(); 2819 if (userState.isDisplayMagnificationEnabledLocked() 2820 || userState.isShortcutMagnificationEnabledLocked()) { 2821 for (int i = 0; i < displays.size(); i++) { 2822 final Display display = displays.get(i); 2823 getMagnificationController().getFullScreenMagnificationController().register( 2824 display.getDisplayId()); 2825 } 2826 return; 2827 } 2828 2829 // Register if display has listening magnification services. 2830 for (int i = 0; i < displays.size(); i++) { 2831 final Display display = displays.get(i); 2832 final int displayId = display.getDisplayId(); 2833 if (userHasListeningMagnificationServicesLocked(userState, displayId)) { 2834 getMagnificationController().getFullScreenMagnificationController().register( 2835 displayId); 2836 } else if (mMagnificationController.isFullScreenMagnificationControllerInitialized()) { 2837 getMagnificationController().getFullScreenMagnificationController().unregister( 2838 displayId); 2839 } 2840 } 2841 } 2842 updateWindowMagnificationConnectionIfNeeded(AccessibilityUserState userState)2843 private void updateWindowMagnificationConnectionIfNeeded(AccessibilityUserState userState) { 2844 if (!mMagnificationController.supportWindowMagnification()) { 2845 return; 2846 } 2847 final boolean connect = (userState.isShortcutMagnificationEnabledLocked() 2848 || userState.isDisplayMagnificationEnabledLocked()) 2849 && (userState.getMagnificationCapabilitiesLocked() 2850 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) 2851 || userHasMagnificationServicesLocked(userState); 2852 getWindowMagnificationMgr().requestConnection(connect); 2853 } 2854 2855 /** 2856 * Returns whether the specified user has any services that are capable of 2857 * controlling magnification. 2858 */ userHasMagnificationServicesLocked(AccessibilityUserState userState)2859 private boolean userHasMagnificationServicesLocked(AccessibilityUserState userState) { 2860 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 2861 for (int i = 0, count = services.size(); i < count; i++) { 2862 final AccessibilityServiceConnection service = services.get(i); 2863 if (mSecurityPolicy.canControlMagnification(service)) { 2864 return true; 2865 } 2866 } 2867 return false; 2868 } 2869 2870 /** 2871 * Returns whether the specified user has any services that are capable of 2872 * controlling magnification and are actively listening for magnification updates. 2873 */ userHasListeningMagnificationServicesLocked(AccessibilityUserState userState, int displayId)2874 private boolean userHasListeningMagnificationServicesLocked(AccessibilityUserState userState, 2875 int displayId) { 2876 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 2877 for (int i = 0, count = services.size(); i < count; i++) { 2878 final AccessibilityServiceConnection service = services.get(i); 2879 if (mSecurityPolicy.canControlMagnification(service) 2880 && service.isMagnificationCallbackEnabled(displayId)) { 2881 return true; 2882 } 2883 } 2884 return false; 2885 } 2886 updateFingerprintGestureHandling(AccessibilityUserState userState)2887 private void updateFingerprintGestureHandling(AccessibilityUserState userState) { 2888 final List<AccessibilityServiceConnection> services; 2889 synchronized (mLock) { 2890 services = userState.mBoundServices; 2891 if ((mFingerprintGestureDispatcher == null) 2892 && mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 2893 // Only create the controller when a service wants to use the feature 2894 int numServices = services.size(); 2895 for (int i = 0; i < numServices; i++) { 2896 if (services.get(i).isCapturingFingerprintGestures()) { 2897 IFingerprintService service = null; 2898 final long identity = Binder.clearCallingIdentity(); 2899 try { 2900 service = IFingerprintService.Stub.asInterface( 2901 ServiceManager.getService(Context.FINGERPRINT_SERVICE)); 2902 } finally { 2903 Binder.restoreCallingIdentity(identity); 2904 } 2905 if (service != null) { 2906 mFingerprintGestureDispatcher = new FingerprintGestureDispatcher( 2907 service, mContext.getResources(), mLock); 2908 break; 2909 } 2910 } 2911 } 2912 } 2913 } 2914 if (mFingerprintGestureDispatcher != null) { 2915 mFingerprintGestureDispatcher.updateClientList(services); 2916 } 2917 } 2918 2919 /** 2920 * 1) Update accessibility button availability to accessibility services. 2921 * 2) Check if the target that will be enabled by the accessibility button is installed. 2922 * If it isn't, remove it from the list and associated setting so a side loaded service can't 2923 * spoof the package name of the default service. 2924 */ updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState)2925 private void updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState) { 2926 // Update accessibility button availability. 2927 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 2928 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 2929 if (service.mRequestAccessibilityButton) { 2930 service.notifyAccessibilityButtonAvailabilityChangedLocked( 2931 service.isAccessibilityButtonAvailableLocked(userState)); 2932 } 2933 } 2934 2935 final Set<String> currentTargets = 2936 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON); 2937 final int lastSize = currentTargets.size(); 2938 if (lastSize == 0) { 2939 return; 2940 } 2941 currentTargets.removeIf( 2942 name -> !userState.isShortcutTargetInstalledLocked(name)); 2943 if (lastSize == currentTargets.size()) { 2944 return; 2945 } 2946 2947 // Update setting key with new value. 2948 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 2949 userState.mUserId, currentTargets, str -> str); 2950 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2951 } 2952 2953 /** 2954 * 1) Check if the service assigned to accessibility button target sdk version > Q. 2955 * If it isn't, remove it from the list and associated setting. 2956 * (It happens when an accessibility service package is downgraded.) 2957 * 2) For a service targeting sdk version > Q and requesting a11y button, it should be in the 2958 * enabled list if's assigned to a11y button. 2959 * (It happens when an accessibility service package is same graded, and updated requesting 2960 * a11y button flag) 2961 * 3) Check if an enabled service targeting sdk version > Q and requesting a11y button is 2962 * assigned to a shortcut. If it isn't, assigns it to the accessibility button. 2963 * (It happens when an enabled accessibility service package is upgraded.) 2964 * 2965 * @param packageName The package name to check, or {@code null} to check all services. 2966 * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0} 2967 * if the caller is not related to the restore. 2968 */ migrateAccessibilityButtonSettingsIfNecessaryLocked( AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt)2969 private void migrateAccessibilityButtonSettingsIfNecessaryLocked( 2970 AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) { 2971 // No need to migrate settings if they are restored from a version after Q. 2972 if (restoreFromSdkInt > Build.VERSION_CODES.Q) { 2973 return; 2974 } 2975 final Set<String> buttonTargets = 2976 userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON); 2977 int lastSize = buttonTargets.size(); 2978 buttonTargets.removeIf(name -> { 2979 if (packageName != null && name != null && !name.contains(packageName)) { 2980 return false; 2981 } 2982 final ComponentName componentName = ComponentName.unflattenFromString(name); 2983 if (componentName == null) { 2984 return false; 2985 } 2986 final AccessibilityServiceInfo serviceInfo = 2987 userState.getInstalledServiceInfoLocked(componentName); 2988 if (serviceInfo == null) { 2989 return false; 2990 } 2991 if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo 2992 .targetSdkVersion <= Build.VERSION_CODES.Q) { 2993 // A11y services targeting sdk version <= Q should not be in the list. 2994 Slog.v(LOG_TAG, "Legacy service " + componentName 2995 + " should not in the button"); 2996 return true; 2997 } 2998 final boolean requestA11yButton = (serviceInfo.flags 2999 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 3000 if (requestA11yButton && !userState.mEnabledServices.contains(componentName)) { 3001 // An a11y service targeting sdk version > Q and request A11y button and is assigned 3002 // to a11y btn should be in the enabled list. 3003 Slog.v(LOG_TAG, "Service requesting a11y button and be assigned to the button" 3004 + componentName + " should be enabled state"); 3005 return true; 3006 } 3007 return false; 3008 }); 3009 boolean changed = (lastSize != buttonTargets.size()); 3010 lastSize = buttonTargets.size(); 3011 3012 final Set<String> shortcutKeyTargets = 3013 userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY); 3014 userState.mEnabledServices.forEach(componentName -> { 3015 if (packageName != null && componentName != null 3016 && !packageName.equals(componentName.getPackageName())) { 3017 return; 3018 } 3019 final AccessibilityServiceInfo serviceInfo = 3020 userState.getInstalledServiceInfoLocked(componentName); 3021 if (serviceInfo == null) { 3022 return; 3023 } 3024 final boolean requestA11yButton = (serviceInfo.flags 3025 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 3026 if (!(serviceInfo.getResolveInfo().serviceInfo.applicationInfo 3027 .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton)) { 3028 return; 3029 } 3030 final String serviceName = componentName.flattenToString(); 3031 if (TextUtils.isEmpty(serviceName)) { 3032 return; 3033 } 3034 if (doesShortcutTargetsStringContain(buttonTargets, serviceName) 3035 || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName)) { 3036 return; 3037 } 3038 // For enabled a11y services targeting sdk version > Q and requesting a11y button should 3039 // be assigned to a shortcut. 3040 Slog.v(LOG_TAG, "A enabled service requesting a11y button " + componentName 3041 + " should be assign to the button or shortcut."); 3042 buttonTargets.add(serviceName); 3043 }); 3044 changed |= (lastSize != buttonTargets.size()); 3045 if (!changed) { 3046 return; 3047 } 3048 3049 // Update setting key with new value. 3050 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 3051 userState.mUserId, buttonTargets, str -> str); 3052 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3053 } 3054 3055 /** 3056 * Remove the shortcut target for the unbound service which is requesting accessibility button 3057 * and targeting sdk > Q from the accessibility button and shortcut. 3058 * 3059 * @param userState The accessibility user state. 3060 * @param service The unbound service. 3061 */ removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState, AccessibilityServiceConnection service)3062 private void removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState, 3063 AccessibilityServiceConnection service) { 3064 if (!service.mRequestAccessibilityButton 3065 || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo 3066 .targetSdkVersion <= Build.VERSION_CODES.Q) { 3067 return; 3068 } 3069 final ComponentName serviceName = service.getComponentName(); 3070 if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) { 3071 final Set<String> currentTargets = userState.getShortcutTargetsLocked( 3072 ACCESSIBILITY_SHORTCUT_KEY); 3073 persistColonDelimitedSetToSettingLocked( 3074 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, 3075 userState.mUserId, currentTargets, str -> str); 3076 } 3077 if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) { 3078 final Set<String> currentTargets = userState.getShortcutTargetsLocked( 3079 ACCESSIBILITY_BUTTON); 3080 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 3081 userState.mUserId, currentTargets, str -> str); 3082 } 3083 } 3084 updateRecommendedUiTimeoutLocked(AccessibilityUserState userState)3085 private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) { 3086 int newNonInteractiveUiTimeout = userState.getUserNonInteractiveUiTimeoutLocked(); 3087 int newInteractiveUiTimeout = userState.getUserInteractiveUiTimeoutLocked(); 3088 // read from a11y services if user does not specify value 3089 if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) { 3090 int serviceNonInteractiveUiTimeout = 0; 3091 int serviceInteractiveUiTimeout = 0; 3092 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 3093 for (int i = 0; i < services.size(); i++) { 3094 int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis(); 3095 if (serviceInteractiveUiTimeout < timeout) { 3096 serviceInteractiveUiTimeout = timeout; 3097 } 3098 timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis(); 3099 if (serviceNonInteractiveUiTimeout < timeout) { 3100 serviceNonInteractiveUiTimeout = timeout; 3101 } 3102 } 3103 if (newNonInteractiveUiTimeout == 0) { 3104 newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout; 3105 } 3106 if (newInteractiveUiTimeout == 0) { 3107 newInteractiveUiTimeout = serviceInteractiveUiTimeout; 3108 } 3109 } 3110 userState.setNonInteractiveUiTimeoutLocked(newNonInteractiveUiTimeout); 3111 userState.setInteractiveUiTimeoutLocked(newInteractiveUiTimeout); 3112 } 3113 3114 @Override getKeyEventDispatcher()3115 public KeyEventDispatcher getKeyEventDispatcher() { 3116 if (mKeyEventDispatcher == null) { 3117 mKeyEventDispatcher = new KeyEventDispatcher( 3118 mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock, 3119 mPowerManager); 3120 } 3121 return mKeyEventDispatcher; 3122 } 3123 3124 @Override 3125 @SuppressWarnings("AndroidFrameworkPendingIntentMutability") getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)3126 public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent, 3127 int flags) { 3128 return PendingIntent.getActivity(context, requestCode, intent, flags); 3129 } 3130 3131 /** 3132 * AIDL-exposed method to be called when the accessibility shortcut key is enabled. Requires 3133 * permission to write secure settings, since someone with that permission can enable 3134 * accessibility services themselves. 3135 * 3136 * @param targetName The flattened {@link ComponentName} string or the class name of a system 3137 * class implementing a supported accessibility feature, or {@code null} if there's no 3138 * specified target. 3139 */ 3140 @Override performAccessibilityShortcut(String targetName)3141 public void performAccessibilityShortcut(String targetName) { 3142 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3143 mTraceManager.logTrace(LOG_TAG + ".performAccessibilityShortcut", 3144 FLAGS_ACCESSIBILITY_MANAGER, "targetName=" + targetName); 3145 } 3146 3147 if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) 3148 && (mContext.checkCallingPermission(Manifest.permission.MANAGE_ACCESSIBILITY) 3149 != PackageManager.PERMISSION_GRANTED)) { 3150 throw new SecurityException( 3151 "performAccessibilityShortcut requires the MANAGE_ACCESSIBILITY permission"); 3152 } 3153 mMainHandler.sendMessage(obtainMessage( 3154 AccessibilityManagerService::performAccessibilityShortcutInternal, this, 3155 Display.DEFAULT_DISPLAY, ACCESSIBILITY_SHORTCUT_KEY, targetName)); 3156 } 3157 3158 /** 3159 * Perform the accessibility shortcut action. 3160 * 3161 * @param shortcutType The shortcut type. 3162 * @param displayId The display id of the accessibility button. 3163 * @param targetName The flattened {@link ComponentName} string or the class name of a system 3164 * class implementing a supported accessibility feature, or {@code null} if there's no 3165 * specified target. 3166 */ performAccessibilityShortcutInternal(int displayId, @ShortcutType int shortcutType, @Nullable String targetName)3167 private void performAccessibilityShortcutInternal(int displayId, 3168 @ShortcutType int shortcutType, @Nullable String targetName) { 3169 final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType); 3170 if (shortcutTargets.isEmpty()) { 3171 Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType); 3172 return; 3173 } 3174 // In case the caller specified a target name 3175 if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets, targetName)) { 3176 Slog.v(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName); 3177 targetName = null; 3178 } 3179 if (targetName == null) { 3180 // In case there are many targets assigned to the given shortcut. 3181 if (shortcutTargets.size() > 1) { 3182 showAccessibilityTargetsSelection(displayId, shortcutType); 3183 return; 3184 } 3185 targetName = shortcutTargets.get(0); 3186 } 3187 // In case user assigned magnification to the given shortcut. 3188 if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) { 3189 final boolean enabled = 3190 !getMagnificationController().getFullScreenMagnificationController() 3191 .isMagnifying(displayId); 3192 logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType, 3193 enabled); 3194 sendAccessibilityButtonToInputFilter(displayId); 3195 return; 3196 } 3197 final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName); 3198 if (targetComponentName == null) { 3199 Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName); 3200 return; 3201 } 3202 // In case user assigned an accessibility framework feature to the given shortcut. 3203 if (performAccessibilityFrameworkFeature(targetComponentName, shortcutType)) { 3204 return; 3205 } 3206 // In case user assigned an accessibility shortcut target to the given shortcut. 3207 if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) { 3208 logAccessibilityShortcutActivated(mContext, targetComponentName, shortcutType); 3209 return; 3210 } 3211 // in case user assigned an accessibility service to the given shortcut. 3212 if (performAccessibilityShortcutTargetService( 3213 displayId, shortcutType, targetComponentName)) { 3214 return; 3215 } 3216 } 3217 performAccessibilityFrameworkFeature(ComponentName assignedTarget, @ShortcutType int shortcutType)3218 private boolean performAccessibilityFrameworkFeature(ComponentName assignedTarget, 3219 @ShortcutType int shortcutType) { 3220 final Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureMap = 3221 AccessibilityShortcutController.getFrameworkShortcutFeaturesMap(); 3222 if (!frameworkFeatureMap.containsKey(assignedTarget)) { 3223 return false; 3224 } 3225 // Toggle the requested framework feature 3226 final ToggleableFrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(assignedTarget); 3227 final SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(), 3228 featureInfo.getSettingKey(), mCurrentUserId); 3229 // Assuming that the default state will be to have the feature off 3230 if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) { 3231 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 3232 /* serviceEnabled= */ true); 3233 setting.write(featureInfo.getSettingOnValue()); 3234 } else { 3235 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 3236 /* serviceEnabled= */ false); 3237 setting.write(featureInfo.getSettingOffValue()); 3238 } 3239 return true; 3240 } 3241 performAccessibilityShortcutTargetActivity(int displayId, ComponentName assignedTarget)3242 private boolean performAccessibilityShortcutTargetActivity(int displayId, 3243 ComponentName assignedTarget) { 3244 synchronized (mLock) { 3245 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3246 for (int i = 0; i < userState.mInstalledShortcuts.size(); i++) { 3247 final AccessibilityShortcutInfo shortcutInfo = userState.mInstalledShortcuts.get(i); 3248 if (!shortcutInfo.getComponentName().equals(assignedTarget)) { 3249 continue; 3250 } 3251 launchShortcutTargetActivity(displayId, assignedTarget); 3252 return true; 3253 } 3254 } 3255 return false; 3256 } 3257 3258 /** 3259 * Perform accessibility service shortcut action. 3260 * 3261 * 1) For {@link AccessibilityManager#ACCESSIBILITY_BUTTON} type and services targeting sdk 3262 * version <= Q: callbacks to accessibility service if service is bounded and requests 3263 * accessibility button. 3264 * 2) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk 3265 * version <= Q: turns on / off the accessibility service. 3266 * 3) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk 3267 * version > Q and request accessibility button: turn on the accessibility service if it's 3268 * not in the enabled state. 3269 * (It'll happen when a service is disabled and assigned to shortcut then upgraded.) 3270 * 4) For services targeting sdk version > Q: 3271 * a) Turns on / off the accessibility service, if service does not request accessibility 3272 * button. 3273 * b) Callbacks to accessibility service if service is bounded and requests accessibility 3274 * button. 3275 */ performAccessibilityShortcutTargetService(int displayId, @ShortcutType int shortcutType, ComponentName assignedTarget)3276 private boolean performAccessibilityShortcutTargetService(int displayId, 3277 @ShortcutType int shortcutType, ComponentName assignedTarget) { 3278 synchronized (mLock) { 3279 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3280 final AccessibilityServiceInfo installedServiceInfo = 3281 userState.getInstalledServiceInfoLocked(assignedTarget); 3282 if (installedServiceInfo == null) { 3283 Slog.d(LOG_TAG, "Perform shortcut failed, invalid component name:" 3284 + assignedTarget); 3285 return false; 3286 } 3287 3288 final AccessibilityServiceConnection serviceConnection = 3289 userState.getServiceConnectionLocked(assignedTarget); 3290 final int targetSdk = installedServiceInfo.getResolveInfo() 3291 .serviceInfo.applicationInfo.targetSdkVersion; 3292 final boolean requestA11yButton = (installedServiceInfo.flags 3293 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 3294 // Turns on / off the accessibility service 3295 if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY) 3296 || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) { 3297 if (serviceConnection == null) { 3298 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 3299 /* serviceEnabled= */ true); 3300 enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); 3301 3302 } else { 3303 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 3304 /* serviceEnabled= */ false); 3305 disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); 3306 } 3307 return true; 3308 } 3309 if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY && targetSdk > Build.VERSION_CODES.Q 3310 && requestA11yButton) { 3311 if (!userState.getEnabledServicesLocked().contains(assignedTarget)) { 3312 enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); 3313 return true; 3314 } 3315 } 3316 // Callbacks to a11y service if it's bounded and requests a11y button. 3317 if (serviceConnection == null 3318 || !userState.mBoundServices.contains(serviceConnection) 3319 || !serviceConnection.mRequestAccessibilityButton) { 3320 Slog.d(LOG_TAG, "Perform shortcut failed, service is not ready:" 3321 + assignedTarget); 3322 return false; 3323 } 3324 // ServiceConnection means service enabled. 3325 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 3326 /* serviceEnabled= */ true); 3327 serviceConnection.notifyAccessibilityButtonClickedLocked(displayId); 3328 return true; 3329 } 3330 } 3331 3332 @Override getAccessibilityShortcutTargets(@hortcutType int shortcutType)3333 public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) { 3334 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3335 mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets", 3336 FLAGS_ACCESSIBILITY_MANAGER, "shortcutType=" + shortcutType); 3337 } 3338 3339 if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY) 3340 != PackageManager.PERMISSION_GRANTED) { 3341 throw new SecurityException( 3342 "getAccessibilityShortcutService requires the MANAGE_ACCESSIBILITY permission"); 3343 } 3344 return getAccessibilityShortcutTargetsInternal(shortcutType); 3345 } 3346 getAccessibilityShortcutTargetsInternal(@hortcutType int shortcutType)3347 private List<String> getAccessibilityShortcutTargetsInternal(@ShortcutType int shortcutType) { 3348 synchronized (mLock) { 3349 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3350 final ArrayList<String> shortcutTargets = new ArrayList<>( 3351 userState.getShortcutTargetsLocked(shortcutType)); 3352 if (shortcutType != ACCESSIBILITY_BUTTON) { 3353 return shortcutTargets; 3354 } 3355 // Adds legacy a11y services requesting a11y button into the list. 3356 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 3357 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 3358 if (!service.mRequestAccessibilityButton 3359 || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo 3360 .targetSdkVersion > Build.VERSION_CODES.Q) { 3361 continue; 3362 } 3363 final String serviceName = service.getComponentName().flattenToString(); 3364 if (!TextUtils.isEmpty(serviceName)) { 3365 shortcutTargets.add(serviceName); 3366 } 3367 } 3368 return shortcutTargets; 3369 } 3370 } 3371 3372 /** 3373 * Enables accessibility service specified by {@param componentName} for the {@param userId}. 3374 */ enableAccessibilityServiceLocked(ComponentName componentName, int userId)3375 private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) { 3376 mTempComponentNameSet.clear(); 3377 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 3378 userId, mTempComponentNameSet); 3379 mTempComponentNameSet.add(componentName); 3380 persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 3381 mTempComponentNameSet, userId); 3382 3383 AccessibilityUserState userState = getUserStateLocked(userId); 3384 if (userState.mEnabledServices.add(componentName)) { 3385 onUserStateChangedLocked(userState); 3386 } 3387 } 3388 3389 /** 3390 * Disables accessibility service specified by {@param componentName} for the {@param userId}. 3391 */ disableAccessibilityServiceLocked(ComponentName componentName, int userId)3392 private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) { 3393 mTempComponentNameSet.clear(); 3394 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 3395 userId, mTempComponentNameSet); 3396 mTempComponentNameSet.remove(componentName); 3397 persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 3398 mTempComponentNameSet, userId); 3399 3400 AccessibilityUserState userState = getUserStateLocked(userId); 3401 if (userState.mEnabledServices.remove(componentName)) { 3402 onUserStateChangedLocked(userState); 3403 } 3404 } 3405 3406 @Override sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event)3407 public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) { 3408 if (event.getWindowChanges() == AccessibilityEvent.WINDOWS_CHANGE_ADDED) { 3409 // We need to ensure the window is available before sending pending 3410 // window_state_changed events. 3411 sendPendingWindowStateChangedEventsForAvailableWindowLocked(event.getWindowId()); 3412 } 3413 sendAccessibilityEventLocked(event, mCurrentUserId); 3414 } 3415 sendAccessibilityEventLocked(AccessibilityEvent event, int userId)3416 private void sendAccessibilityEventLocked(AccessibilityEvent event, int userId) { 3417 // Resync to avoid calling out with the lock held 3418 event.setEventTime(SystemClock.uptimeMillis()); 3419 mMainHandler.sendMessage(obtainMessage( 3420 AccessibilityManagerService::sendAccessibilityEvent, 3421 this, event, userId)); 3422 } 3423 3424 /** 3425 * AIDL-exposed method. System only. 3426 * Inform accessibility that a fingerprint gesture was performed 3427 * 3428 * @param gestureKeyCode The key code corresponding to the fingerprint gesture. 3429 * @return {@code true} if accessibility consumes the fingerprint gesture, {@code false} if it 3430 * doesn't. 3431 */ 3432 @Override sendFingerprintGesture(int gestureKeyCode)3433 public boolean sendFingerprintGesture(int gestureKeyCode) { 3434 if (mTraceManager.isA11yTracingEnabledForTypes( 3435 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT)) { 3436 mTraceManager.logTrace(LOG_TAG + ".sendFingerprintGesture", 3437 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT, 3438 "gestureKeyCode=" + gestureKeyCode); 3439 } 3440 3441 synchronized(mLock) { 3442 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { 3443 throw new SecurityException("Only SYSTEM can call sendFingerprintGesture"); 3444 } 3445 } 3446 if (mFingerprintGestureDispatcher == null) { 3447 return false; 3448 } 3449 return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode); 3450 } 3451 3452 /** 3453 * AIDL-exposed method. System only. 3454 * Gets accessibility window id from window token. 3455 * 3456 * @param windowToken Window token to get accessibility window id. 3457 * @return Accessibility window id for the window token. Returns -1 if no such token is 3458 * registered. 3459 */ 3460 @Override getAccessibilityWindowId(@ullable IBinder windowToken)3461 public int getAccessibilityWindowId(@Nullable IBinder windowToken) { 3462 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3463 mTraceManager.logTrace(LOG_TAG + ".getAccessibilityWindowId", 3464 FLAGS_ACCESSIBILITY_MANAGER, "windowToken=" + windowToken); 3465 } 3466 3467 synchronized (mLock) { 3468 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { 3469 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId"); 3470 } 3471 3472 return mA11yWindowManager.findWindowIdLocked(mCurrentUserId, windowToken); 3473 } 3474 } 3475 3476 /** 3477 * Get the recommended timeout of interactive controls and non-interactive controls. 3478 * 3479 * @return A long for pair of {@code int}s. First integer for interactive one, and second 3480 * integer for non-interactive one. 3481 */ 3482 @Override getRecommendedTimeoutMillis()3483 public long getRecommendedTimeoutMillis() { 3484 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3485 mTraceManager.logTrace( 3486 LOG_TAG + ".getRecommendedTimeoutMillis", FLAGS_ACCESSIBILITY_MANAGER); 3487 } 3488 3489 synchronized(mLock) { 3490 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3491 return getRecommendedTimeoutMillisLocked(userState); 3492 } 3493 } 3494 getRecommendedTimeoutMillisLocked(AccessibilityUserState userState)3495 private long getRecommendedTimeoutMillisLocked(AccessibilityUserState userState) { 3496 return IntPair.of(userState.getInteractiveUiTimeoutLocked(), 3497 userState.getNonInteractiveUiTimeoutLocked()); 3498 } 3499 3500 @Override setWindowMagnificationConnection( IWindowMagnificationConnection connection)3501 public void setWindowMagnificationConnection( 3502 IWindowMagnificationConnection connection) throws RemoteException { 3503 if (mTraceManager.isA11yTracingEnabledForTypes( 3504 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_WINDOW_MAGNIFICATION_CONNECTION)) { 3505 mTraceManager.logTrace(LOG_TAG + ".setWindowMagnificationConnection", 3506 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_WINDOW_MAGNIFICATION_CONNECTION, 3507 "connection=" + connection); 3508 } 3509 3510 mSecurityPolicy.enforceCallingOrSelfPermission( 3511 android.Manifest.permission.STATUS_BAR_SERVICE); 3512 3513 getWindowMagnificationMgr().setConnection(connection); 3514 } 3515 3516 /** 3517 * Getter of {@link WindowMagnificationManager}. 3518 * 3519 * @return WindowMagnificationManager 3520 */ getWindowMagnificationMgr()3521 public WindowMagnificationManager getWindowMagnificationMgr() { 3522 synchronized (mLock) { 3523 return mMagnificationController.getWindowMagnificationMgr(); 3524 } 3525 } 3526 3527 /** 3528 * Getter of {@link MagnificationController}. 3529 * 3530 * @return MagnificationController 3531 */ getMagnificationController()3532 MagnificationController getMagnificationController() { 3533 return mMagnificationController; 3534 } 3535 3536 @Override associateEmbeddedHierarchy(@onNull IBinder host, @NonNull IBinder embedded)3537 public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) { 3538 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3539 mTraceManager.logTrace(LOG_TAG + ".associateEmbeddedHierarchy", 3540 FLAGS_ACCESSIBILITY_MANAGER, "host=" + host + ";embedded=" + embedded); 3541 } 3542 3543 synchronized (mLock) { 3544 mA11yWindowManager.associateEmbeddedHierarchyLocked(host, embedded); 3545 } 3546 } 3547 3548 @Override disassociateEmbeddedHierarchy(@onNull IBinder token)3549 public void disassociateEmbeddedHierarchy(@NonNull IBinder token) { 3550 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3551 mTraceManager.logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy", 3552 FLAGS_ACCESSIBILITY_MANAGER, "token=" + token); 3553 } 3554 3555 synchronized (mLock) { 3556 mA11yWindowManager.disassociateEmbeddedHierarchyLocked(token); 3557 } 3558 } 3559 3560 /** 3561 * Gets the stroke width of the focus rectangle. 3562 * @return The stroke width. 3563 */ 3564 @Override getFocusStrokeWidth()3565 public int getFocusStrokeWidth() { 3566 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3567 mTraceManager.logTrace(LOG_TAG + ".getFocusStrokeWidth", FLAGS_ACCESSIBILITY_MANAGER); 3568 } 3569 synchronized (mLock) { 3570 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3571 3572 return userState.getFocusStrokeWidthLocked(); 3573 } 3574 } 3575 3576 /** 3577 * Gets the color of the focus rectangle. 3578 * @return The color. 3579 */ 3580 @Override getFocusColor()3581 public int getFocusColor() { 3582 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3583 mTraceManager.logTrace(LOG_TAG + ".getFocusColor", FLAGS_ACCESSIBILITY_MANAGER); 3584 } 3585 synchronized (mLock) { 3586 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3587 3588 return userState.getFocusColorLocked(); 3589 } 3590 } 3591 3592 /** 3593 * Gets the status of the audio description preference. 3594 * @return {@code true} if the audio description is enabled, {@code false} otherwise. 3595 */ 3596 @Override isAudioDescriptionByDefaultEnabled()3597 public boolean isAudioDescriptionByDefaultEnabled() { 3598 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3599 mTraceManager.logTrace(LOG_TAG + ".isAudioDescriptionByDefaultEnabled", 3600 FLAGS_ACCESSIBILITY_MANAGER); 3601 } 3602 synchronized (mLock) { 3603 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3604 3605 return userState.isAudioDescriptionByDefaultEnabledLocked(); 3606 } 3607 } 3608 3609 @Override 3610 @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) setSystemAudioCaptioningEnabled(boolean isEnabled, int userId)3611 public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) { 3612 mContext.enforceCallingOrSelfPermission( 3613 Manifest.permission.SET_SYSTEM_AUDIO_CAPTION, 3614 "setSystemAudioCaptioningEnabled"); 3615 3616 mCaptioningManagerImpl.setSystemAudioCaptioningEnabled(isEnabled, userId); 3617 } 3618 3619 @Override isSystemAudioCaptioningUiEnabled(int userId)3620 public boolean isSystemAudioCaptioningUiEnabled(int userId) { 3621 return mCaptioningManagerImpl.isSystemAudioCaptioningUiEnabled(userId); 3622 } 3623 3624 @Override 3625 @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId)3626 public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) { 3627 mContext.enforceCallingOrSelfPermission( 3628 Manifest.permission.SET_SYSTEM_AUDIO_CAPTION, 3629 "setSystemAudioCaptioningUiEnabled"); 3630 3631 mCaptioningManagerImpl.setSystemAudioCaptioningUiEnabled(isEnabled, userId); 3632 } 3633 3634 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)3635 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 3636 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; 3637 synchronized (mLock) { 3638 pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)"); 3639 pw.println(); 3640 pw.append("currentUserId=").append(String.valueOf(mCurrentUserId)); 3641 pw.println(); 3642 pw.append("hasWindowMagnificationConnection=").append( 3643 String.valueOf(getWindowMagnificationMgr().isConnected())); 3644 pw.println(); 3645 mMagnificationProcessor.dump(pw, getValidDisplayList()); 3646 final int userCount = mUserStates.size(); 3647 for (int i = 0; i < userCount; i++) { 3648 mUserStates.valueAt(i).dump(fd, pw, args); 3649 } 3650 if (mUiAutomationManager.isUiAutomationRunningLocked()) { 3651 mUiAutomationManager.dumpUiAutomationService(fd, pw, args); 3652 pw.println(); 3653 } 3654 mA11yWindowManager.dump(fd, pw, args); 3655 if (mHasInputFilter && mInputFilter != null) { 3656 mInputFilter.dump(fd, pw, args); 3657 } 3658 pw.println("Global client list info:{"); 3659 mGlobalClients.dump(pw, " Client list "); 3660 pw.println(" Registered clients:{"); 3661 for (int i = 0; i < mGlobalClients.getRegisteredCallbackCount(); i++) { 3662 AccessibilityManagerService.Client client = (AccessibilityManagerService.Client) 3663 mGlobalClients.getRegisteredCallbackCookie(i); 3664 pw.append(Arrays.toString(client.mPackageNames)); 3665 } 3666 } 3667 } 3668 3669 //TODO remove after refactoring KeyEventDispatcherTest 3670 final class MainHandler extends Handler { 3671 public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8; 3672 MainHandler(Looper looper)3673 public MainHandler(Looper looper) { 3674 super(looper); 3675 } 3676 3677 @Override handleMessage(Message msg)3678 public void handleMessage(Message msg) { 3679 if (msg.what == MSG_SEND_KEY_EVENT_TO_INPUT_FILTER) { 3680 KeyEvent event = (KeyEvent) msg.obj; 3681 final int policyFlags = msg.arg1; 3682 synchronized (mLock) { 3683 if (mHasInputFilter && mInputFilter != null) { 3684 mInputFilter.sendInputEvent(event, policyFlags); 3685 } 3686 } 3687 event.recycle(); 3688 } 3689 } 3690 } 3691 3692 @Override getMagnificationProcessor()3693 public MagnificationProcessor getMagnificationProcessor() { 3694 return mMagnificationProcessor; 3695 } 3696 3697 @Override onClientChangeLocked(boolean serviceInfoChanged)3698 public void onClientChangeLocked(boolean serviceInfoChanged) { 3699 AccessibilityUserState userState = getUserStateLocked(mCurrentUserId); 3700 onUserStateChangedLocked(userState); 3701 if (serviceInfoChanged) { 3702 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3703 } 3704 } 3705 3706 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)3707 public void onShellCommand(FileDescriptor in, FileDescriptor out, 3708 FileDescriptor err, String[] args, ShellCallback callback, 3709 ResultReceiver resultReceiver) { 3710 new AccessibilityShellCommand(this, mSystemActionPerformer).exec(this, in, out, err, args, 3711 callback, resultReceiver); 3712 } 3713 3714 private final class InteractionBridge { 3715 private final ComponentName COMPONENT_NAME = 3716 new ComponentName("com.android.server.accessibility", "InteractionBridge"); 3717 3718 private final Display mDefaultDisplay; 3719 private final int mConnectionId; 3720 private final AccessibilityInteractionClient mClient; 3721 InteractionBridge()3722 public InteractionBridge() { 3723 final AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 3724 info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); 3725 info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 3726 info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 3727 final AccessibilityUserState userState; 3728 synchronized (mLock) { 3729 userState = getCurrentUserStateLocked(); 3730 } 3731 AccessibilityServiceConnection service = new AccessibilityServiceConnection( 3732 userState, mContext, 3733 COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, 3734 AccessibilityManagerService.this, 3735 AccessibilityManagerService.this.getTraceManager(), mWindowManagerService, 3736 getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) { 3737 @Override 3738 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { 3739 return true; 3740 } 3741 }; 3742 3743 mConnectionId = service.mId; 3744 3745 mClient = AccessibilityInteractionClient.getInstance(mContext); 3746 mClient.addConnection(mConnectionId, service, /*initializeCache=*/false); 3747 3748 //TODO: (multi-display) We need to support multiple displays. 3749 DisplayManager displayManager = (DisplayManager) 3750 mContext.getSystemService(Context.DISPLAY_SERVICE); 3751 mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 3752 } 3753 3754 /** 3755 * Gets a point within the accessibility focused node where we can send down and up events 3756 * to perform a click. 3757 * 3758 * @param outPoint The click point to populate. 3759 * @return Whether accessibility a click point was found and set. 3760 */ 3761 // TODO: (multi-display) Make sure this works for multiple displays. getAccessibilityFocusClickPointInScreen(Point outPoint)3762 boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { 3763 return getInteractionBridge() 3764 .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); 3765 } 3766 3767 /** 3768 * Perform an accessibility action on the view that currently has accessibility focus. 3769 * Has no effect if no item has accessibility focus, if the item with accessibility 3770 * focus does not expose the specified action, or if the action fails. 3771 * 3772 * @param action The action to perform. 3773 * 3774 * @return {@code true} if the action was performed. {@code false} if it was not. 3775 */ performActionOnAccessibilityFocusedItemNotLocked( AccessibilityNodeInfo.AccessibilityAction action)3776 public boolean performActionOnAccessibilityFocusedItemNotLocked( 3777 AccessibilityNodeInfo.AccessibilityAction action) { 3778 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); 3779 if ((focus == null) || !focus.getActionList().contains(action)) { 3780 return false; 3781 } 3782 return focus.performAction(action.getId()); 3783 } 3784 getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint)3785 public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { 3786 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); 3787 if (focus == null) { 3788 return false; 3789 } 3790 3791 synchronized (mLock) { 3792 Rect boundsInScreenBeforeMagnification = mTempRect; 3793 3794 focus.getBoundsInScreen(boundsInScreenBeforeMagnification); 3795 final Point nodeCenter = new Point(boundsInScreenBeforeMagnification.centerX(), 3796 boundsInScreenBeforeMagnification.centerY()); 3797 3798 // Invert magnification if needed. 3799 final Pair<float[], MagnificationSpec> pair = 3800 getWindowTransformationMatrixAndMagnificationSpec(focus.getWindowId()); 3801 MagnificationSpec spec = null; 3802 if (pair != null && pair.second != null) { 3803 spec = new MagnificationSpec(); 3804 spec.setTo(pair.second); 3805 } 3806 3807 if (spec != null && !spec.isNop()) { 3808 boundsInScreenBeforeMagnification.offset((int) -spec.offsetX, 3809 (int) -spec.offsetY); 3810 boundsInScreenBeforeMagnification.scale(1 / spec.scale); 3811 } 3812 3813 //Clip to the window bounds. 3814 Rect windowBounds = mTempRect1; 3815 getWindowBounds(focus.getWindowId(), windowBounds); 3816 if (!boundsInScreenBeforeMagnification.intersect(windowBounds)) { 3817 return false; 3818 } 3819 3820 //Clip to the screen bounds. 3821 Point screenSize = mTempPoint; 3822 mDefaultDisplay.getRealSize(screenSize); 3823 if (!boundsInScreenBeforeMagnification.intersect(0, 0, screenSize.x, 3824 screenSize.y)) { 3825 return false; 3826 } 3827 3828 outPoint.set(nodeCenter.x, nodeCenter.y); 3829 } 3830 3831 return true; 3832 } 3833 getAccessibilityFocusNotLocked()3834 private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { 3835 final int focusedWindowId; 3836 synchronized (mLock) { 3837 focusedWindowId = mA11yWindowManager.getFocusedWindowId( 3838 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 3839 if (focusedWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { 3840 return null; 3841 } 3842 } 3843 return getAccessibilityFocusNotLocked(focusedWindowId); 3844 } 3845 getAccessibilityFocusNotLocked(int windowId)3846 private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) { 3847 return mClient.findFocus(mConnectionId, 3848 windowId, AccessibilityNodeInfo.ROOT_NODE_ID, 3849 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 3850 } 3851 } 3852 3853 /** 3854 * Gets all currently valid logical displays. 3855 * 3856 * @return An array list containing all valid logical displays. 3857 */ getValidDisplayList()3858 public ArrayList<Display> getValidDisplayList() { 3859 return mA11yDisplayListener.getValidDisplayList(); 3860 } 3861 3862 /** 3863 * A Utility class to handle display state. 3864 */ 3865 public class AccessibilityDisplayListener implements DisplayManager.DisplayListener { 3866 private final DisplayManager mDisplayManager; 3867 private final ArrayList<Display> mDisplaysList = new ArrayList<>(); 3868 private int mSystemUiUid = 0; 3869 AccessibilityDisplayListener(Context context, MainHandler handler)3870 AccessibilityDisplayListener(Context context, MainHandler handler) { 3871 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 3872 mDisplayManager.registerDisplayListener(this, handler); 3873 initializeDisplayList(); 3874 3875 final PackageManagerInternal pm = 3876 LocalServices.getService(PackageManagerInternal.class); 3877 if (pm != null) { 3878 mSystemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(), 3879 PackageManager.MATCH_SYSTEM_ONLY, mCurrentUserId); 3880 } 3881 } 3882 3883 /** 3884 * Gets all currently valid logical displays. 3885 * 3886 * @return An array list containing all valid logical displays. 3887 */ getValidDisplayList()3888 public ArrayList<Display> getValidDisplayList() { 3889 synchronized (mLock) { 3890 return mDisplaysList; 3891 } 3892 } 3893 initializeDisplayList()3894 private void initializeDisplayList() { 3895 final Display[] displays = mDisplayManager.getDisplays(); 3896 synchronized (mLock) { 3897 mDisplaysList.clear(); 3898 for (int i = 0; i < displays.length; i++) { 3899 // Exclude overlay virtual displays. The display list is for A11yInputFilter 3900 // to create event handler per display. The events should be handled by the 3901 // display which is overlaid by it. 3902 final Display display = displays[i]; 3903 if (isValidDisplay(display)) { 3904 mDisplaysList.add(display); 3905 } 3906 } 3907 } 3908 } 3909 3910 @Override onDisplayAdded(int displayId)3911 public void onDisplayAdded(int displayId) { 3912 final Display display = mDisplayManager.getDisplay(displayId); 3913 if (!isValidDisplay(display)) { 3914 return; 3915 } 3916 3917 synchronized (mLock) { 3918 mDisplaysList.add(display); 3919 if (mInputFilter != null) { 3920 mInputFilter.onDisplayAdded(display); 3921 } 3922 AccessibilityUserState userState = getCurrentUserStateLocked(); 3923 if (displayId != Display.DEFAULT_DISPLAY) { 3924 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 3925 for (int i = 0; i < services.size(); i++) { 3926 AccessibilityServiceConnection boundClient = services.get(i); 3927 boundClient.onDisplayAdded(displayId); 3928 } 3929 } 3930 updateMagnificationLocked(userState); 3931 updateWindowsForAccessibilityCallbackLocked(userState); 3932 notifyClearAccessibilityCacheLocked(); 3933 } 3934 } 3935 3936 @Override onDisplayRemoved(int displayId)3937 public void onDisplayRemoved(int displayId) { 3938 synchronized (mLock) { 3939 if (!removeDisplayFromList(displayId)) { 3940 return; 3941 } 3942 if (mInputFilter != null) { 3943 mInputFilter.onDisplayRemoved(displayId); 3944 } 3945 AccessibilityUserState userState = getCurrentUserStateLocked(); 3946 if (displayId != Display.DEFAULT_DISPLAY) { 3947 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 3948 for (int i = 0; i < services.size(); i++) { 3949 AccessibilityServiceConnection boundClient = services.get(i); 3950 boundClient.onDisplayRemoved(displayId); 3951 } 3952 } 3953 } 3954 mMagnificationController.onDisplayRemoved(displayId); 3955 mA11yWindowManager.stopTrackingWindows(displayId); 3956 } 3957 3958 @GuardedBy("mLock") removeDisplayFromList(int displayId)3959 private boolean removeDisplayFromList(int displayId) { 3960 for (int i = 0; i < mDisplaysList.size(); i++) { 3961 if (mDisplaysList.get(i).getDisplayId() == displayId) { 3962 mDisplaysList.remove(i); 3963 return true; 3964 } 3965 } 3966 return false; 3967 } 3968 3969 @Override onDisplayChanged(int displayId)3970 public void onDisplayChanged(int displayId) { 3971 /* do nothing */ 3972 } 3973 isValidDisplay(@ullable Display display)3974 private boolean isValidDisplay(@Nullable Display display) { 3975 if (display == null || display.getType() == Display.TYPE_OVERLAY) { 3976 return false; 3977 } 3978 // Private virtual displays are created by the ap and is not allowed to access by other 3979 // aps. We assume we could ignore them. 3980 // The exceptional case is for bubbles. Because the bubbles use the activityView, and 3981 // the virtual display of the activityView is private, so if the owner UID of the 3982 // private virtual display is the one of system ui which creates the virtual display of 3983 // bubbles, then this private virtual display should track the windows. 3984 if (display.getType() == Display.TYPE_VIRTUAL 3985 && (display.getFlags() & Display.FLAG_PRIVATE) != 0 3986 && display.getOwnerUid() != mSystemUiUid) { 3987 return false; 3988 } 3989 return true; 3990 } 3991 } 3992 3993 /** Represents an {@link AccessibilityManager} */ 3994 class Client { 3995 final IAccessibilityManagerClient mCallback; 3996 final String[] mPackageNames; 3997 int mLastSentRelevantEventTypes; 3998 Client(IAccessibilityManagerClient callback, int clientUid, AccessibilityUserState userState)3999 private Client(IAccessibilityManagerClient callback, int clientUid, 4000 AccessibilityUserState userState) { 4001 mCallback = callback; 4002 mPackageNames = mPackageManager.getPackagesForUid(clientUid); 4003 synchronized (mLock) { 4004 mLastSentRelevantEventTypes = computeRelevantEventTypesLocked(userState, this); 4005 } 4006 } 4007 } 4008 4009 private final class AccessibilityContentObserver extends ContentObserver { 4010 4011 private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor( 4012 Settings.Secure.TOUCH_EXPLORATION_ENABLED); 4013 4014 private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor( 4015 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 4016 4017 private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor( 4018 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED); 4019 4020 private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor( 4021 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 4022 4023 private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure 4024 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); 4025 4026 private final Uri mHighTextContrastUri = Settings.Secure.getUriFor( 4027 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED); 4028 4029 private final Uri mAudioDescriptionByDefaultUri = Settings.Secure.getUriFor( 4030 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT); 4031 4032 private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor( 4033 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); 4034 4035 private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor( 4036 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); 4037 4038 private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor( 4039 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); 4040 4041 private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor( 4042 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT); 4043 4044 private final Uri mAccessibilityButtonTargetsUri = Settings.Secure.getUriFor( 4045 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); 4046 4047 private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor( 4048 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS); 4049 4050 private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor( 4051 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS); 4052 4053 private final Uri mMagnificationModeUri = Settings.Secure.getUriFor( 4054 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE); 4055 4056 private final Uri mMagnificationCapabilityUri = Settings.Secure.getUriFor( 4057 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY); 4058 4059 private final Uri mMagnificationFollowTypingUri = Settings.Secure.getUriFor( 4060 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED); 4061 AccessibilityContentObserver(Handler handler)4062 public AccessibilityContentObserver(Handler handler) { 4063 super(handler); 4064 } 4065 register(ContentResolver contentResolver)4066 public void register(ContentResolver contentResolver) { 4067 contentResolver.registerContentObserver(mTouchExplorationEnabledUri, 4068 false, this, UserHandle.USER_ALL); 4069 contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri, 4070 false, this, UserHandle.USER_ALL); 4071 contentResolver.registerContentObserver(mAutoclickEnabledUri, 4072 false, this, UserHandle.USER_ALL); 4073 contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri, 4074 false, this, UserHandle.USER_ALL); 4075 contentResolver.registerContentObserver( 4076 mTouchExplorationGrantedAccessibilityServicesUri, 4077 false, this, UserHandle.USER_ALL); 4078 contentResolver.registerContentObserver( 4079 mHighTextContrastUri, false, this, UserHandle.USER_ALL); 4080 contentResolver.registerContentObserver( 4081 mAudioDescriptionByDefaultUri, false, this, UserHandle.USER_ALL); 4082 contentResolver.registerContentObserver( 4083 mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL); 4084 contentResolver.registerContentObserver( 4085 mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL); 4086 contentResolver.registerContentObserver( 4087 mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL); 4088 contentResolver.registerContentObserver( 4089 mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL); 4090 contentResolver.registerContentObserver( 4091 mAccessibilityButtonTargetsUri, false, this, UserHandle.USER_ALL); 4092 contentResolver.registerContentObserver( 4093 mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); 4094 contentResolver.registerContentObserver( 4095 mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); 4096 contentResolver.registerContentObserver( 4097 mMagnificationModeUri, false, this, UserHandle.USER_ALL); 4098 contentResolver.registerContentObserver( 4099 mMagnificationCapabilityUri, false, this, UserHandle.USER_ALL); 4100 contentResolver.registerContentObserver( 4101 mMagnificationFollowTypingUri, false, this, UserHandle.USER_ALL); 4102 } 4103 4104 @Override onChange(boolean selfChange, Uri uri)4105 public void onChange(boolean selfChange, Uri uri) { 4106 synchronized (mLock) { 4107 // Profiles share the accessibility state of the parent. Therefore, 4108 // we are checking for changes only the parent settings. 4109 AccessibilityUserState userState = getCurrentUserStateLocked(); 4110 4111 if (mTouchExplorationEnabledUri.equals(uri)) { 4112 if (readTouchExplorationEnabledSettingLocked(userState)) { 4113 onUserStateChangedLocked(userState); 4114 } 4115 } else if (mDisplayMagnificationEnabledUri.equals(uri)) { 4116 if (readMagnificationEnabledSettingsLocked(userState)) { 4117 onUserStateChangedLocked(userState); 4118 } 4119 } else if (mAutoclickEnabledUri.equals(uri)) { 4120 if (readAutoclickEnabledSettingLocked(userState)) { 4121 onUserStateChangedLocked(userState); 4122 } 4123 } else if (mEnabledAccessibilityServicesUri.equals(uri)) { 4124 if (readEnabledAccessibilityServicesLocked(userState)) { 4125 mSecurityPolicy.onEnabledServicesChangedLocked(userState.mUserId, 4126 userState.mEnabledServices); 4127 userState.updateCrashedServicesIfNeededLocked(); 4128 onUserStateChangedLocked(userState); 4129 } 4130 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { 4131 if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) { 4132 onUserStateChangedLocked(userState); 4133 } 4134 } else if (mHighTextContrastUri.equals(uri)) { 4135 if (readHighTextContrastEnabledSettingLocked(userState)) { 4136 onUserStateChangedLocked(userState); 4137 } 4138 } else if (mAudioDescriptionByDefaultUri.equals(uri)) { 4139 if (readAudioDescriptionEnabledSettingLocked(userState)) { 4140 onUserStateChangedLocked(userState); 4141 } 4142 } else if (mAccessibilitySoftKeyboardModeUri.equals(uri) 4143 || mShowImeWithHardKeyboardUri.equals(uri)) { 4144 userState.reconcileSoftKeyboardModeWithSettingsLocked(); 4145 } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) { 4146 if (readAccessibilityShortcutKeySettingLocked(userState)) { 4147 onUserStateChangedLocked(userState); 4148 } 4149 } else if (mAccessibilityButtonComponentIdUri.equals(uri)) { 4150 if (readAccessibilityButtonTargetComponentLocked(userState)) { 4151 onUserStateChangedLocked(userState); 4152 } 4153 } else if (mAccessibilityButtonTargetsUri.equals(uri)) { 4154 if (readAccessibilityButtonTargetsLocked(userState)) { 4155 onUserStateChangedLocked(userState); 4156 } 4157 } else if (mUserNonInteractiveUiTimeoutUri.equals(uri) 4158 || mUserInteractiveUiTimeoutUri.equals(uri)) { 4159 readUserRecommendedUiTimeoutSettingsLocked(userState); 4160 } else if (mMagnificationModeUri.equals(uri)) { 4161 if (readMagnificationModeForDefaultDisplayLocked(userState)) { 4162 updateMagnificationModeChangeSettingsLocked(userState, 4163 Display.DEFAULT_DISPLAY); 4164 } 4165 } else if (mMagnificationCapabilityUri.equals(uri)) { 4166 if (readMagnificationCapabilitiesLocked(userState)) { 4167 updateMagnificationCapabilitiesSettingsChangeLocked(userState); 4168 } 4169 } else if (mMagnificationFollowTypingUri.equals(uri)) { 4170 readMagnificationFollowTypingLocked(userState); 4171 } 4172 } 4173 } 4174 } 4175 updateMagnificationCapabilitiesSettingsChangeLocked( AccessibilityUserState userState)4176 private void updateMagnificationCapabilitiesSettingsChangeLocked( 4177 AccessibilityUserState userState) { 4178 final ArrayList<Display> displays = getValidDisplayList(); 4179 for (int i = 0; i < displays.size(); i++) { 4180 final int displayId = displays.get(i).getDisplayId(); 4181 if (fallBackMagnificationModeSettingsLocked(userState, displayId)) { 4182 updateMagnificationModeChangeSettingsLocked(userState, displayId); 4183 } 4184 } 4185 updateWindowMagnificationConnectionIfNeeded(userState); 4186 // Remove magnification button UI when the magnification capability is not all mode or 4187 // magnification is disabled. 4188 if (!(userState.isDisplayMagnificationEnabledLocked() 4189 || userState.isShortcutMagnificationEnabledLocked()) 4190 || userState.getMagnificationCapabilitiesLocked() 4191 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { 4192 4193 for (int i = 0; i < displays.size(); i++) { 4194 final int displayId = displays.get(i).getDisplayId(); 4195 getWindowMagnificationMgr().removeMagnificationButton(displayId); 4196 } 4197 } 4198 } 4199 fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState, int displayId)4200 private boolean fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState, 4201 int displayId) { 4202 if (userState.isValidMagnificationModeLocked(displayId)) { 4203 return false; 4204 } 4205 Slog.w(LOG_TAG, "displayId " + displayId + ", invalid magnification mode:" 4206 + userState.getMagnificationModeLocked(displayId)); 4207 final int capabilities = userState.getMagnificationCapabilitiesLocked(); 4208 userState.setMagnificationModeLocked(displayId, capabilities); 4209 if (displayId == Display.DEFAULT_DISPLAY) { 4210 persistMagnificationModeSettingsLocked(capabilities); 4211 } 4212 return true; 4213 } 4214 persistMagnificationModeSettingsLocked(int mode)4215 private void persistMagnificationModeSettingsLocked(int mode) { 4216 BackgroundThread.getHandler().post(() -> { 4217 final long identity = Binder.clearCallingIdentity(); 4218 try { 4219 Settings.Secure.putIntForUser(mContext.getContentResolver(), 4220 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, mode, mCurrentUserId); 4221 } finally { 4222 Binder.restoreCallingIdentity(identity); 4223 } 4224 }); 4225 } 4226 4227 /** 4228 * Gets the magnification mode of the specified display. 4229 * 4230 * @param displayId The logical displayId. 4231 * @return magnification mode. It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or 4232 * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW. 4233 */ getMagnificationMode(int displayId)4234 public int getMagnificationMode(int displayId) { 4235 synchronized (mLock) { 4236 return getCurrentUserStateLocked().getMagnificationModeLocked(displayId); 4237 } 4238 } 4239 4240 // Only the value of the default display is from user settings because not each of displays has 4241 // a unique id. readMagnificationModeForDefaultDisplayLocked(AccessibilityUserState userState)4242 private boolean readMagnificationModeForDefaultDisplayLocked(AccessibilityUserState userState) { 4243 final int magnificationMode = Settings.Secure.getIntForUser( 4244 mContext.getContentResolver(), 4245 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 4246 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); 4247 if (magnificationMode != userState.getMagnificationModeLocked(Display.DEFAULT_DISPLAY)) { 4248 userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY, magnificationMode); 4249 return true; 4250 } 4251 return false; 4252 } 4253 readMagnificationCapabilitiesLocked(AccessibilityUserState userState)4254 private boolean readMagnificationCapabilitiesLocked(AccessibilityUserState userState) { 4255 final int capabilities = Settings.Secure.getIntForUser( 4256 mContext.getContentResolver(), 4257 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY, 4258 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); 4259 if (capabilities != userState.getMagnificationCapabilitiesLocked()) { 4260 userState.setMagnificationCapabilitiesLocked(capabilities); 4261 mMagnificationController.setMagnificationCapabilities(capabilities); 4262 return true; 4263 } 4264 return false; 4265 } 4266 readMagnificationFollowTypingLocked(AccessibilityUserState userState)4267 boolean readMagnificationFollowTypingLocked(AccessibilityUserState userState) { 4268 final boolean followTypeEnabled = Settings.Secure.getIntForUser( 4269 mContext.getContentResolver(), 4270 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, 4271 1, userState.mUserId) == 1; 4272 if (followTypeEnabled != userState.isMagnificationFollowTypingEnabled()) { 4273 userState.setMagnificationFollowTypingEnabled(followTypeEnabled); 4274 mMagnificationController.setMagnificationFollowTypingEnabled(followTypeEnabled); 4275 return true; 4276 } 4277 return false; 4278 } 4279 4280 @Override setGestureDetectionPassthroughRegion(int displayId, Region region)4281 public void setGestureDetectionPassthroughRegion(int displayId, Region region) { 4282 mMainHandler.sendMessage( 4283 obtainMessage( 4284 AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal, 4285 this, 4286 displayId, 4287 region)); 4288 } 4289 4290 @Override setTouchExplorationPassthroughRegion(int displayId, Region region)4291 public void setTouchExplorationPassthroughRegion(int displayId, Region region) { 4292 mMainHandler.sendMessage( 4293 obtainMessage( 4294 AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal, 4295 this, 4296 displayId, 4297 region)); 4298 } 4299 setTouchExplorationPassthroughRegionInternal(int displayId, Region region)4300 private void setTouchExplorationPassthroughRegionInternal(int displayId, Region region) { 4301 synchronized (mLock) { 4302 if (mHasInputFilter && mInputFilter != null) { 4303 mInputFilter.setTouchExplorationPassthroughRegion(displayId, region); 4304 } 4305 } 4306 } 4307 setGestureDetectionPassthroughRegionInternal(int displayId, Region region)4308 private void setGestureDetectionPassthroughRegionInternal(int displayId, Region region) { 4309 synchronized (mLock) { 4310 if (mHasInputFilter && mInputFilter != null) { 4311 mInputFilter.setGestureDetectionPassthroughRegion(displayId, region); 4312 } 4313 } 4314 } 4315 4316 @Override setServiceDetectsGesturesEnabled(int displayId, boolean mode)4317 public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) { 4318 mMainHandler.sendMessage( 4319 obtainMessage(AccessibilityManagerService::setServiceDetectsGesturesInternal, this, 4320 displayId, mode)); 4321 } 4322 setServiceDetectsGesturesInternal(int displayId, boolean mode)4323 private void setServiceDetectsGesturesInternal(int displayId, boolean mode) { 4324 synchronized (mLock) { 4325 if (mHasInputFilter && mInputFilter != null) { 4326 mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode); 4327 } 4328 } 4329 } 4330 4331 @Override requestTouchExploration(int displayId)4332 public void requestTouchExploration(int displayId) { 4333 mMainHandler.sendMessage(obtainMessage( 4334 AccessibilityManagerService::requestTouchExplorationInternal, this, displayId)); 4335 } 4336 requestTouchExplorationInternal(int displayId)4337 private void requestTouchExplorationInternal(int displayId) { 4338 synchronized (mLock) { 4339 if (mHasInputFilter && mInputFilter != null) { 4340 mInputFilter.requestTouchExploration(displayId); 4341 } 4342 } 4343 } 4344 4345 @Override requestDragging(int displayId, int pointerId)4346 public void requestDragging(int displayId, int pointerId) { 4347 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::requestDraggingInternal, 4348 this, displayId, pointerId)); 4349 } 4350 requestDraggingInternal(int displayId, int pointerId)4351 private void requestDraggingInternal(int displayId, int pointerId) { 4352 synchronized (mLock) { 4353 if (mHasInputFilter && mInputFilter != null) { 4354 mInputFilter.requestDragging(displayId, pointerId); 4355 } 4356 } 4357 } 4358 4359 @Override requestDelegating(int displayId)4360 public void requestDelegating(int displayId) { 4361 mMainHandler.sendMessage( 4362 obtainMessage( 4363 AccessibilityManagerService::requestDelegatingInternal, this, displayId)); 4364 } 4365 requestDelegatingInternal(int displayId)4366 private void requestDelegatingInternal(int displayId) { 4367 synchronized (mLock) { 4368 if (mHasInputFilter && mInputFilter != null) { 4369 mInputFilter.requestDelegating(displayId); 4370 } 4371 } 4372 } 4373 4374 @Override onDoubleTap(int displayId)4375 public void onDoubleTap(int displayId) { 4376 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapInternal, 4377 this, displayId)); 4378 } 4379 onDoubleTapInternal(int displayId)4380 private void onDoubleTapInternal(int displayId) { 4381 AccessibilityInputFilter inputFilter = null; 4382 synchronized (mLock) { 4383 if (mHasInputFilter && mInputFilter != null) { 4384 inputFilter = mInputFilter; 4385 } 4386 } 4387 if (inputFilter != null) { 4388 inputFilter.onDoubleTap(displayId); 4389 } 4390 } 4391 4392 @Override onDoubleTapAndHold(int displayId)4393 public void onDoubleTapAndHold(int displayId) { 4394 mMainHandler 4395 .sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapAndHoldInternal, 4396 this, displayId)); 4397 } 4398 4399 @Override requestImeLocked(AbstractAccessibilityServiceConnection connection)4400 public void requestImeLocked(AbstractAccessibilityServiceConnection connection) { 4401 mMainHandler.sendMessage(obtainMessage( 4402 AccessibilityManagerService::createSessionForConnection, this, connection)); 4403 mMainHandler.sendMessage(obtainMessage( 4404 AccessibilityManagerService::bindAndStartInputForConnection, this, connection)); 4405 } 4406 4407 @Override unbindImeLocked(AbstractAccessibilityServiceConnection connection)4408 public void unbindImeLocked(AbstractAccessibilityServiceConnection connection) { 4409 mMainHandler.sendMessage(obtainMessage( 4410 AccessibilityManagerService::unbindInputForConnection, this, connection)); 4411 } 4412 createSessionForConnection(AbstractAccessibilityServiceConnection connection)4413 private void createSessionForConnection(AbstractAccessibilityServiceConnection connection) { 4414 synchronized (mLock) { 4415 if (mInputSessionRequested) { 4416 connection.createImeSessionLocked(); 4417 } 4418 } 4419 } 4420 bindAndStartInputForConnection(AbstractAccessibilityServiceConnection connection)4421 private void bindAndStartInputForConnection(AbstractAccessibilityServiceConnection connection) { 4422 synchronized (mLock) { 4423 if (mInputBound) { 4424 connection.bindInputLocked(); 4425 connection.startInputLocked(mRemoteInputConnection, mEditorInfo, mRestarting); 4426 } 4427 } 4428 } 4429 unbindInputForConnection(AbstractAccessibilityServiceConnection connection)4430 private void unbindInputForConnection(AbstractAccessibilityServiceConnection connection) { 4431 InputMethodManagerInternal.get().unbindAccessibilityFromCurrentClient(connection.mId); 4432 synchronized (mLock) { 4433 connection.unbindInputLocked(); 4434 } 4435 } 4436 onDoubleTapAndHoldInternal(int displayId)4437 private void onDoubleTapAndHoldInternal(int displayId) { 4438 synchronized (mLock) { 4439 if (mHasInputFilter && mInputFilter != null) { 4440 mInputFilter.onDoubleTapAndHold(displayId); 4441 } 4442 } 4443 } 4444 updateFocusAppearanceDataLocked(AccessibilityUserState userState)4445 private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) { 4446 if (userState.mUserId != mCurrentUserId) { 4447 return; 4448 } 4449 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 4450 mTraceManager.logTrace(LOG_TAG + ".updateFocusAppearanceDataLocked", 4451 FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState); 4452 } 4453 mMainHandler.post(() -> { 4454 broadcastToClients(userState, ignoreRemoteException(client -> { 4455 client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(), 4456 userState.getFocusColorLocked()); 4457 })); 4458 }); 4459 4460 } 4461 getTraceManager()4462 public AccessibilityTraceManager getTraceManager() { 4463 return mTraceManager; 4464 } 4465 4466 /** 4467 * Bind input for accessibility services which request ime capabilities. 4468 */ scheduleBindInput()4469 public void scheduleBindInput() { 4470 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this)); 4471 } 4472 bindInput()4473 private void bindInput() { 4474 synchronized (mLock) { 4475 // Keep records of these in case new Accessibility Services are enabled. 4476 mInputBound = true; 4477 AccessibilityUserState userState = getCurrentUserStateLocked(); 4478 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 4479 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 4480 if (service.requestImeApis()) { 4481 service.bindInputLocked(); 4482 } 4483 } 4484 } 4485 } 4486 4487 /** 4488 * Unbind input for accessibility services which request ime capabilities. 4489 */ scheduleUnbindInput()4490 public void scheduleUnbindInput() { 4491 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this)); 4492 } 4493 unbindInput()4494 private void unbindInput() { 4495 synchronized (mLock) { 4496 mInputBound = false; 4497 AccessibilityUserState userState = getCurrentUserStateLocked(); 4498 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 4499 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 4500 if (service.requestImeApis()) { 4501 service.unbindInputLocked(); 4502 } 4503 } 4504 } 4505 } 4506 4507 /** 4508 * Start input for accessibility services which request ime capabilities. 4509 */ scheduleStartInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, boolean restarting)4510 public void scheduleStartInput(IRemoteAccessibilityInputConnection connection, 4511 EditorInfo editorInfo, boolean restarting) { 4512 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this, 4513 connection, editorInfo, restarting)); 4514 } 4515 startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, boolean restarting)4516 private void startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, 4517 boolean restarting) { 4518 synchronized (mLock) { 4519 // Keep records of these in case new Accessibility Services are enabled. 4520 mRemoteInputConnection = connection; 4521 mEditorInfo = editorInfo; 4522 mRestarting = restarting; 4523 AccessibilityUserState userState = getCurrentUserStateLocked(); 4524 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 4525 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 4526 if (service.requestImeApis()) { 4527 service.startInputLocked(connection, editorInfo, restarting); 4528 } 4529 } 4530 } 4531 } 4532 4533 /** 4534 * Request input sessions from all accessibility services which request ime capabilities and 4535 * whose id is not in the ignoreSet 4536 */ scheduleCreateImeSession(ArraySet<Integer> ignoreSet)4537 public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) { 4538 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession, 4539 this, ignoreSet)); 4540 } 4541 createImeSession(ArraySet<Integer> ignoreSet)4542 private void createImeSession(ArraySet<Integer> ignoreSet) { 4543 synchronized (mLock) { 4544 mInputSessionRequested = true; 4545 AccessibilityUserState userState = getCurrentUserStateLocked(); 4546 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 4547 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 4548 if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) { 4549 service.createImeSessionLocked(); 4550 } 4551 } 4552 } 4553 } 4554 4555 /** 4556 * Enable or disable the sessions. 4557 * 4558 * @param sessions Sessions to enable or disable. 4559 * @param enabled True if enable the sessions or false if disable the sessions. 4560 */ scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)4561 public void scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, 4562 boolean enabled) { 4563 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled, 4564 this, sessions, enabled)); 4565 } 4566 setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)4567 private void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, 4568 boolean enabled) { 4569 synchronized (mLock) { 4570 AccessibilityUserState userState = getCurrentUserStateLocked(); 4571 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 4572 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 4573 if (sessions.contains(service.mId) && service.requestImeApis()) { 4574 service.setImeSessionEnabledLocked(sessions.get(service.mId), enabled); 4575 } 4576 } 4577 } 4578 } 4579 4580 private final class SendWindowStateChangedEventRunnable implements Runnable { 4581 4582 private final AccessibilityEvent mPendingEvent; 4583 private final int mWindowId; 4584 SendWindowStateChangedEventRunnable(@onNull AccessibilityEvent event)4585 SendWindowStateChangedEventRunnable(@NonNull AccessibilityEvent event) { 4586 mPendingEvent = event; 4587 mWindowId = event.getWindowId(); 4588 } 4589 4590 @Override run()4591 public void run() { 4592 synchronized (mLock) { 4593 Slog.w(LOG_TAG, " wait for adding window timeout: " + mWindowId); 4594 sendPendingEventLocked(); 4595 } 4596 } 4597 sendPendingEventLocked()4598 private void sendPendingEventLocked() { 4599 mSendWindowStateChangedEventRunnables.remove(this); 4600 dispatchAccessibilityEventLocked(mPendingEvent); 4601 } 4602 getWindowId()4603 private int getWindowId() { 4604 return mWindowId; 4605 } 4606 } 4607 sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId)4608 void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) { 4609 final int eventSize = mSendWindowStateChangedEventRunnables.size(); 4610 for (int i = eventSize - 1; i >= 0; i--) { 4611 final SendWindowStateChangedEventRunnable runnable = 4612 mSendWindowStateChangedEventRunnables.get(i); 4613 if (runnable.getWindowId() == windowId) { 4614 mMainHandler.removeCallbacks(runnable); 4615 runnable.sendPendingEventLocked(); 4616 } 4617 } 4618 } 4619 4620 /** 4621 * Postpones the {@link AccessibilityEvent} with 4622 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED} 4623 * which doesn't have the corresponding window until the window is added or timeout. 4624 * 4625 * @return {@code true} if the event is postponed. 4626 */ postponeWindowStateEvent(AccessibilityEvent event)4627 private boolean postponeWindowStateEvent(AccessibilityEvent event) { 4628 synchronized (mLock) { 4629 final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked( 4630 event.getWindowId()); 4631 if (mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId) != null) { 4632 return false; 4633 } 4634 final SendWindowStateChangedEventRunnable pendingRunnable = 4635 new SendWindowStateChangedEventRunnable(new AccessibilityEvent(event)); 4636 mMainHandler.postDelayed(pendingRunnable, 4637 POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS); 4638 mSendWindowStateChangedEventRunnables.add(pendingRunnable); 4639 return true; 4640 } 4641 } 4642 } 4643