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