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