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