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.Manifest.permission.CREATE_VIRTUAL_DEVICE; 20 import static android.Manifest.permission.INJECT_EVENTS; 21 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; 22 import static android.Manifest.permission.MANAGE_ACCESSIBILITY; 23 import static android.Manifest.permission.MANAGE_BIND_INSTANT_SERVICE; 24 import static android.Manifest.permission.MODIFY_ACCESSIBILITY_DATA; 25 import static android.Manifest.permission.RETRIEVE_WINDOW_CONTENT; 26 import static android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION; 27 import static android.Manifest.permission.STATUS_BAR_SERVICE; 28 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON; 29 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER; 30 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_MANAGER_CLIENT; 31 import static android.accessibilityservice.AccessibilityTrace.FLAGS_ACCESSIBILITY_SERVICE_CLIENT; 32 import static android.accessibilityservice.AccessibilityTrace.FLAGS_FINGERPRINT; 33 import static android.accessibilityservice.AccessibilityTrace.FLAGS_INPUT_FILTER; 34 import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION; 35 import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROADCAST_RECEIVER; 36 import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; 37 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; 38 import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED; 39 import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID; 40 import static android.content.Context.DEVICE_ID_DEFAULT; 41 import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED; 42 import static android.view.accessibility.AccessibilityManager.FlashNotificationReason; 43 44 import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; 45 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME; 46 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; 47 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; 48 import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES; 49 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; 50 import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityShortcutActivated; 51 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; 52 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 53 import static com.android.server.accessibility.AccessibilityUserState.doesShortcutTargetsStringContain; 54 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 55 56 import android.accessibilityservice.AccessibilityGestureEvent; 57 import android.accessibilityservice.AccessibilityService; 58 import android.accessibilityservice.AccessibilityServiceInfo; 59 import android.accessibilityservice.AccessibilityShortcutInfo; 60 import android.accessibilityservice.IAccessibilityServiceClient; 61 import android.accessibilityservice.MagnificationConfig; 62 import android.accessibilityservice.TouchInteractionController; 63 import android.annotation.EnforcePermission; 64 import android.annotation.NonNull; 65 import android.annotation.Nullable; 66 import android.annotation.PermissionManuallyEnforced; 67 import android.annotation.RequiresNoPermission; 68 import android.annotation.SuppressLint; 69 import android.annotation.UserIdInt; 70 import android.app.ActivityOptions; 71 import android.app.AlertDialog; 72 import android.app.AppOpsManager; 73 import android.app.PendingIntent; 74 import android.app.RemoteAction; 75 import android.app.admin.DevicePolicyManager; 76 import android.app.ecm.EnhancedConfirmationManager; 77 import android.appwidget.AppWidgetManagerInternal; 78 import android.content.ActivityNotFoundException; 79 import android.content.BroadcastReceiver; 80 import android.content.ComponentName; 81 import android.content.ContentResolver; 82 import android.content.Context; 83 import android.content.DialogInterface; 84 import android.content.DialogInterface.OnClickListener; 85 import android.content.Intent; 86 import android.content.IntentFilter; 87 import android.content.pm.PackageManager; 88 import android.content.pm.PackageManagerInternal; 89 import android.content.pm.ParceledListSlice; 90 import android.content.pm.ResolveInfo; 91 import android.content.pm.ServiceInfo; 92 import android.database.ContentObserver; 93 import android.graphics.Matrix; 94 import android.graphics.Point; 95 import android.graphics.Rect; 96 import android.graphics.Region; 97 import android.hardware.display.DisplayManager; 98 import android.hardware.fingerprint.IFingerprintService; 99 import android.media.AudioManagerInternal; 100 import android.net.Uri; 101 import android.os.Binder; 102 import android.os.Build; 103 import android.os.Bundle; 104 import android.os.Handler; 105 import android.os.IBinder; 106 import android.os.Looper; 107 import android.os.Message; 108 import android.os.PermissionEnforcer; 109 import android.os.PowerManager; 110 import android.os.Process; 111 import android.os.RemoteCallbackList; 112 import android.os.RemoteException; 113 import android.os.ResultReceiver; 114 import android.os.ServiceManager; 115 import android.os.ShellCallback; 116 import android.os.SystemClock; 117 import android.os.UserHandle; 118 import android.os.UserManager; 119 import android.provider.Settings; 120 import android.provider.SettingsStringUtil.SettingStringHelper; 121 import android.safetycenter.SafetyCenterManager; 122 import android.text.TextUtils; 123 import android.text.TextUtils.SimpleStringSplitter; 124 import android.util.ArrayMap; 125 import android.util.ArraySet; 126 import android.util.IntArray; 127 import android.util.Log; 128 import android.util.Pair; 129 import android.util.Slog; 130 import android.util.SparseArray; 131 import android.util.SparseBooleanArray; 132 import android.view.Display; 133 import android.view.IWindow; 134 import android.view.InputDevice; 135 import android.view.InputEvent; 136 import android.view.KeyEvent; 137 import android.view.MagnificationSpec; 138 import android.view.MotionEvent; 139 import android.view.SurfaceControl; 140 import android.view.WindowInfo; 141 import android.view.WindowManager; 142 import android.view.accessibility.AccessibilityEvent; 143 import android.view.accessibility.AccessibilityInteractionClient; 144 import android.view.accessibility.AccessibilityManager; 145 import android.view.accessibility.AccessibilityNodeInfo; 146 import android.view.accessibility.AccessibilityWindowAttributes; 147 import android.view.accessibility.AccessibilityWindowInfo; 148 import android.view.accessibility.IAccessibilityInteractionConnection; 149 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 150 import android.view.accessibility.IAccessibilityManager; 151 import android.view.accessibility.IAccessibilityManagerClient; 152 import android.view.accessibility.IMagnificationConnection; 153 import android.view.inputmethod.EditorInfo; 154 155 import com.android.internal.R; 156 import com.android.internal.accessibility.AccessibilityShortcutController; 157 import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkFeatureInfo; 158 import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo; 159 import com.android.internal.accessibility.common.ShortcutConstants; 160 import com.android.internal.accessibility.common.ShortcutConstants.FloatingMenuSize; 161 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; 162 import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity; 163 import com.android.internal.accessibility.util.AccessibilityUtils; 164 import com.android.internal.accessibility.util.ShortcutUtils; 165 import com.android.internal.annotations.GuardedBy; 166 import com.android.internal.annotations.VisibleForTesting; 167 import com.android.internal.content.PackageMonitor; 168 import com.android.internal.inputmethod.IAccessibilityInputMethodSession; 169 import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; 170 import com.android.internal.os.BackgroundThread; 171 import com.android.internal.util.ArrayUtils; 172 import com.android.internal.util.DumpUtils; 173 import com.android.internal.util.IntPair; 174 import com.android.internal.util.Preconditions; 175 import com.android.modules.expresslog.Counter; 176 import com.android.server.AccessibilityManagerInternal; 177 import com.android.server.LocalServices; 178 import com.android.server.SystemService; 179 import com.android.server.accessibility.magnification.MagnificationConnectionManager; 180 import com.android.server.accessibility.magnification.MagnificationController; 181 import com.android.server.accessibility.magnification.MagnificationProcessor; 182 import com.android.server.accessibility.magnification.MagnificationScaleProvider; 183 import com.android.server.inputmethod.InputMethodManagerInternal; 184 import com.android.server.pm.UserManagerInternal; 185 import com.android.server.policy.WindowManagerPolicy; 186 import com.android.server.statusbar.StatusBarManagerInternal; 187 import com.android.server.utils.Slogf; 188 import com.android.server.wm.ActivityTaskManagerInternal; 189 import com.android.server.wm.WindowManagerInternal; 190 import com.android.settingslib.RestrictedLockUtils; 191 192 import org.xmlpull.v1.XmlPullParserException; 193 194 import java.io.FileDescriptor; 195 import java.io.IOException; 196 import java.io.PrintWriter; 197 import java.util.ArrayList; 198 import java.util.Arrays; 199 import java.util.Collections; 200 import java.util.HashSet; 201 import java.util.Iterator; 202 import java.util.List; 203 import java.util.Map; 204 import java.util.Objects; 205 import java.util.Set; 206 import java.util.concurrent.Executors; 207 import java.util.function.Consumer; 208 import java.util.function.Function; 209 import java.util.function.Predicate; 210 import java.util.stream.Collectors; 211 212 /** 213 * This class is instantiated by the system as a system level service and can be 214 * accessed only by the system. The task of this service is to be a centralized 215 * event dispatch for {@link AccessibilityEvent}s generated across all processes 216 * on the device. Events are dispatched to {@link AccessibilityService}s. 217 */ 218 public class AccessibilityManagerService extends IAccessibilityManager.Stub 219 implements AbstractAccessibilityServiceConnection.SystemSupport, 220 AccessibilityUserState.ServiceInfoChangeListener, 221 AccessibilityWindowManager.AccessibilityEventSender, 222 AccessibilitySecurityPolicy.AccessibilityUserManager, 223 SystemActionPerformer.SystemActionsChangedListener, 224 SystemActionPerformer.DisplayUpdateCallBack, ProxyManager.SystemSupport { 225 226 private static final boolean DEBUG = false; 227 228 private static final String LOG_TAG = "AccessibilityManagerService"; 229 230 // TODO: This is arbitrary. When there is time implement this by watching 231 // when that accessibility services are bound. 232 private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000; 233 234 // TODO: Restructure service initialization so services aren't connected before all of 235 // their capabilities are ready. 236 private static final int WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS = 1000; 237 238 239 // This postpones state changes events when a window doesn't exist with the expectation that 240 // a race condition will resolve. It is determined by observing elapsed time of the 241 // corresponding window added. 242 //TODO(b/230810909) : Fix it with a better idea. 243 private static final int POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS = 500; 244 245 private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE = 246 "registerUiTestAutomationService"; 247 248 private static final String GET_WINDOW_TOKEN = "getWindowToken"; 249 250 private static final String SET_PIP_ACTION_REPLACEMENT = 251 "setPictureInPictureActionReplacingConnection"; 252 253 /** 254 * An intent action to launch Hearing devices dialog. 255 */ 256 @VisibleForTesting 257 static final String ACTION_LAUNCH_HEARING_DEVICES_DIALOG = 258 "com.android.systemui.action.LAUNCH_HEARING_DEVICES_DIALOG"; 259 260 private static final char COMPONENT_NAME_SEPARATOR = ':'; 261 262 private static final int OWN_PROCESS_ID = android.os.Process.myPid(); 263 264 public static final int INVALID_SERVICE_ID = -1; 265 266 // Each service has an ID. Also provide one for magnification gesture handling 267 public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0; 268 269 private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1; 270 /** 271 * The counter metric id tracking how many times users add qs shortcut for a11y features. 272 * 273 * <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg. 274 */ 275 static final String METRIC_ID_QS_SHORTCUT_ADD = "accessibility.value_qs_shortcut_add"; 276 277 /** 278 * The counter metric id tracking how many times users remove qs shortcut for a11y features. 279 * 280 * <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg. 281 */ 282 static final String METRIC_ID_QS_SHORTCUT_REMOVE = "accessibility.value_qs_shortcut_remove"; 283 284 285 private final Context mContext; 286 287 private final Object mLock = new Object(); 288 289 private final SimpleStringSplitter mStringColonSplitter = 290 new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); 291 292 private final Rect mTempRect = new Rect(); 293 private final Rect mTempRect1 = new Rect(); 294 295 private final PackageManager mPackageManager; 296 297 private final PowerManager mPowerManager; 298 299 private final WindowManagerInternal mWindowManagerService; 300 301 private final AccessibilitySecurityPolicy mSecurityPolicy; 302 303 private final AccessibilityWindowManager mA11yWindowManager; 304 305 private final AccessibilityDisplayListener mA11yDisplayListener; 306 307 private final ActivityTaskManagerInternal mActivityTaskManagerService; 308 309 private final MagnificationController mMagnificationController; 310 private final MagnificationProcessor mMagnificationProcessor; 311 312 private final Handler mMainHandler; 313 314 // Lazily initialized - access through getSystemActionPerformer() 315 private SystemActionPerformer mSystemActionPerformer; 316 317 private InteractionBridge mInteractionBridge; 318 319 private AlertDialog mEnableTouchExplorationDialog; 320 321 private AccessibilityInputFilter mInputFilter; 322 323 private boolean mHasInputFilter; 324 325 private boolean mInputFilterInstalled; 326 327 private KeyEventDispatcher mKeyEventDispatcher; 328 329 private SparseArray<MotionEventInjector> mMotionEventInjectors; 330 331 private FingerprintGestureDispatcher mFingerprintGestureDispatcher; 332 333 private final Set<ComponentName> mTempComponentNameSet = new HashSet<>(); 334 335 private final IntArray mTempIntArray = new IntArray(0); 336 337 private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients = 338 new RemoteCallbackList<>(); 339 340 private PackageMonitor mPackageMonitor; 341 342 @VisibleForTesting 343 final SparseArray<AccessibilityUserState> mUserStates = new SparseArray<>(); 344 345 private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock); 346 private final ProxyManager mProxyManager; 347 private final AccessibilityTraceManager mTraceManager; 348 private final CaptioningManagerImpl mCaptioningManagerImpl; 349 350 private final List<SendWindowStateChangedEventRunnable> mSendWindowStateChangedEventRunnables = 351 new ArrayList<>(); 352 353 @GuardedBy("mLock") 354 private @UserIdInt int mCurrentUserId = UserHandle.USER_SYSTEM; 355 356 // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation: 357 // when the UiAutomation is set in a visible background user, mCurrentUserId points to that user 358 // and mRealCurrentUserId points to the "real" current user; otherwise, mRealCurrentUserId 359 // is set as UserHandle.USER_CURRENT. 360 @GuardedBy("mLock") 361 private @UserIdInt int mRealCurrentUserId = UserHandle.USER_CURRENT; 362 363 // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation 364 // purposes - in the long term, the whole service should be refactored so it handles "visible" 365 // users, not current user. Notice that because this is temporary, it's not trying to optimize 366 // performance / utilization (for example, it's not using an IntArray) 367 @GuardedBy("mLock") 368 @Nullable // only set when device supports visible background users 369 private final SparseBooleanArray mVisibleBgUserIds; 370 371 //TODO: Remove this hack 372 private boolean mInitialized; 373 374 private Point mTempPoint = new Point(); 375 private boolean mIsAccessibilityButtonShown; 376 private boolean mInputBound; 377 IRemoteAccessibilityInputConnection mRemoteInputConnection; 378 EditorInfo mEditorInfo; 379 boolean mRestarting; 380 boolean mInputSessionRequested; 381 private SparseArray<SurfaceControl> mA11yOverlayLayers = new SparseArray<>(); 382 383 private final FlashNotificationsController mFlashNotificationsController; 384 private final UserManagerInternal mUmi; 385 getCurrentUserStateLocked()386 private AccessibilityUserState getCurrentUserStateLocked() { 387 return getUserStateLocked(mCurrentUserId); 388 } 389 390 /** 391 * Changes the magnification mode on the given display. 392 * 393 * @param displayId the logical display 394 * @param magnificationMode the target magnification mode 395 */ changeMagnificationMode(int displayId, int magnificationMode)396 public void changeMagnificationMode(int displayId, int magnificationMode) { 397 synchronized (mLock) { 398 if (displayId == Display.DEFAULT_DISPLAY) { 399 persistMagnificationModeSettingsLocked(magnificationMode); 400 } else { 401 final AccessibilityUserState userState = getCurrentUserStateLocked(); 402 final int currentMode = userState.getMagnificationModeLocked(displayId); 403 if (magnificationMode != currentMode) { 404 userState.setMagnificationModeLocked(displayId, magnificationMode); 405 updateMagnificationModeChangeSettingsLocked(userState, displayId); 406 } 407 } 408 } 409 } 410 411 private static final class LocalServiceImpl extends AccessibilityManagerInternal { 412 @NonNull 413 private final AccessibilityManagerService mService; 414 LocalServiceImpl(@onNull AccessibilityManagerService service)415 LocalServiceImpl(@NonNull AccessibilityManagerService service) { 416 mService = service; 417 } 418 419 @Override setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)420 public void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, 421 boolean enabled) { 422 mService.scheduleSetImeSessionEnabled(sessions, enabled); 423 } 424 425 @Override unbindInput()426 public void unbindInput() { 427 mService.scheduleUnbindInput(); 428 } 429 430 @Override bindInput()431 public void bindInput() { 432 mService.scheduleBindInput(); 433 } 434 435 @Override createImeSession(ArraySet<Integer> ignoreSet)436 public void createImeSession(ArraySet<Integer> ignoreSet) { 437 mService.scheduleCreateImeSession(ignoreSet); 438 } 439 440 @Override startInput( IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, EditorInfo editorInfo, boolean restarting)441 public void startInput( 442 IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, 443 EditorInfo editorInfo, boolean restarting) { 444 mService.scheduleStartInput(remoteAccessibilityInputConnection, editorInfo, restarting); 445 } 446 447 @Override performSystemAction(int actionId)448 public void performSystemAction(int actionId) { 449 mService.getSystemActionPerformer().performSystemAction(actionId); 450 } 451 452 @Override isTouchExplorationEnabled(@serIdInt int userId)453 public boolean isTouchExplorationEnabled(@UserIdInt int userId) { 454 synchronized (mService.mLock) { 455 return mService.getUserStateLocked(userId).isTouchExplorationEnabledLocked(); 456 } 457 } 458 } 459 460 public static final class Lifecycle extends SystemService { 461 private final AccessibilityManagerService mService; 462 Lifecycle(Context context)463 public Lifecycle(Context context) { 464 super(context); 465 mService = new AccessibilityManagerService(context); 466 } 467 468 @Override onStart()469 public void onStart() { 470 LocalServices.addService(AccessibilityManagerInternal.class, 471 new LocalServiceImpl(mService)); 472 publishBinderService(Context.ACCESSIBILITY_SERVICE, mService); 473 } 474 475 @Override onBootPhase(int phase)476 public void onBootPhase(int phase) { 477 mService.onBootPhase(phase); 478 } 479 } 480 481 @VisibleForTesting AccessibilityManagerService( Context context, Handler handler, PackageManager packageManager, AccessibilitySecurityPolicy securityPolicy, SystemActionPerformer systemActionPerformer, AccessibilityWindowManager a11yWindowManager, AccessibilityDisplayListener a11yDisplayListener, MagnificationController magnificationController, @Nullable AccessibilityInputFilter inputFilter, ProxyManager proxyManager, PermissionEnforcer permissionEnforcer)482 AccessibilityManagerService( 483 Context context, 484 Handler handler, 485 PackageManager packageManager, 486 AccessibilitySecurityPolicy securityPolicy, 487 SystemActionPerformer systemActionPerformer, 488 AccessibilityWindowManager a11yWindowManager, 489 AccessibilityDisplayListener a11yDisplayListener, 490 MagnificationController magnificationController, 491 @Nullable AccessibilityInputFilter inputFilter, 492 ProxyManager proxyManager, 493 PermissionEnforcer permissionEnforcer) { 494 super(permissionEnforcer); 495 mContext = context; 496 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 497 mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); 498 mTraceManager = AccessibilityTraceManager.getInstance( 499 mWindowManagerService.getAccessibilityController(), this, mLock); 500 mMainHandler = handler; 501 mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class); 502 mPackageManager = packageManager; 503 mSecurityPolicy = securityPolicy; 504 mSystemActionPerformer = systemActionPerformer; 505 mA11yWindowManager = a11yWindowManager; 506 mA11yDisplayListener = a11yDisplayListener; 507 mMagnificationController = magnificationController; 508 mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); 509 mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); 510 mProxyManager = proxyManager; 511 if (inputFilter != null) { 512 mInputFilter = inputFilter; 513 mHasInputFilter = true; 514 } 515 mFlashNotificationsController = new FlashNotificationsController(mContext); 516 mUmi = LocalServices.getService(UserManagerInternal.class); 517 // TODO(b/255426725): not used on tests 518 mVisibleBgUserIds = null; 519 520 init(); 521 } 522 523 /** 524 * Creates a new instance. 525 * 526 * @param context A {@link Context} instance. 527 */ AccessibilityManagerService(Context context)528 public AccessibilityManagerService(Context context) { 529 super(PermissionEnforcer.fromContext(context)); 530 mContext = context; 531 mPowerManager = context.getSystemService(PowerManager.class); 532 mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); 533 mTraceManager = AccessibilityTraceManager.getInstance( 534 mWindowManagerService.getAccessibilityController(), this, mLock); 535 mMainHandler = new MainHandler(mContext.getMainLooper()); 536 mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class); 537 mPackageManager = mContext.getPackageManager(); 538 final PolicyWarningUIController policyWarningUIController = new PolicyWarningUIController( 539 mMainHandler, context, 540 new PolicyWarningUIController.NotificationController(context)); 541 mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext, 542 this, LocalServices.getService(PackageManagerInternal.class)); 543 mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler, 544 mWindowManagerService, this, mSecurityPolicy, this, mTraceManager); 545 mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler); 546 mMagnificationController = new MagnificationController( 547 this, 548 mLock, 549 mContext, 550 new MagnificationScaleProvider(mContext), 551 Executors.newSingleThreadExecutor() 552 ); 553 mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); 554 mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); 555 mProxyManager = new ProxyManager(mLock, mA11yWindowManager, mContext, mMainHandler, 556 mUiAutomationManager, this); 557 mFlashNotificationsController = new FlashNotificationsController(mContext); 558 mUmi = LocalServices.getService(UserManagerInternal.class); 559 560 if (UserManager.isVisibleBackgroundUsersEnabled()) { 561 mVisibleBgUserIds = new SparseBooleanArray(); 562 mUmi.addUserVisibilityListener((u, v) -> onUserVisibilityChanged(u, v)); 563 } else { 564 mVisibleBgUserIds = null; 565 } 566 567 init(); 568 } 569 init()570 private void init() { 571 mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager); 572 registerBroadcastReceivers(); 573 new AccessibilityContentObserver(mMainHandler).register( 574 mContext.getContentResolver()); 575 disableAccessibilityMenuToMigrateIfNeeded(); 576 } 577 578 /** 579 * Returns if the current thread is holding {@link #mLock}. Used for testing 580 * deadlock bug fixes. 581 * 582 * <p><strong>Warning:</strong> this should not be used for production logic 583 * because by the time you receive an answer it may no longer be valid. 584 * </p> 585 */ 586 @VisibleForTesting unsafeIsLockHeld()587 boolean unsafeIsLockHeld() { 588 return Thread.holdsLock(mLock); 589 } 590 591 /** 592 * Returns if the service is initialized. 593 * 594 * The service is considered initialized when the user switch happened. 595 */ isServiceInitializedLocked()596 private boolean isServiceInitializedLocked() { 597 return mInitialized; 598 } 599 600 @Override getCurrentUserIdLocked()601 public int getCurrentUserIdLocked() { 602 return mCurrentUserId; 603 } 604 605 @GuardedBy("mLock") 606 @Override getVisibleUserIdsLocked()607 public SparseBooleanArray getVisibleUserIdsLocked() { 608 return mVisibleBgUserIds; 609 } 610 611 @Override isAccessibilityButtonShown()612 public boolean isAccessibilityButtonShown() { 613 return mIsAccessibilityButtonShown; 614 } 615 616 @Override getWindowTransformationMatrixAndMagnificationSpec( int windowId)617 public Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec( 618 int windowId) { 619 WindowInfo windowInfo; 620 synchronized (mLock) { 621 windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(windowId); 622 } 623 if (windowInfo != null) { 624 final MagnificationSpec spec = new MagnificationSpec(); 625 spec.setTo(windowInfo.mMagnificationSpec); 626 return new Pair<>(windowInfo.mTransformMatrix, spec); 627 } else { 628 // If the framework doesn't track windows, we fall back to get the pair of 629 // transformation matrix and MagnificationSpe from the WindowManagerService's 630 // WindowState. 631 IBinder token; 632 synchronized (mLock) { 633 token = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(mCurrentUserId, 634 windowId); 635 } 636 Pair<Matrix, MagnificationSpec> pair = 637 mWindowManagerService.getWindowTransformationMatrixAndMagnificationSpec(token); 638 final float[] outTransformationMatrix = new float[9]; 639 final Matrix tmpMatrix = pair.first; 640 final MagnificationSpec spec = pair.second; 641 if (!spec.isNop()) { 642 tmpMatrix.postScale(spec.scale, spec.scale); 643 tmpMatrix.postTranslate(spec.offsetX, spec.offsetY); 644 } 645 tmpMatrix.getValues(outTransformationMatrix); 646 647 return new Pair<>(outTransformationMatrix, pair.second); 648 } 649 } 650 651 @Override 652 @RequiresNoPermission getWindowTransformationSpec( int windowId)653 public IAccessibilityManager.WindowTransformationSpec getWindowTransformationSpec( 654 int windowId) { 655 IAccessibilityManager.WindowTransformationSpec windowTransformationSpec = 656 new IAccessibilityManager.WindowTransformationSpec(); 657 Pair<float[], MagnificationSpec> result = 658 getWindowTransformationMatrixAndMagnificationSpec(windowId); 659 windowTransformationSpec.transformationMatrix = result.first; 660 windowTransformationSpec.magnificationSpec = result.second; 661 return windowTransformationSpec; 662 } 663 664 @Override onServiceInfoChangedLocked(AccessibilityUserState userState)665 public void onServiceInfoChangedLocked(AccessibilityUserState userState) { 666 mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId, 667 userState.mBoundServices); 668 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 669 } 670 671 @Nullable getFingerprintGestureDispatcher()672 public FingerprintGestureDispatcher getFingerprintGestureDispatcher() { 673 return mFingerprintGestureDispatcher; 674 } 675 676 /** 677 * Called by the {@link AccessibilityInputFilter} when the filter install state changes. 678 */ onInputFilterInstalled(boolean installed)679 public void onInputFilterInstalled(boolean installed) { 680 synchronized (mLock) { 681 mInputFilterInstalled = installed; 682 mLock.notifyAll(); 683 } 684 } 685 onBootPhase(int phase)686 private void onBootPhase(int phase) { 687 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 688 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) { 689 mSecurityPolicy.setAppWidgetManager( 690 LocalServices.getService(AppWidgetManagerInternal.class)); 691 } 692 } 693 694 // SafetyCenterService is ready after this phase. 695 if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 696 setNonA11yToolNotificationToMatchSafetyCenter(); 697 } 698 } 699 setNonA11yToolNotificationToMatchSafetyCenter()700 private void setNonA11yToolNotificationToMatchSafetyCenter() { 701 final boolean sendNotification = !mContext.getSystemService( 702 SafetyCenterManager.class).isSafetyCenterEnabled(); 703 synchronized (mLock) { 704 mSecurityPolicy.setSendingNonA11yToolNotificationLocked(sendNotification); 705 } 706 } 707 708 /** 709 * Returns the lock object for any synchronized test blocks. 710 * External classes should only use for testing. 711 * @return lock object. 712 */ 713 @VisibleForTesting getLock()714 Object getLock() { 715 return mLock; 716 } 717 getCurrentUserState()718 AccessibilityUserState getCurrentUserState() { 719 synchronized (mLock) { 720 return getCurrentUserStateLocked(); 721 } 722 } 723 getUserState(int userId)724 private AccessibilityUserState getUserState(int userId) { 725 synchronized (mLock) { 726 return getUserStateLocked(userId); 727 } 728 } 729 730 @NonNull getUserStateLocked(int userId)731 private AccessibilityUserState getUserStateLocked(int userId) { 732 AccessibilityUserState state = mUserStates.get(userId); 733 if (state == null) { 734 state = new AccessibilityUserState(userId, mContext, this); 735 mUserStates.put(userId, state); 736 } 737 return state; 738 } 739 getBindInstantServiceAllowed(int userId)740 boolean getBindInstantServiceAllowed(int userId) { 741 synchronized (mLock) { 742 final AccessibilityUserState userState = getUserStateLocked(userId); 743 return userState.getBindInstantServiceAllowedLocked(); 744 } 745 } 746 setBindInstantServiceAllowed(int userId, boolean allowed)747 void setBindInstantServiceAllowed(int userId, boolean allowed) { 748 mContext.enforceCallingOrSelfPermission( 749 MANAGE_BIND_INSTANT_SERVICE, "setBindInstantServiceAllowed"); 750 synchronized (mLock) { 751 final AccessibilityUserState userState = getUserStateLocked(userId); 752 if (allowed != userState.getBindInstantServiceAllowedLocked()) { 753 userState.setBindInstantServiceAllowedLocked(allowed); 754 onUserStateChangedLocked(userState); 755 } 756 } 757 } 758 onSomePackagesChangedLocked( @ullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos, @Nullable List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos)759 private void onSomePackagesChangedLocked( 760 @Nullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos, 761 @Nullable List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) { 762 final AccessibilityUserState userState = getCurrentUserStateLocked(); 763 // Reload the installed services since some services may have different attributes 764 // or resolve info (does not support equals), etc. Remove them then to force reload. 765 userState.mInstalledServices.clear(); 766 if (readConfigurationForUserStateLocked(userState, 767 parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos)) { 768 onUserStateChangedLocked(userState); 769 } 770 } 771 onPackageRemovedLocked(String packageName)772 private void onPackageRemovedLocked(String packageName) { 773 final AccessibilityUserState userState = getCurrentUserState(); 774 final Predicate<ComponentName> filter = 775 component -> component != null && component.getPackageName().equals( 776 packageName); 777 userState.mBindingServices.removeIf(filter); 778 userState.mCrashedServices.removeIf(filter); 779 final Iterator<ComponentName> it = userState.mEnabledServices.iterator(); 780 boolean anyServiceRemoved = false; 781 while (it.hasNext()) { 782 final ComponentName comp = it.next(); 783 final String compPkg = comp.getPackageName(); 784 if (compPkg.equals(packageName)) { 785 it.remove(); 786 userState.mTouchExplorationGrantedServices.remove(comp); 787 anyServiceRemoved = true; 788 } 789 } 790 if (anyServiceRemoved) { 791 // Update the enabled services setting. 792 persistComponentNamesToSettingLocked( 793 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 794 userState.mEnabledServices, mCurrentUserId); 795 // Update the touch exploration granted services setting. 796 persistComponentNamesToSettingLocked( 797 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 798 userState.mTouchExplorationGrantedServices, mCurrentUserId); 799 onUserStateChangedLocked(userState); 800 } 801 } 802 803 /** 804 * Handles a package or packages being force stopped. 805 * Will disable any relevant services, 806 * and remove any button targets of continuous services, 807 * denoted by {@link AccessibilityServiceInfo#FLAG_REQUEST_ACCESSIBILITY_BUTTON}. 808 * If the result is {@code true}, 809 * then {@link AccessibilityManagerService#onUserStateChangedLocked( 810 * AccessibilityUserState, boolean)} should be called afterwards. 811 * 812 * @param packages list of packages that have stopped. 813 * @param userState user state to be read & modified. 814 * @return {@code true} if the lists of enabled services or buttons were changed, 815 * {@code false} otherwise. 816 */ 817 @VisibleForTesting onPackagesForceStoppedLocked( String[] packages, AccessibilityUserState userState)818 boolean onPackagesForceStoppedLocked( 819 String[] packages, AccessibilityUserState userState) { 820 final List<String> continuousServicePackages = 821 userState.mInstalledServices.stream().filter(service -> 822 (service.flags & FLAG_REQUEST_ACCESSIBILITY_BUTTON) 823 == FLAG_REQUEST_ACCESSIBILITY_BUTTON 824 ).map(service -> service.getComponentName().flattenToString()).toList(); 825 826 boolean enabledServicesChanged = false; 827 final Iterator<ComponentName> it = userState.mEnabledServices.iterator(); 828 while (it.hasNext()) { 829 final ComponentName comp = it.next(); 830 final String compPkg = comp.getPackageName(); 831 for (String pkg : packages) { 832 if (compPkg.equals(pkg)) { 833 it.remove(); 834 userState.getBindingServicesLocked().remove(comp); 835 userState.getCrashedServicesLocked().remove(comp); 836 enabledServicesChanged = true; 837 break; 838 } 839 } 840 } 841 if (enabledServicesChanged) { 842 persistComponentNamesToSettingLocked( 843 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 844 userState.mEnabledServices, userState.mUserId); 845 } 846 847 boolean buttonTargetsChanged = userState.mAccessibilityButtonTargets.removeIf( 848 target -> continuousServicePackages.stream().anyMatch( 849 pkg -> Objects.equals(target, pkg))); 850 if (buttonTargetsChanged) { 851 persistColonDelimitedSetToSettingLocked( 852 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 853 userState.mUserId, 854 userState.mAccessibilityButtonTargets, str -> str); 855 } 856 857 return enabledServicesChanged || buttonTargetsChanged; 858 } 859 860 @VisibleForTesting getPackageMonitor()861 PackageMonitor getPackageMonitor() { 862 return mPackageMonitor; 863 } 864 865 @VisibleForTesting setPackageMonitor(PackageMonitor monitor)866 void setPackageMonitor(PackageMonitor monitor) { 867 mPackageMonitor = monitor; 868 } 869 870 @SuppressLint("MissingPermission") registerBroadcastReceivers()871 private void registerBroadcastReceivers() { 872 // package changes 873 mPackageMonitor = new ManagerPackageMonitor(this); 874 mPackageMonitor.register(mContext, null, UserHandle.ALL, true); 875 876 // user change and unlock 877 IntentFilter intentFilter = new IntentFilter(); 878 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 879 intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); 880 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 881 intentFilter.addAction(Intent.ACTION_SETTING_RESTORED); 882 883 Handler receiverHandler = 884 Flags.managerAvoidReceiverTimeout() ? BackgroundThread.getHandler() : null; 885 mContext.registerReceiverAsUser(new BroadcastReceiver() { 886 @Override 887 public void onReceive(Context context, Intent intent) { 888 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_USER_BROADCAST_RECEIVER)) { 889 mTraceManager.logTrace( 890 LOG_TAG + ".BR.onReceive", 891 FLAGS_USER_BROADCAST_RECEIVER, 892 "context=" + context + ";intent=" + intent); 893 } 894 895 String action = intent.getAction(); 896 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 897 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 898 } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { 899 unlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 900 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 901 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 902 } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) { 903 final String which = intent.getStringExtra(Intent.EXTRA_SETTING_NAME); 904 if (which == null) { 905 return; 906 } 907 final String previousValue = 908 intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE); 909 final String newValue = 910 intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE); 911 final int restoredFromSdk = 912 intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0); 913 switch (which) { 914 case Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES -> { 915 synchronized (mLock) { 916 restoreEnabledAccessibilityServicesLocked( 917 previousValue, newValue, restoredFromSdk); 918 } 919 } 920 case ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED -> { 921 synchronized (mLock) { 922 restoreLegacyDisplayMagnificationNavBarIfNeededLocked( 923 newValue, restoredFromSdk); 924 } 925 } 926 case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> { 927 synchronized (mLock) { 928 restoreAccessibilityButtonTargetsLocked( 929 previousValue, newValue); 930 } 931 } 932 case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> { 933 if (!android.view.accessibility.Flags.a11yQsShortcut()) { 934 return; 935 } 936 restoreAccessibilityQsTargets(newValue); 937 } 938 case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> { 939 if (!android.view.accessibility.Flags 940 .restoreA11yShortcutTargetService()) { 941 return; 942 } 943 restoreAccessibilityShortcutTargetService(previousValue, newValue); 944 } 945 } 946 } 947 } 948 }, UserHandle.ALL, intentFilter, null, receiverHandler); 949 950 final IntentFilter filter = new IntentFilter(); 951 filter.addAction(SafetyCenterManager.ACTION_SAFETY_CENTER_ENABLED_CHANGED); 952 final BroadcastReceiver receiver = new BroadcastReceiver() { 953 @Override 954 public void onReceive(Context context, Intent intent) { 955 setNonA11yToolNotificationToMatchSafetyCenter(); 956 } 957 }; 958 mContext.registerReceiverAsUser( 959 receiver, UserHandle.ALL, filter, null, mMainHandler, 960 Context.RECEIVER_EXPORTED); 961 962 if (!android.companion.virtual.flags.Flags.vdmPublicApis()) { 963 final BroadcastReceiver virtualDeviceReceiver = new BroadcastReceiver() { 964 @Override 965 public void onReceive(Context context, Intent intent) { 966 final int deviceId = intent.getIntExtra( 967 EXTRA_VIRTUAL_DEVICE_ID, DEVICE_ID_DEFAULT); 968 mProxyManager.clearConnections(deviceId); 969 } 970 }; 971 972 final IntentFilter virtualDeviceFilter = new IntentFilter( 973 ACTION_VIRTUAL_DEVICE_REMOVED); 974 mContext.registerReceiver(virtualDeviceReceiver, virtualDeviceFilter, 975 Context.RECEIVER_NOT_EXPORTED); 976 } 977 } 978 979 /** 980 * Disables the component returned by 981 * {@link AccessibilityUtils#getAccessibilityMenuComponentToMigrate} so that it does not appear 982 * in Settings or other places that query for installed accessibility services. 983 * 984 * <p> 985 * SettingsProvider is responsible for migrating users off of Menu-outside-system, 986 * which it performs in its initialization before AccessibilityManagerService is started. 987 * </p> 988 */ disableAccessibilityMenuToMigrateIfNeeded()989 private void disableAccessibilityMenuToMigrateIfNeeded() { 990 int userId; 991 synchronized (mLock) { 992 userId = mCurrentUserId; 993 } 994 final ComponentName menuToMigrate = 995 AccessibilityUtils.getAccessibilityMenuComponentToMigrate(mPackageManager, userId); 996 if (menuToMigrate != null) { 997 // PackageManager#setComponentEnabledSetting disables the component for only the user 998 // linked to PackageManager's context, but mPackageManager is linked to the system user, 999 // so grab a new PackageManager for the current user to support secondary users. 1000 final PackageManager userPackageManager = 1001 mContext.createContextAsUser(UserHandle.of(userId), /* flags = */ 0) 1002 .getPackageManager(); 1003 userPackageManager.setComponentEnabledSetting( 1004 menuToMigrate, 1005 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 1006 PackageManager.DONT_KILL_APP); 1007 } 1008 } 1009 1010 // Called only during settings restore; currently supports only the owner user 1011 // TODO: b/22388012 restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, int restoreFromSdkInt)1012 private void restoreLegacyDisplayMagnificationNavBarIfNeededLocked(String newSetting, 1013 int restoreFromSdkInt) { 1014 if (restoreFromSdkInt >= Build.VERSION_CODES.R) { 1015 return; 1016 } 1017 1018 boolean displayMagnificationNavBarEnabled; 1019 try { 1020 displayMagnificationNavBarEnabled = Integer.parseInt(newSetting) == 1; 1021 } catch (NumberFormatException e) { 1022 Slog.w(LOG_TAG, "number format is incorrect" + e); 1023 return; 1024 } 1025 1026 final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 1027 final Set<String> targetsFromSetting = new ArraySet<>(); 1028 readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 1029 userState.mUserId, str -> str, targetsFromSetting); 1030 final boolean targetsContainMagnification = targetsFromSetting.contains( 1031 MAGNIFICATION_CONTROLLER_NAME); 1032 if (targetsContainMagnification == displayMagnificationNavBarEnabled) { 1033 return; 1034 } 1035 1036 if (displayMagnificationNavBarEnabled) { 1037 targetsFromSetting.add(MAGNIFICATION_CONTROLLER_NAME); 1038 } else { 1039 targetsFromSetting.remove(MAGNIFICATION_CONTROLLER_NAME); 1040 } 1041 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 1042 userState.mUserId, targetsFromSetting, str -> str); 1043 readAccessibilityButtonTargetsLocked(userState); 1044 onUserStateChangedLocked(userState); 1045 } 1046 1047 @Override 1048 @RequiresNoPermission addClient(IAccessibilityManagerClient callback, int userId)1049 public long addClient(IAccessibilityManagerClient callback, int userId) { 1050 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1051 mTraceManager.logTrace(LOG_TAG + ".addClient", FLAGS_ACCESSIBILITY_MANAGER, 1052 "callback=" + callback + ";userId=" + userId); 1053 } 1054 1055 synchronized (mLock) { 1056 // We treat calls from a profile as if made by its parent as profiles 1057 // share the accessibility state of the parent. The call below 1058 // performs the current profile parent resolution. 1059 final int resolvedUserId = mSecurityPolicy 1060 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1061 1062 AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 1063 // Support a process moving from the default device to a single virtual 1064 // device. 1065 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 1066 Binder.getCallingUid()); 1067 Client client = new Client(callback, Binder.getCallingUid(), userState, deviceId); 1068 // If the client is from a process that runs across users such as 1069 // the system UI or the system we add it to the global state that 1070 // is shared across users. 1071 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 1072 if (mProxyManager.isProxyedDeviceId(deviceId)) { 1073 if (DEBUG) { 1074 Slog.v(LOG_TAG, "Added global client for proxy-ed pid: " 1075 + Binder.getCallingPid() + " for device id " + deviceId 1076 + " with package names " + Arrays.toString(client.mPackageNames)); 1077 } 1078 return IntPair.of(mProxyManager.getStateLocked(deviceId), 1079 client.mLastSentRelevantEventTypes); 1080 } 1081 mGlobalClients.register(callback, client); 1082 if (DEBUG) { 1083 Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); 1084 } 1085 } else { 1086 // If the display belongs to a proxy connections 1087 if (mProxyManager.isProxyedDeviceId(deviceId)) { 1088 if (DEBUG) { 1089 Slog.v(LOG_TAG, "Added user client for proxy-ed pid: " 1090 + Binder.getCallingPid() + " for device id " + deviceId 1091 + " with package names " + Arrays.toString(client.mPackageNames)); 1092 } 1093 return IntPair.of(mProxyManager.getStateLocked(deviceId), 1094 client.mLastSentRelevantEventTypes); 1095 } 1096 userState.mUserClients.register(callback, client); 1097 // If this client is not for the current user we do not 1098 // return a state since it is not for the foreground user. 1099 // We will send the state to the client on a user switch. 1100 if (DEBUG) { 1101 Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid() 1102 + " and userId:" + mCurrentUserId); 1103 } 1104 } 1105 return IntPair.of( 1106 (resolvedUserId == mCurrentUserId) ? getClientStateLocked(userState) : 0, 1107 client.mLastSentRelevantEventTypes); 1108 } 1109 } 1110 1111 @Override 1112 @RequiresNoPermission removeClient(IAccessibilityManagerClient callback, int userId)1113 public boolean removeClient(IAccessibilityManagerClient callback, int userId) { 1114 // TODO(b/190216606): Add tracing for removeClient when implementation is the same in master 1115 1116 synchronized (mLock) { 1117 final int resolvedUserId = mSecurityPolicy 1118 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1119 1120 AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 1121 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 1122 boolean unregistered = mGlobalClients.unregister(callback); 1123 if (DEBUG) { 1124 Slog.i(LOG_TAG, 1125 "Removed global client for pid:" + Binder.getCallingPid() + "state: " 1126 + unregistered); 1127 } 1128 return unregistered; 1129 } else { 1130 boolean unregistered = userState.mUserClients.unregister(callback); 1131 if (DEBUG) { 1132 Slog.i(LOG_TAG, "Removed user client for pid:" + Binder.getCallingPid() 1133 + " and userId:" + resolvedUserId + "state: " + unregistered); 1134 } 1135 return unregistered; 1136 } 1137 } 1138 } 1139 1140 @Override 1141 @RequiresNoPermission sendAccessibilityEvent(AccessibilityEvent event, int userId)1142 public void sendAccessibilityEvent(AccessibilityEvent event, int userId) { 1143 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1144 mTraceManager.logTrace(LOG_TAG + ".sendAccessibilityEvent", FLAGS_ACCESSIBILITY_MANAGER, 1145 "event=" + event + ";userId=" + userId); 1146 } 1147 boolean dispatchEvent = false; 1148 int resolvedUserId; 1149 1150 synchronized (mLock) { 1151 if (event.getWindowId() == 1152 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID) { 1153 // The replacer window isn't shown to services. Move its events into the pip. 1154 AccessibilityWindowInfo pip = mA11yWindowManager.getPictureInPictureWindowLocked(); 1155 if (pip != null) { 1156 int pipId = pip.getId(); 1157 event.setWindowId(pipId); 1158 } 1159 } 1160 1161 // We treat calls from a profile as if made by its parent as profiles 1162 // share the accessibility state of the parent. The call below 1163 // performs the current profile parent resolution. 1164 resolvedUserId = mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId); 1165 1166 // Make sure the reported package is one the caller has access to. 1167 event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked( 1168 event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId, 1169 getCallingPid())); 1170 1171 // This method does nothing for a background user. 1172 if (resolvedUserId == mCurrentUserId) { 1173 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(mCurrentUserId, event)) { 1174 mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked( 1175 mCurrentUserId, event.getWindowId(), event.getSourceNodeId(), 1176 event.getEventType(), event.getAction()); 1177 mSecurityPolicy.updateEventSourceLocked(event); 1178 dispatchEvent = true; 1179 } 1180 if (mHasInputFilter && mInputFilter != null) { 1181 mMainHandler.sendMessage(obtainMessage( 1182 AccessibilityManagerService::sendAccessibilityEventToInputFilter, 1183 this, AccessibilityEvent.obtain(event))); 1184 } 1185 } 1186 } 1187 1188 if (dispatchEvent) { 1189 // Make sure clients receiving this event will be able to get the 1190 // current state of the windows as the window manager may be delaying 1191 // the computation for performance reasons. 1192 boolean shouldComputeWindows = false; 1193 int displayId = event.getDisplayId(); 1194 final int windowId = event.getWindowId(); 1195 if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID 1196 && displayId == Display.INVALID_DISPLAY) { 1197 displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowId( 1198 resolvedUserId, windowId); 1199 event.setDisplayId(displayId); 1200 } 1201 synchronized (mLock) { 1202 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1203 && displayId != Display.INVALID_DISPLAY 1204 && mA11yWindowManager.isTrackingWindowsLocked(displayId)) { 1205 shouldComputeWindows = true; 1206 } 1207 } 1208 if (shouldComputeWindows) { 1209 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) { 1210 mTraceManager.logTrace("WindowManagerInternal.computeWindowsForAccessibility", 1211 FLAGS_WINDOW_MANAGER_INTERNAL, "display=" + displayId); 1212 } 1213 final WindowManagerInternal wm = LocalServices.getService( 1214 WindowManagerInternal.class); 1215 wm.computeWindowsForAccessibility(displayId); 1216 // The App side sends a event to notify that the window visible or focused, 1217 // but the window information in framework is not updated yet, so we postpone it. 1218 if (postponeWindowStateEvent(event)) { 1219 return; 1220 } 1221 } 1222 1223 synchronized (mLock) { 1224 dispatchAccessibilityEventLocked(event); 1225 } 1226 } 1227 1228 if (OWN_PROCESS_ID != Binder.getCallingPid()) { 1229 event.recycle(); 1230 } 1231 } 1232 dispatchAccessibilityEventLocked(AccessibilityEvent event)1233 private void dispatchAccessibilityEventLocked(AccessibilityEvent event) { 1234 if (mProxyManager.isProxyedDisplay(event.getDisplayId())) { 1235 mProxyManager.sendAccessibilityEventLocked(event); 1236 } else { 1237 notifyAccessibilityServicesDelayedLocked(event, false); 1238 notifyAccessibilityServicesDelayedLocked(event, true); 1239 } 1240 mUiAutomationManager.sendAccessibilityEventLocked(event); 1241 } 1242 sendAccessibilityEventToInputFilter(AccessibilityEvent event)1243 private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) { 1244 synchronized (mLock) { 1245 if (mHasInputFilter && mInputFilter != null) { 1246 mInputFilter.notifyAccessibilityEvent(event); 1247 } 1248 } 1249 event.recycle(); 1250 } 1251 1252 /** 1253 * This is the implementation of AccessibilityManager system API. 1254 * System UI calls into this method through AccessibilityManager system API to register a 1255 * system action. 1256 */ 1257 @Override 1258 @EnforcePermission(MANAGE_ACCESSIBILITY) registerSystemAction(RemoteAction action, int actionId)1259 public void registerSystemAction(RemoteAction action, int actionId) { 1260 registerSystemAction_enforcePermission(); 1261 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1262 mTraceManager.logTrace(LOG_TAG + ".registerSystemAction", 1263 FLAGS_ACCESSIBILITY_MANAGER, "action=" + action + ";actionId=" + actionId); 1264 } 1265 getSystemActionPerformer().registerSystemAction(actionId, action); 1266 } 1267 1268 /** 1269 * This is the implementation of AccessibilityManager system API. 1270 * System UI calls into this method through AccessibilityManager system API to unregister a 1271 * system action. 1272 */ 1273 @Override 1274 @EnforcePermission(MANAGE_ACCESSIBILITY) unregisterSystemAction(int actionId)1275 public void unregisterSystemAction(int actionId) { 1276 unregisterSystemAction_enforcePermission(); 1277 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1278 mTraceManager.logTrace(LOG_TAG + ".unregisterSystemAction", 1279 FLAGS_ACCESSIBILITY_MANAGER, "actionId=" + actionId); 1280 } 1281 1282 getSystemActionPerformer().unregisterSystemAction(actionId); 1283 } 1284 getSystemActionPerformer()1285 private SystemActionPerformer getSystemActionPerformer() { 1286 if (mSystemActionPerformer == null) { 1287 mSystemActionPerformer = 1288 new SystemActionPerformer(mContext, mWindowManagerService, null, this, this); 1289 } 1290 return mSystemActionPerformer; 1291 } 1292 1293 @Override 1294 @RequiresNoPermission getInstalledAccessibilityServiceList( int userId)1295 public ParceledListSlice<AccessibilityServiceInfo> getInstalledAccessibilityServiceList( 1296 int userId) { 1297 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1298 mTraceManager.logTrace(LOG_TAG + ".getInstalledAccessibilityServiceList", 1299 FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId); 1300 } 1301 1302 final int resolvedUserId; 1303 final List<AccessibilityServiceInfo> serviceInfos; 1304 synchronized (mLock) { 1305 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 1306 Binder.getCallingUid()); 1307 if (mProxyManager.isProxyedDeviceId(deviceId)) { 1308 return new ParceledListSlice<>( 1309 mProxyManager.getInstalledAndEnabledServiceInfosLocked( 1310 AccessibilityServiceInfo.FEEDBACK_ALL_MASK, deviceId)); 1311 } 1312 // We treat calls from a profile as if made by its parent as profiles 1313 // share the accessibility state of the parent. The call below 1314 // performs the current profile parent resolution. 1315 resolvedUserId = mSecurityPolicy 1316 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1317 serviceInfos = new ArrayList<>( 1318 getUserStateLocked(resolvedUserId).mInstalledServices); 1319 } 1320 1321 if (Binder.getCallingPid() == OWN_PROCESS_ID) { 1322 return new ParceledListSlice<>(serviceInfos); 1323 } 1324 final PackageManagerInternal pm = LocalServices.getService( 1325 PackageManagerInternal.class); 1326 final int callingUid = Binder.getCallingUid(); 1327 for (int i = serviceInfos.size() - 1; i >= 0; i--) { 1328 final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i); 1329 if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid, 1330 resolvedUserId)) { 1331 serviceInfos.remove(i); 1332 } 1333 } 1334 return new ParceledListSlice<>(serviceInfos); 1335 } 1336 1337 @Override 1338 @RequiresNoPermission getEnabledAccessibilityServiceList(int feedbackType, int userId)1339 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, 1340 int userId) { 1341 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1342 mTraceManager.logTrace(LOG_TAG + ".getEnabledAccessibilityServiceList", 1343 FLAGS_ACCESSIBILITY_MANAGER, 1344 "feedbackType=" + feedbackType + ";userId=" + userId); 1345 } 1346 1347 synchronized (mLock) { 1348 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 1349 Binder.getCallingUid()); 1350 if (mProxyManager.isProxyedDeviceId(deviceId)) { 1351 return mProxyManager.getInstalledAndEnabledServiceInfosLocked(feedbackType, 1352 deviceId); 1353 } 1354 // We treat calls from a profile as if made by its parent as profiles 1355 // share the accessibility state of the parent. The call below 1356 // performs the current profile parent resolution. 1357 final int resolvedUserId = mSecurityPolicy 1358 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1359 1360 // The automation service can suppress other services. 1361 final AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 1362 if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) { 1363 return Collections.emptyList(); 1364 } 1365 1366 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 1367 final int serviceCount = services.size(); 1368 final List<AccessibilityServiceInfo> result = new ArrayList<>(serviceCount); 1369 for (int i = 0; i < serviceCount; ++i) { 1370 final AccessibilityServiceConnection service = services.get(i); 1371 if ((service.mFeedbackType & feedbackType) != 0 1372 || feedbackType == AccessibilityServiceInfo.FEEDBACK_ALL_MASK) { 1373 result.add(service.getServiceInfo()); 1374 } 1375 } 1376 return result; 1377 } 1378 } 1379 1380 @Override 1381 @RequiresNoPermission interrupt(int userId)1382 public void interrupt(int userId) { 1383 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1384 mTraceManager.logTrace(LOG_TAG + ".interrupt", 1385 FLAGS_ACCESSIBILITY_MANAGER, "userId=" + userId); 1386 } 1387 1388 List<IAccessibilityServiceClient> interfacesToInterrupt; 1389 synchronized (mLock) { 1390 // We treat calls from a profile as if made by its parent as profiles 1391 // share the accessibility state of the parent. The call below 1392 // performs the current profile parent resolution. 1393 final int resolvedUserId = mSecurityPolicy 1394 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1395 // This method does nothing for a background user. 1396 if (resolvedUserId != mCurrentUserId) { 1397 return; 1398 } 1399 1400 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 1401 Binder.getCallingUid()); 1402 if (mProxyManager.isProxyedDeviceId(deviceId)) { 1403 interfacesToInterrupt = new ArrayList<>(); 1404 mProxyManager.addServiceInterfacesLocked(interfacesToInterrupt, deviceId); 1405 } else { 1406 List<AccessibilityServiceConnection> services = 1407 getUserStateLocked(resolvedUserId).mBoundServices; 1408 interfacesToInterrupt = new ArrayList<>(services.size()); 1409 for (int i = 0; i < services.size(); i++) { 1410 AccessibilityServiceConnection service = services.get(i); 1411 IBinder a11yServiceBinder = service.mService; 1412 IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface; 1413 if ((a11yServiceBinder != null) && (a11yServiceInterface != null)) { 1414 interfacesToInterrupt.add(a11yServiceInterface); 1415 } 1416 } 1417 } 1418 } 1419 for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) { 1420 try { 1421 if (mTraceManager.isA11yTracingEnabledForTypes( 1422 FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 1423 mTraceManager.logTrace(LOG_TAG + ".IAccessibilityServiceClient.onInterrupt", 1424 FLAGS_ACCESSIBILITY_SERVICE_CLIENT); 1425 } 1426 interfacesToInterrupt.get(i).onInterrupt(); 1427 } catch (RemoteException re) { 1428 Slog.e(LOG_TAG, "Error sending interrupt request to " 1429 + interfacesToInterrupt.get(i), re); 1430 } 1431 } 1432 } 1433 1434 @Override 1435 @RequiresNoPermission addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, IAccessibilityInteractionConnection connection, String packageName, int userId)1436 public int addAccessibilityInteractionConnection(IWindow windowToken, IBinder leashToken, 1437 IAccessibilityInteractionConnection connection, String packageName, 1438 int userId) throws RemoteException { 1439 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1440 mTraceManager.logTrace(LOG_TAG + ".addAccessibilityInteractionConnection", 1441 FLAGS_ACCESSIBILITY_MANAGER, 1442 "windowToken=" + windowToken + "leashToken=" + leashToken + ";connection=" 1443 + connection + "; packageName=" + packageName + ";userId=" + userId); 1444 } 1445 1446 return mA11yWindowManager.addAccessibilityInteractionConnection( 1447 windowToken, leashToken, connection, packageName, userId); 1448 } 1449 1450 @Override 1451 @RequiresNoPermission removeAccessibilityInteractionConnection(IWindow window)1452 public void removeAccessibilityInteractionConnection(IWindow window) { 1453 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1454 mTraceManager.logTrace(LOG_TAG + ".removeAccessibilityInteractionConnection", 1455 FLAGS_ACCESSIBILITY_MANAGER, "window=" + window); 1456 } 1457 mA11yWindowManager.removeAccessibilityInteractionConnection(window); 1458 } 1459 1460 @Override 1461 @EnforcePermission(MODIFY_ACCESSIBILITY_DATA) setPictureInPictureActionReplacingConnection( IAccessibilityInteractionConnection connection)1462 public void setPictureInPictureActionReplacingConnection( 1463 IAccessibilityInteractionConnection connection) throws RemoteException { 1464 setPictureInPictureActionReplacingConnection_enforcePermission(); 1465 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1466 mTraceManager.logTrace(LOG_TAG + ".setPictureInPictureActionReplacingConnection", 1467 FLAGS_ACCESSIBILITY_MANAGER, "connection=" + connection); 1468 } 1469 mA11yWindowManager.setPictureInPictureActionReplacingConnection(connection); 1470 } 1471 1472 @Override 1473 @EnforcePermission(RETRIEVE_WINDOW_CONTENT) registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo, int userId, int flags)1474 public void registerUiTestAutomationService(IBinder owner, 1475 IAccessibilityServiceClient serviceClient, 1476 AccessibilityServiceInfo accessibilityServiceInfo, 1477 int userId, 1478 int flags) { 1479 registerUiTestAutomationService_enforcePermission(); 1480 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1481 mTraceManager.logTrace(LOG_TAG + ".registerUiTestAutomationService", 1482 FLAGS_ACCESSIBILITY_MANAGER, 1483 "owner=" + owner + ";serviceClient=" + serviceClient 1484 + ";accessibilityServiceInfo=" + accessibilityServiceInfo + ";flags=" + flags); 1485 } 1486 1487 synchronized (mLock) { 1488 changeCurrentUserForTestAutomationIfNeededLocked(userId); 1489 mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient, 1490 mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler, 1491 mSecurityPolicy, this, getTraceManager(), mWindowManagerService, 1492 getSystemActionPerformer(), mA11yWindowManager, flags); 1493 onUserStateChangedLocked(getCurrentUserStateLocked()); 1494 } 1495 } 1496 1497 @Override 1498 @RequiresNoPermission unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)1499 public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { 1500 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1501 mTraceManager.logTrace(LOG_TAG + ".unregisterUiTestAutomationService", 1502 FLAGS_ACCESSIBILITY_MANAGER, "serviceClient=" + serviceClient); 1503 } 1504 synchronized (mLock) { 1505 mUiAutomationManager.unregisterUiTestAutomationServiceLocked(serviceClient); 1506 restoreCurrentUserAfterTestAutomationIfNeededLocked(); 1507 } 1508 } 1509 1510 // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation 1511 @GuardedBy("mLock") changeCurrentUserForTestAutomationIfNeededLocked(@serIdInt int userId)1512 private void changeCurrentUserForTestAutomationIfNeededLocked(@UserIdInt int userId) { 1513 if (mVisibleBgUserIds == null) { 1514 Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(%d): ignoring " 1515 + "because device doesn't support visible background users", userId); 1516 return; 1517 } 1518 if (!mVisibleBgUserIds.get(userId)) { 1519 Slogf.wtf(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): cannot change " 1520 + "current user to %d as it's not visible (mVisibleUsers=%s)", 1521 userId, mVisibleBgUserIds); 1522 return; 1523 } 1524 if (mCurrentUserId == userId) { 1525 Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): NOT changing " 1526 + "current user for test automation purposes as it is already %d", 1527 mCurrentUserId); 1528 return; 1529 } 1530 Slogf.i(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): changing current user" 1531 + " from %d to %d for test automation purposes", mCurrentUserId, userId); 1532 mRealCurrentUserId = mCurrentUserId; 1533 switchUser(userId); 1534 } 1535 1536 // TODO(b/255426725): temporary workaround to support visible background users for UiAutomation 1537 @GuardedBy("mLock") restoreCurrentUserAfterTestAutomationIfNeededLocked()1538 private void restoreCurrentUserAfterTestAutomationIfNeededLocked() { 1539 if (mVisibleBgUserIds == null) { 1540 Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring " 1541 + "because device doesn't support visible background users"); 1542 return; 1543 } 1544 if (mRealCurrentUserId == UserHandle.USER_CURRENT) { 1545 Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring " 1546 + "because mRealCurrentUserId is already USER_CURRENT"); 1547 return; 1548 } 1549 Slogf.i(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): restoring current " 1550 + "user to %d after using %d for test automation purposes", 1551 mRealCurrentUserId, mCurrentUserId); 1552 int currentUserId = mRealCurrentUserId; 1553 mRealCurrentUserId = UserHandle.USER_CURRENT; 1554 switchUser(currentUserId); 1555 } 1556 1557 @Override 1558 @EnforcePermission(RETRIEVE_WINDOW_CONTENT) getWindowToken(int windowId, int userId)1559 public IBinder getWindowToken(int windowId, int userId) { 1560 getWindowToken_enforcePermission(); 1561 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1562 mTraceManager.logTrace(LOG_TAG + ".getWindowToken", 1563 FLAGS_ACCESSIBILITY_MANAGER, "windowId=" + windowId + ";userId=" + userId); 1564 } 1565 1566 synchronized (mLock) { 1567 // We treat calls from a profile as if made by its parent as profiles 1568 // share the accessibility state of the parent. The call below 1569 // performs the current profile parent resolution. 1570 final int resolvedUserId = mSecurityPolicy 1571 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1572 if (resolvedUserId != mCurrentUserId) { 1573 return null; 1574 } 1575 final AccessibilityWindowInfo accessibilityWindowInfo = mA11yWindowManager 1576 .findA11yWindowInfoByIdLocked(windowId); 1577 if (accessibilityWindowInfo == null) { 1578 return null; 1579 } 1580 // We use AccessibilityWindowInfo#getId instead of windowId. When the windowId comes 1581 // from an embedded hierarchy, the system can't find correct window token because 1582 // embedded hierarchy doesn't have windowInfo. Calling 1583 // AccessibilityWindowManager#findA11yWindowInfoByIdLocked can look for its parent's 1584 // windowInfo, so it is safer to use AccessibilityWindowInfo#getId 1585 // to get window token to find real window. 1586 return mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(userId, 1587 accessibilityWindowInfo.getId()); 1588 } 1589 } 1590 1591 /** 1592 * Invoked remotely over AIDL by SysUi when the accessibility button within the system's 1593 * navigation area has been clicked. 1594 * 1595 * @param displayId The logical display id. 1596 * @param targetName The flattened {@link ComponentName} string or the class name of a system 1597 * class implementing a supported accessibility feature, or {@code null} if there's no 1598 * specified target. 1599 */ 1600 @Override 1601 @EnforcePermission(STATUS_BAR_SERVICE) notifyAccessibilityButtonClicked(int displayId, String targetName)1602 public void notifyAccessibilityButtonClicked(int displayId, String targetName) { 1603 notifyAccessibilityButtonClicked_enforcePermission(); 1604 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1605 mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonClicked", 1606 FLAGS_ACCESSIBILITY_MANAGER, 1607 "displayId=" + displayId + ";targetName=" + targetName); 1608 } 1609 1610 if (targetName == null) { 1611 synchronized (mLock) { 1612 final AccessibilityUserState userState = getCurrentUserStateLocked(); 1613 targetName = userState.getTargetAssignedToAccessibilityButton(); 1614 } 1615 } 1616 mMainHandler.sendMessage(obtainMessage( 1617 AccessibilityManagerService::performAccessibilityShortcutInternal, this, 1618 displayId, UserShortcutType.SOFTWARE, targetName)); 1619 } 1620 1621 /** 1622 * Invoked remotely over AIDL by SysUi when the visibility of the accessibility 1623 * button within the system's navigation area has changed. 1624 * 1625 * @param shown {@code true} if the accessibility button is shown to the 1626 * user, {@code false} otherwise 1627 */ 1628 @Override 1629 @EnforcePermission(STATUS_BAR_SERVICE) notifyAccessibilityButtonVisibilityChanged(boolean shown)1630 public void notifyAccessibilityButtonVisibilityChanged(boolean shown) { 1631 notifyAccessibilityButtonVisibilityChanged_enforcePermission(); 1632 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 1633 mTraceManager.logTrace(LOG_TAG + ".notifyAccessibilityButtonVisibilityChanged", 1634 FLAGS_ACCESSIBILITY_MANAGER, "shown=" + shown); 1635 } 1636 1637 synchronized (mLock) { 1638 notifyAccessibilityButtonVisibilityChangedLocked(shown); 1639 } 1640 } 1641 1642 @Override 1643 @EnforcePermission(allOf = { STATUS_BAR_SERVICE, MANAGE_ACCESSIBILITY }) notifyQuickSettingsTilesChanged( @serIdInt int userId, @NonNull List<ComponentName> tileComponentNames)1644 public void notifyQuickSettingsTilesChanged( 1645 @UserIdInt int userId, @NonNull List<ComponentName> tileComponentNames) { 1646 notifyQuickSettingsTilesChanged_enforcePermission(); 1647 if (!android.view.accessibility.Flags.a11yQsShortcut()) { 1648 return; 1649 } 1650 if (DEBUG) { 1651 Slog.d(LOG_TAG, TextUtils.formatSimple( 1652 "notifyQuickSettingsTilesChanged userId: %d, tileComponentNames: %s", 1653 userId, tileComponentNames)); 1654 } 1655 final Set<ComponentName> newTileComponentNames = new ArraySet<>(tileComponentNames); 1656 final Set<ComponentName> addedTiles; 1657 final Set<ComponentName> removedTiles; 1658 final Map<ComponentName, AccessibilityServiceInfo> tileServiceToA11yServiceInfo; 1659 final Map<ComponentName, ComponentName> a11yFeatureToTileService; 1660 1661 // update in-memory copy of QS_TILES in AccessibilityManager 1662 synchronized (mLock) { 1663 AccessibilityUserState userState = getUserStateLocked(userId); 1664 1665 tileServiceToA11yServiceInfo = userState.getTileServiceToA11yServiceInfoMapLocked(); 1666 a11yFeatureToTileService = userState.getA11yFeatureToTileService(); 1667 1668 ArraySet<ComponentName> currentTiles = userState.getA11yQsTilesInQsPanel(); 1669 // Find newly added tiles 1670 addedTiles = newTileComponentNames 1671 .stream() 1672 .filter(tileComponentName -> !currentTiles.contains(tileComponentName)) 1673 .collect(Collectors.toSet()); 1674 // Find newly removed tiles 1675 removedTiles = currentTiles 1676 .stream() 1677 .filter(tileComponentName -> !newTileComponentNames.contains(tileComponentName)) 1678 .collect(Collectors.toSet()); 1679 1680 if (addedTiles.isEmpty() && removedTiles.isEmpty()) { 1681 return; 1682 } 1683 1684 userState.updateA11yTilesInQsPanelLocked(newTileComponentNames); 1685 } 1686 1687 List<String> a11yFeaturesToEnable = new ArrayList<>(); 1688 List<String> a11yFeaturesToRemove = new ArrayList<>(); 1689 // Find the framework features to configure the qs shortcut on/off 1690 for (Map.Entry<ComponentName, ComponentName> frameworkFeatureWithTile : 1691 ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.entrySet()) { 1692 String a11yFeature = frameworkFeatureWithTile.getKey().flattenToString(); 1693 ComponentName tile = frameworkFeatureWithTile.getValue(); 1694 if (addedTiles.contains(tile)) { 1695 a11yFeaturesToEnable.add(a11yFeature); 1696 } else if (removedTiles.contains(tile)) { 1697 a11yFeaturesToRemove.add(a11yFeature); 1698 } 1699 } 1700 // Find the accessibility service/activity to configure the qs shortcut on/off 1701 for (Map.Entry<ComponentName, ComponentName> a11yFeatureWithTileService : 1702 a11yFeatureToTileService.entrySet()) { 1703 String a11yFeature = a11yFeatureWithTileService.getKey().flattenToString(); 1704 ComponentName tileService = a11yFeatureWithTileService.getValue(); 1705 if (addedTiles.contains(tileService)) { 1706 AccessibilityServiceInfo serviceInfo = tileServiceToA11yServiceInfo.getOrDefault( 1707 tileService, null); 1708 if (serviceInfo != null && isAccessibilityServiceWarningRequired(serviceInfo)) { 1709 // TODO(b/314850435): show full device control warning if needed after 1710 // SysUI QS Panel can update live 1711 // The user attempts to add QS shortcut in QS Panel, but we don't actually 1712 // turn on the shortcut due to lack of full device control permission 1713 logMetricForQsShortcutConfiguration(/* enable= */ true, /* numOfFeatures= */ 1); 1714 continue; 1715 } 1716 a11yFeaturesToEnable.add(a11yFeature); 1717 } else if (removedTiles.contains(tileService)) { 1718 a11yFeaturesToRemove.add(a11yFeature); 1719 } 1720 } 1721 // Turn on/off a11y qs shortcut for the a11y features based on the change in QS Panel 1722 if (!a11yFeaturesToEnable.isEmpty()) { 1723 enableShortcutForTargets(/* enable= */ true, UserShortcutType.QUICK_SETTINGS, 1724 a11yFeaturesToEnable, userId); 1725 } 1726 1727 if (!a11yFeaturesToRemove.isEmpty()) { 1728 enableShortcutForTargets(/* enable= */ false, UserShortcutType.QUICK_SETTINGS, 1729 a11yFeaturesToRemove, userId); 1730 } 1731 } 1732 1733 /** 1734 * Called when a gesture is detected on a display by the framework. 1735 * 1736 * @param gestureEvent the detail of the gesture. 1737 * @return true if the event is handled. 1738 */ onGesture(AccessibilityGestureEvent gestureEvent)1739 public boolean onGesture(AccessibilityGestureEvent gestureEvent) { 1740 synchronized (mLock) { 1741 boolean handled = notifyGestureLocked(gestureEvent, false); 1742 if (!handled) { 1743 handled = notifyGestureLocked(gestureEvent, true); 1744 } 1745 return handled; 1746 } 1747 } 1748 1749 /** Send a motion event to the services. */ sendMotionEventToListeningServices(MotionEvent event)1750 public boolean sendMotionEventToListeningServices(MotionEvent event) { 1751 boolean result; 1752 event = MotionEvent.obtain(event); 1753 if (DEBUG) { 1754 Slog.d(LOG_TAG, "Sending event to service: " + event); 1755 } 1756 result = scheduleNotifyMotionEvent(event); 1757 return result; 1758 } 1759 1760 /** 1761 * Notifies services that the touch state on a given display has changed. 1762 */ onTouchStateChanged(int displayId, int state)1763 public boolean onTouchStateChanged(int displayId, int state) { 1764 if (DEBUG) { 1765 Slog.d(LOG_TAG, "Notifying touch state:" 1766 + TouchInteractionController.stateToString(state)); 1767 } 1768 return scheduleNotifyTouchState(displayId, state); 1769 } 1770 1771 /** 1772 * Called when the system action list is changed. 1773 */ 1774 @Override onSystemActionsChanged()1775 public void onSystemActionsChanged() { 1776 synchronized (mLock) { 1777 AccessibilityUserState state = getCurrentUserStateLocked(); 1778 notifySystemActionsChangedLocked(state); 1779 } 1780 } 1781 1782 @Override 1783 // TODO(b/276459590): Remove when this is resolved at the virtual device/input level. moveNonProxyTopFocusedDisplayToTopIfNeeded()1784 public void moveNonProxyTopFocusedDisplayToTopIfNeeded() { 1785 mA11yWindowManager.moveNonProxyTopFocusedDisplayToTopIfNeeded(); 1786 } 1787 1788 @Override 1789 // TODO(b/276459590): Remove when this is resolved at the virtual device/input level. getLastNonProxyTopFocusedDisplayId()1790 public int getLastNonProxyTopFocusedDisplayId() { 1791 return mA11yWindowManager.getLastNonProxyTopFocusedDisplayId(); 1792 } 1793 1794 @VisibleForTesting notifySystemActionsChangedLocked(AccessibilityUserState userState)1795 void notifySystemActionsChangedLocked(AccessibilityUserState userState) { 1796 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 1797 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 1798 service.notifySystemActionsChangedLocked(); 1799 } 1800 } 1801 1802 @VisibleForTesting notifyKeyEvent(KeyEvent event, int policyFlags)1803 public boolean notifyKeyEvent(KeyEvent event, int policyFlags) { 1804 synchronized (mLock) { 1805 List<AccessibilityServiceConnection> boundServices = 1806 getCurrentUserStateLocked().mBoundServices; 1807 if (boundServices.isEmpty()) { 1808 return false; 1809 } 1810 return getKeyEventDispatcher().notifyKeyEventLocked(event, policyFlags, boundServices); 1811 } 1812 } 1813 1814 /** 1815 * Called by the MagnificationController when the state of display 1816 * magnification changes. 1817 * 1818 * <p> 1819 * It can notify window magnification change if the service supports controlling all the 1820 * magnification mode. 1821 * </p> 1822 * 1823 * @param displayId The logical display id 1824 * @param region The magnification region. 1825 * If the config mode is 1826 * {@link MagnificationConfig#MAGNIFICATION_MODE_FULLSCREEN}, 1827 * it is the region of the screen currently active for magnification. 1828 * the returned region will be empty if the magnification is not active 1829 * (e.g. scale is 1. And the magnification is active if magnification 1830 * gestures are enabled or if a service is running that can control 1831 * magnification. 1832 * If the config mode is 1833 * {@link MagnificationConfig#MAGNIFICATION_MODE_WINDOW}, 1834 * it is the region of screen projected on the magnification window. 1835 * The region will be empty if magnification is not activated. 1836 * @param config The magnification config. That has magnification mode, the new scale and the 1837 * new screen-relative center position 1838 */ notifyMagnificationChanged(int displayId, @NonNull Region region, @NonNull MagnificationConfig config)1839 public void notifyMagnificationChanged(int displayId, @NonNull Region region, 1840 @NonNull MagnificationConfig config) { 1841 synchronized (mLock) { 1842 notifyClearAccessibilityCacheLocked(); 1843 notifyMagnificationChangedLocked(displayId, region, config); 1844 } 1845 } 1846 1847 /** 1848 * Called by AccessibilityInputFilter when it creates or destroys the motionEventInjector. 1849 * Not using a getter because the AccessibilityInputFilter isn't thread-safe 1850 * 1851 * @param motionEventInjectors The array of motionEventInjectors. May be null. 1852 * 1853 */ setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors)1854 void setMotionEventInjectors(SparseArray<MotionEventInjector> motionEventInjectors) { 1855 synchronized (mLock) { 1856 mMotionEventInjectors = motionEventInjectors; 1857 // We may be waiting on this object being set 1858 mLock.notifyAll(); 1859 } 1860 } 1861 1862 @Override getMotionEventInjectorForDisplayLocked(int displayId)1863 public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) { 1864 final long endMillis = SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS; 1865 MotionEventInjector motionEventInjector = null; 1866 while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) { 1867 try { 1868 mLock.wait(endMillis - SystemClock.uptimeMillis()); 1869 } catch (InterruptedException ie) { 1870 /* ignore */ 1871 } 1872 } 1873 if (mMotionEventInjectors == null) { 1874 Slog.e(LOG_TAG, "MotionEventInjector installation timed out"); 1875 } else { 1876 motionEventInjector = mMotionEventInjectors.get(displayId); 1877 } 1878 return motionEventInjector; 1879 } 1880 1881 /** 1882 * Gets a point within the accessibility focused node where we can send down 1883 * and up events to perform a click. 1884 * 1885 * @param outPoint The click point to populate. 1886 * @return Whether accessibility a click point was found and set. 1887 */ 1888 // TODO: (multi-display) Make sure this works for multiple displays. getAccessibilityFocusClickPointInScreen(Point outPoint)1889 public boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { 1890 return getInteractionBridge().getAccessibilityFocusClickPointInScreenNotLocked(outPoint); 1891 } 1892 1893 /** 1894 * Perform an accessibility action on the view that currently has accessibility focus. 1895 * Has no effect if no item has accessibility focus, if the item with accessibility 1896 * focus does not expose the specified action, or if the action fails. 1897 * 1898 * @param action The action to perform. 1899 * 1900 * @return {@code true} if the action was performed. {@code false} if it was not. 1901 */ performActionOnAccessibilityFocusedItem( AccessibilityNodeInfo.AccessibilityAction action)1902 public boolean performActionOnAccessibilityFocusedItem( 1903 AccessibilityNodeInfo.AccessibilityAction action) { 1904 return getInteractionBridge().performActionOnAccessibilityFocusedItemNotLocked(action); 1905 } 1906 1907 /** 1908 * Returns true if accessibility focus is confined to the active window. 1909 */ accessibilityFocusOnlyInActiveWindow()1910 public boolean accessibilityFocusOnlyInActiveWindow() { 1911 synchronized (mLock) { 1912 return mA11yWindowManager.accessibilityFocusOnlyInActiveWindowLocked(); 1913 } 1914 } 1915 1916 /** 1917 * Gets the bounds of a window. 1918 * 1919 * @param outBounds The output to which to write the bounds. 1920 */ getWindowBounds(int windowId, Rect outBounds)1921 boolean getWindowBounds(int windowId, Rect outBounds) { 1922 IBinder token; 1923 synchronized (mLock) { 1924 token = getWindowToken(windowId, mCurrentUserId); 1925 } 1926 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL)) { 1927 mTraceManager.logTrace("WindowManagerInternal.getWindowFrame", 1928 FLAGS_WINDOW_MANAGER_INTERNAL, "token=" + token + ";outBounds=" + outBounds); 1929 } 1930 mWindowManagerService.getWindowFrame(token, outBounds); 1931 if (!outBounds.isEmpty()) { 1932 return true; 1933 } 1934 return false; 1935 } 1936 getActiveWindowId()1937 public int getActiveWindowId() { 1938 return mA11yWindowManager.getActiveWindowId(mCurrentUserId); 1939 } 1940 onTouchInteractionStart()1941 public void onTouchInteractionStart() { 1942 mA11yWindowManager.onTouchInteractionStart(); 1943 } 1944 onTouchInteractionEnd()1945 public void onTouchInteractionEnd() { 1946 mA11yWindowManager.onTouchInteractionEnd(); 1947 } 1948 1949 @VisibleForTesting switchUser(int userId)1950 void switchUser(int userId) { 1951 mMagnificationController.updateUserIdIfNeeded(userId); 1952 List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = null; 1953 List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = null; 1954 parsedAccessibilityServiceInfos = parseAccessibilityServiceInfos(userId); 1955 parsedAccessibilityShortcutInfos = parseAccessibilityShortcutInfos(userId); 1956 synchronized (mLock) { 1957 if (mCurrentUserId == userId && mInitialized) { 1958 return; 1959 } 1960 1961 // Disconnect from services for the old user. 1962 AccessibilityUserState oldUserState = getCurrentUserStateLocked(); 1963 oldUserState.onSwitchToAnotherUserLocked(); 1964 1965 // Disable the local managers for the old user. 1966 if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) { 1967 mMainHandler.sendMessage(obtainMessage( 1968 AccessibilityManagerService::sendStateToClients, 1969 this, 0, oldUserState.mUserId)); 1970 } 1971 1972 // Announce user changes only if more that one exist. 1973 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 1974 final boolean announceNewUser = userManager.getUsers().size() > 1; 1975 1976 // The user changed. 1977 mCurrentUserId = userId; 1978 AccessibilityUserState userState = getCurrentUserStateLocked(); 1979 1980 readConfigurationForUserStateLocked(userState, 1981 parsedAccessibilityServiceInfos, parsedAccessibilityShortcutInfos); 1982 mSecurityPolicy.onSwitchUserLocked(mCurrentUserId, userState.mEnabledServices); 1983 // Even if reading did not yield change, we have to update 1984 // the state since the context in which the current user 1985 // state was used has changed since it was inactive. 1986 onUserStateChangedLocked(userState); 1987 // It's better to have this migration in SettingsProvider. Unfortunately, 1988 // SettingsProvider migrated database in a very early stage which A11yManagerService 1989 // haven't finished or started the initialization. We cannot get enough information from 1990 // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for 1991 // restoreFromSdkInt to have this migration check execute every time, because we did not 1992 // find out a way to detect the device finished the OTA and switch the user. 1993 migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, 1994 /* restoreFromSdkInt = */0); 1995 // Package components are disabled per user, so secondary users also need their migrated 1996 // Accessibility Menu component disabled. 1997 disableAccessibilityMenuToMigrateIfNeeded(); 1998 1999 if (announceNewUser) { 2000 // Schedule announcement of the current user if needed. 2001 mMainHandler.sendMessageDelayed( 2002 obtainMessage(AccessibilityManagerService::announceNewUserIfNeeded, this), 2003 WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS); 2004 } 2005 } 2006 } 2007 announceNewUserIfNeeded()2008 private void announceNewUserIfNeeded() { 2009 synchronized (mLock) { 2010 AccessibilityUserState userState = getCurrentUserStateLocked(); 2011 if (userState.isHandlingAccessibilityEventsLocked()) { 2012 UserManager userManager = (UserManager) mContext.getSystemService( 2013 Context.USER_SERVICE); 2014 String message = mContext.getString(R.string.user_switched, 2015 userManager.getUserInfo(mCurrentUserId).name); 2016 AccessibilityEvent event = AccessibilityEvent.obtain( 2017 AccessibilityEvent.TYPE_ANNOUNCEMENT); 2018 event.getText().add(message); 2019 sendAccessibilityEventLocked(event, mCurrentUserId); 2020 } 2021 } 2022 } 2023 unlockUser(int userId)2024 private void unlockUser(int userId) { 2025 synchronized (mLock) { 2026 int parentUserId = mSecurityPolicy.resolveProfileParentLocked(userId); 2027 if (parentUserId == mCurrentUserId) { 2028 AccessibilityUserState userState = getUserStateLocked(mCurrentUserId); 2029 onUserStateChangedLocked(userState); 2030 } 2031 } 2032 } 2033 removeUser(int userId)2034 private void removeUser(int userId) { 2035 synchronized (mLock) { 2036 mUserStates.remove(userId); 2037 } 2038 getMagnificationController().onUserRemoved(userId); 2039 } 2040 2041 // Called only during settings restore; currently supports only the owner user 2042 // TODO: http://b/22388012 restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting, int restoreFromSdkInt)2043 void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting, 2044 int restoreFromSdkInt) { 2045 readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false); 2046 readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true); 2047 2048 AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 2049 userState.mEnabledServices.clear(); 2050 userState.mEnabledServices.addAll(mTempComponentNameSet); 2051 persistComponentNamesToSettingLocked( 2052 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 2053 userState.mEnabledServices, 2054 UserHandle.USER_SYSTEM); 2055 onUserStateChangedLocked(userState); 2056 migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt); 2057 } 2058 2059 /** 2060 * User could enable accessibility services and configure accessibility button during the SUW. 2061 * Merges current value of accessibility button settings into the restored one to make sure 2062 * user's preferences of accessibility button updated in SUW are not lost. 2063 * 2064 * Called only during settings restore; currently supports only the owner user 2065 * TODO: http://b/22388012 2066 */ restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting)2067 void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) { 2068 final Set<String> targetsFromSetting = new ArraySet<>(); 2069 readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting, 2070 /* doMerge = */false); 2071 readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting, 2072 /* doMerge = */true); 2073 2074 final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 2075 userState.mAccessibilityButtonTargets.clear(); 2076 userState.mAccessibilityButtonTargets.addAll(targetsFromSetting); 2077 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 2078 UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str); 2079 2080 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2081 onUserStateChangedLocked(userState); 2082 } 2083 2084 /** 2085 * User could configure accessibility shortcut during the SUW before restoring user data. 2086 * Merges the current value and the new value to make sure we don't lost the setting the user's 2087 * preferences of accessibility qs shortcut updated in SUW are not lost. 2088 * 2089 * Called only during settings restore; currently supports only the owner user 2090 * TODO: http://b/22388012 2091 */ restoreAccessibilityQsTargets(String newValue)2092 private void restoreAccessibilityQsTargets(String newValue) { 2093 synchronized (mLock) { 2094 final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 2095 final Set<String> mergedTargets = userState.getA11yQsTargets(); 2096 readColonDelimitedStringToSet(newValue, str -> str, mergedTargets, 2097 /* doMerge = */ true); 2098 2099 userState.updateA11yQsTargetLocked(mergedTargets); 2100 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_QS_TARGETS, 2101 UserHandle.USER_SYSTEM, mergedTargets, str -> str); 2102 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2103 onUserStateChangedLocked(userState); 2104 } 2105 } 2106 2107 /** 2108 * Merges the old and restored value of 2109 * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}. 2110 * 2111 * <p>Also clears out {@link R.string#config_defaultAccessibilityService} from 2112 * the merged set if it was not present before restoring. 2113 */ restoreAccessibilityShortcutTargetService( String oldValue, String restoredValue)2114 private void restoreAccessibilityShortcutTargetService( 2115 String oldValue, String restoredValue) { 2116 final Set<String> targetsFromSetting = new ArraySet<>(); 2117 readColonDelimitedStringToSet(oldValue, str -> str, 2118 targetsFromSetting, /*doMerge=*/false); 2119 final String defaultService = 2120 mContext.getString(R.string.config_defaultAccessibilityService); 2121 final ComponentName defaultServiceComponent = TextUtils.isEmpty(defaultService) 2122 ? null : ComponentName.unflattenFromString(defaultService); 2123 boolean shouldClearDefaultService = defaultServiceComponent != null 2124 && !stringSetContainsComponentName(targetsFromSetting, defaultServiceComponent); 2125 readColonDelimitedStringToSet(restoredValue, str -> str, 2126 targetsFromSetting, /*doMerge=*/true); 2127 if (Flags.clearDefaultFromA11yShortcutTargetServiceRestore()) { 2128 if (shouldClearDefaultService && stringSetContainsComponentName( 2129 targetsFromSetting, defaultServiceComponent)) { 2130 Slog.i(LOG_TAG, "Removing default service " + defaultService 2131 + " from restore of " 2132 + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); 2133 targetsFromSetting.removeIf(str -> 2134 defaultServiceComponent.equals(ComponentName.unflattenFromString(str))); 2135 } 2136 if (targetsFromSetting.isEmpty()) { 2137 return; 2138 } 2139 } 2140 synchronized (mLock) { 2141 final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM); 2142 final Set<String> shortcutTargets = 2143 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE); 2144 shortcutTargets.clear(); 2145 shortcutTargets.addAll(targetsFromSetting); 2146 persistColonDelimitedSetToSettingLocked( 2147 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, 2148 UserHandle.USER_SYSTEM, targetsFromSetting, str -> str); 2149 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 2150 onUserStateChangedLocked(userState); 2151 } 2152 } 2153 2154 /** 2155 * Returns {@code true} if the set contains the provided non-null {@link ComponentName}. 2156 * 2157 * <p>This ignores values in the set that are not valid {@link ComponentName}s. 2158 */ stringSetContainsComponentName(Set<String> set, @NonNull ComponentName componentName)2159 private boolean stringSetContainsComponentName(Set<String> set, 2160 @NonNull ComponentName componentName) { 2161 return componentName != null && set.stream() 2162 .map(ComponentName::unflattenFromString) 2163 .anyMatch(componentName::equals); 2164 } 2165 getClientStateLocked(AccessibilityUserState userState)2166 private int getClientStateLocked(AccessibilityUserState userState) { 2167 return userState.getClientStateLocked( 2168 mUiAutomationManager.canIntrospect(), 2169 mTraceManager.getTraceStateForAccessibilityManagerClientState()); 2170 } 2171 getInteractionBridge()2172 private InteractionBridge getInteractionBridge() { 2173 synchronized (mLock) { 2174 if (mInteractionBridge == null) { 2175 mInteractionBridge = new InteractionBridge(); 2176 } 2177 return mInteractionBridge; 2178 } 2179 } 2180 notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault)2181 private boolean notifyGestureLocked(AccessibilityGestureEvent gestureEvent, boolean isDefault) { 2182 // TODO: Now we are giving the gestures to the last enabled 2183 // service that can handle them which is the last one 2184 // in our list since we write the last enabled as the 2185 // last record in the enabled services setting. Ideally, 2186 // the user should make the call which service handles 2187 // gestures. However, only one service should handle 2188 // gestures to avoid user frustration when different 2189 // behavior is observed from different combinations of 2190 // enabled accessibility services. 2191 AccessibilityUserState state = getCurrentUserStateLocked(); 2192 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 2193 AccessibilityServiceConnection service = state.mBoundServices.get(i); 2194 if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) { 2195 service.notifyGesture(gestureEvent); 2196 return true; 2197 } 2198 } 2199 return false; 2200 } 2201 scheduleNotifyMotionEvent(MotionEvent event)2202 private boolean scheduleNotifyMotionEvent(MotionEvent event) { 2203 boolean result = false; 2204 int displayId = event.getDisplayId(); 2205 synchronized (mLock) { 2206 AccessibilityUserState state = getCurrentUserStateLocked(); 2207 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 2208 AccessibilityServiceConnection service = state.mBoundServices.get(i); 2209 if (service.wantsGenericMotionEvent(event) 2210 || (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN) 2211 && service.isServiceDetectsGesturesEnabled(displayId))) { 2212 service.notifyMotionEvent(event); 2213 result = true; 2214 } 2215 } 2216 } 2217 return result; 2218 } 2219 scheduleNotifyTouchState(int displayId, int touchState)2220 private boolean scheduleNotifyTouchState(int displayId, int touchState) { 2221 boolean result = false; 2222 synchronized (mLock) { 2223 AccessibilityUserState state = getCurrentUserStateLocked(); 2224 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 2225 AccessibilityServiceConnection service = state.mBoundServices.get(i); 2226 if (service.isServiceDetectsGesturesEnabled(displayId)) { 2227 service.notifyTouchState(displayId, touchState); 2228 result = true; 2229 } 2230 } 2231 } 2232 return result; 2233 } 2234 2235 @Override notifyClearAccessibilityCacheLocked()2236 public void notifyClearAccessibilityCacheLocked() { 2237 AccessibilityUserState state = getCurrentUserStateLocked(); 2238 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 2239 AccessibilityServiceConnection service = state.mBoundServices.get(i); 2240 service.notifyClearAccessibilityNodeInfoCache(); 2241 } 2242 2243 mProxyManager.clearCacheLocked(); 2244 } 2245 notifyMagnificationChangedLocked(int displayId, @NonNull Region region, @NonNull MagnificationConfig config)2246 private void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, 2247 @NonNull MagnificationConfig config) { 2248 final AccessibilityUserState state = getCurrentUserStateLocked(); 2249 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 2250 final AccessibilityServiceConnection service = state.mBoundServices.get(i); 2251 service.notifyMagnificationChangedLocked(displayId, region, config); 2252 } 2253 } 2254 sendAccessibilityButtonToInputFilter(int displayId)2255 private void sendAccessibilityButtonToInputFilter(int displayId) { 2256 synchronized (mLock) { 2257 if (mHasInputFilter && mInputFilter != null) { 2258 mInputFilter.notifyAccessibilityButtonClicked(displayId); 2259 } 2260 } 2261 } 2262 showAccessibilityTargetsSelection(int displayId, @UserShortcutType int shortcutType)2263 private void showAccessibilityTargetsSelection(int displayId, 2264 @UserShortcutType int shortcutType) { 2265 final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); 2266 final String chooserClassName = (shortcutType == UserShortcutType.HARDWARE) 2267 ? AccessibilityShortcutChooserActivity.class.getName() 2268 : AccessibilityButtonChooserActivity.class.getName(); 2269 intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); 2270 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 2271 final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); 2272 mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); 2273 } 2274 launchShortcutTargetActivity(int displayId, ComponentName name)2275 private void launchShortcutTargetActivity(int displayId, ComponentName name) { 2276 final Intent intent = new Intent(); 2277 final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); 2278 intent.setComponent(name); 2279 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2280 try { 2281 mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); 2282 } catch (ActivityNotFoundException ignore) { 2283 // ignore the exception 2284 } 2285 } 2286 launchAccessibilitySubSettings(int displayId, ComponentName name)2287 private void launchAccessibilitySubSettings(int displayId, ComponentName name) { 2288 final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS); 2289 final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(); 2290 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2291 intent.putExtra(Intent.EXTRA_COMPONENT_NAME, name.flattenToString()); 2292 try { 2293 mContext.startActivityAsUser(intent, bundle, UserHandle.of(mCurrentUserId)); 2294 } catch (ActivityNotFoundException ignore) { 2295 // ignore the exception 2296 } 2297 } 2298 launchHearingDevicesDialog()2299 private void launchHearingDevicesDialog() { 2300 final Intent intent = new Intent(ACTION_LAUNCH_HEARING_DEVICES_DIALOG); 2301 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 2302 intent.setPackage( 2303 mContext.getString(com.android.internal.R.string.config_systemUi)); 2304 mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM); 2305 } 2306 notifyAccessibilityButtonVisibilityChangedLocked(boolean available)2307 private void notifyAccessibilityButtonVisibilityChangedLocked(boolean available) { 2308 final AccessibilityUserState state = getCurrentUserStateLocked(); 2309 mIsAccessibilityButtonShown = available; 2310 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 2311 final AccessibilityServiceConnection clientConnection = state.mBoundServices.get(i); 2312 if (clientConnection.mRequestAccessibilityButton) { 2313 clientConnection.notifyAccessibilityButtonAvailabilityChangedLocked( 2314 clientConnection.isAccessibilityButtonAvailableLocked(state)); 2315 } 2316 } 2317 } 2318 2319 /** 2320 * Finds packages that provide AccessibilityService interfaces, and parses 2321 * their metadata XML to build up {@link AccessibilityServiceInfo} objects. 2322 * 2323 * <p> 2324 * <strong>Note:</strong> XML parsing is a resource-heavy operation that may 2325 * stall, so this method should not be called while holding a lock. 2326 * </p> 2327 */ parseAccessibilityServiceInfos(int userId)2328 private List<AccessibilityServiceInfo> parseAccessibilityServiceInfos(int userId) { 2329 List<AccessibilityServiceInfo> result = new ArrayList<>(); 2330 2331 int flags = PackageManager.GET_SERVICES 2332 | PackageManager.GET_META_DATA 2333 | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS 2334 | PackageManager.MATCH_DIRECT_BOOT_AWARE 2335 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 2336 2337 synchronized (mLock) { 2338 if (getUserStateLocked(userId).getBindInstantServiceAllowedLocked()) { 2339 flags |= PackageManager.MATCH_INSTANT; 2340 } 2341 } 2342 2343 List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( 2344 new Intent(AccessibilityService.SERVICE_INTERFACE), flags, userId); 2345 2346 for (int i = 0, count = installedServices.size(); i < count; i++) { 2347 ResolveInfo resolveInfo = installedServices.get(i); 2348 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 2349 2350 if (!mSecurityPolicy.canRegisterService(serviceInfo)) { 2351 continue; 2352 } 2353 2354 AccessibilityServiceInfo accessibilityServiceInfo; 2355 try { 2356 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); 2357 } catch (XmlPullParserException | IOException xppe) { 2358 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); 2359 continue; 2360 } 2361 if (!accessibilityServiceInfo.isWithinParcelableSize()) { 2362 Slog.e(LOG_TAG, "Skipping service " 2363 + accessibilityServiceInfo.getResolveInfo().getComponentInfo() 2364 + " because service info size is larger than safe parcelable limits."); 2365 continue; 2366 } 2367 result.add(accessibilityServiceInfo); 2368 } 2369 return result; 2370 } 2371 readInstalledAccessibilityServiceLocked(AccessibilityUserState userState, @Nullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos)2372 private boolean readInstalledAccessibilityServiceLocked(AccessibilityUserState userState, 2373 @Nullable List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos) { 2374 for (int i = 0, count = parsedAccessibilityServiceInfos.size(); i < count; i++) { 2375 AccessibilityServiceInfo accessibilityServiceInfo = 2376 parsedAccessibilityServiceInfos.get(i); 2377 if (userState.mCrashedServices.contains(accessibilityServiceInfo.getComponentName())) { 2378 // Restore the crashed attribute. 2379 accessibilityServiceInfo.crashed = true; 2380 } 2381 } 2382 2383 if (!parsedAccessibilityServiceInfos.equals(userState.mInstalledServices)) { 2384 userState.mInstalledServices.clear(); 2385 userState.mInstalledServices.addAll(parsedAccessibilityServiceInfos); 2386 userState.updateTileServiceMapForAccessibilityServiceLocked(); 2387 return true; 2388 } 2389 return false; 2390 } 2391 2392 /** 2393 * Returns the {@link AccessibilityShortcutInfo}s of the installed 2394 * accessibility shortcut targets for the given user. 2395 * 2396 * <p> 2397 * <strong>Note:</strong> XML parsing is a resource-heavy operation that may 2398 * stall, so this method should not be called while holding a lock. 2399 * </p> 2400 */ parseAccessibilityShortcutInfos(int userId)2401 private List<AccessibilityShortcutInfo> parseAccessibilityShortcutInfos(int userId) { 2402 // TODO: b/297279151 - This should be implemented here, not by AccessibilityManager. 2403 return AccessibilityManager.getInstance(mContext) 2404 .getInstalledAccessibilityShortcutListAsUser(mContext, userId); 2405 } 2406 readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState, List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos)2407 private boolean readInstalledAccessibilityShortcutLocked(AccessibilityUserState userState, 2408 List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) { 2409 if (!parsedAccessibilityShortcutInfos.equals(userState.mInstalledShortcuts)) { 2410 userState.mInstalledShortcuts.clear(); 2411 userState.mInstalledShortcuts.addAll(parsedAccessibilityShortcutInfos); 2412 userState.updateTileServiceMapForAccessibilityActivityLocked(); 2413 return true; 2414 } 2415 return false; 2416 } 2417 readEnabledAccessibilityServicesLocked(AccessibilityUserState userState)2418 private boolean readEnabledAccessibilityServicesLocked(AccessibilityUserState userState) { 2419 mTempComponentNameSet.clear(); 2420 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 2421 userState.mUserId, mTempComponentNameSet); 2422 if (!mTempComponentNameSet.equals(userState.mEnabledServices)) { 2423 userState.mEnabledServices.clear(); 2424 userState.mEnabledServices.addAll(mTempComponentNameSet); 2425 mTempComponentNameSet.clear(); 2426 return true; 2427 } 2428 mTempComponentNameSet.clear(); 2429 return false; 2430 } 2431 readTouchExplorationGrantedAccessibilityServicesLocked( AccessibilityUserState userState)2432 private boolean readTouchExplorationGrantedAccessibilityServicesLocked( 2433 AccessibilityUserState userState) { 2434 mTempComponentNameSet.clear(); 2435 readComponentNamesFromSettingLocked( 2436 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 2437 userState.mUserId, mTempComponentNameSet); 2438 if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) { 2439 userState.mTouchExplorationGrantedServices.clear(); 2440 userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet); 2441 mTempComponentNameSet.clear(); 2442 return true; 2443 } 2444 mTempComponentNameSet.clear(); 2445 return false; 2446 } 2447 2448 /** 2449 * Performs {@link AccessibilityService}s delayed notification. The delay is configurable 2450 * and denotes the period after the last event before notifying the service. 2451 * 2452 * @param event The event. 2453 * @param isDefault True to notify default listeners, not default services. 2454 */ notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)2455 private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, 2456 boolean isDefault) { 2457 try { 2458 AccessibilityUserState state = getCurrentUserStateLocked(); 2459 for (int i = 0, count = state.mBoundServices.size(); i < count; i++) { 2460 AccessibilityServiceConnection service = state.mBoundServices.get(i); 2461 2462 if (service.mIsDefault == isDefault) { 2463 service.notifyAccessibilityEvent(event); 2464 } 2465 } 2466 } catch (IndexOutOfBoundsException oobe) { 2467 // An out of bounds exception can happen if services are going away 2468 // as the for loop is running. If that happens, just bail because 2469 // there are no more services to notify. 2470 } 2471 } 2472 updateRelevantEventsLocked(AccessibilityUserState userState)2473 private void updateRelevantEventsLocked(AccessibilityUserState userState) { 2474 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 2475 mTraceManager.logTrace(LOG_TAG + ".updateRelevantEventsLocked", 2476 FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState); 2477 } 2478 mMainHandler.post(() -> { 2479 broadcastToClients(userState, ignoreRemoteException(client -> { 2480 int relevantEventTypes; 2481 synchronized (mLock) { 2482 relevantEventTypes = computeRelevantEventTypesLocked(userState, client); 2483 if (!mProxyManager.isProxyedDeviceId(client.mDeviceId)) { 2484 if (client.mLastSentRelevantEventTypes != relevantEventTypes) { 2485 client.mLastSentRelevantEventTypes = relevantEventTypes; 2486 client.mCallback.setRelevantEventTypes(relevantEventTypes); 2487 } 2488 } 2489 } 2490 })); 2491 }); 2492 } 2493 computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client)2494 private int computeRelevantEventTypesLocked(AccessibilityUserState userState, Client client) { 2495 int relevantEventTypes = 0; 2496 2497 int serviceCount = userState.mBoundServices.size(); 2498 for (int i = 0; i < serviceCount; i++) { 2499 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 2500 relevantEventTypes |= isClientInPackageAllowlist(service.getServiceInfo(), client) 2501 ? service.getRelevantEventTypes() 2502 : 0; 2503 } 2504 2505 relevantEventTypes |= isClientInPackageAllowlist( 2506 mUiAutomationManager.getServiceInfo(), client) 2507 ? mUiAutomationManager.getRelevantEventTypes() 2508 : 0; 2509 return relevantEventTypes; 2510 } 2511 updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState, int displayId)2512 private void updateMagnificationModeChangeSettingsLocked(AccessibilityUserState userState, 2513 int displayId) { 2514 if (userState.mUserId != mCurrentUserId) { 2515 return; 2516 } 2517 // New mode is invalid, so ignore and restore it. 2518 if (fallBackMagnificationModeSettingsLocked(userState, displayId)) { 2519 return; 2520 } 2521 mMagnificationController.transitionMagnificationModeLocked( 2522 displayId, userState.getMagnificationModeLocked(displayId), 2523 this::onMagnificationTransitionEndedLocked); 2524 } 2525 2526 /** 2527 * Called when the magnification mode transition is completed. If the given display is default 2528 * display, we also need to fall back the mode in user settings. 2529 */ onMagnificationTransitionEndedLocked(int displayId, boolean success)2530 void onMagnificationTransitionEndedLocked(int displayId, boolean success) { 2531 final AccessibilityUserState userState = getCurrentUserStateLocked(); 2532 final int previousMode = userState.getMagnificationModeLocked(displayId) 2533 ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL; 2534 if (!success && previousMode != 0) { 2535 userState.setMagnificationModeLocked(displayId, previousMode); 2536 if (displayId == Display.DEFAULT_DISPLAY) { 2537 persistMagnificationModeSettingsLocked(previousMode); 2538 } 2539 } else { 2540 mMainHandler.sendMessage(obtainMessage( 2541 AccessibilityManagerService::notifyRefreshMagnificationModeToInputFilter, 2542 this, displayId)); 2543 } 2544 } 2545 notifyRefreshMagnificationModeToInputFilter(int displayId)2546 private void notifyRefreshMagnificationModeToInputFilter(int displayId) { 2547 synchronized (mLock) { 2548 if (!mHasInputFilter) { 2549 return; 2550 } 2551 final ArrayList<Display> displays = getValidDisplayList(); 2552 for (int i = 0; i < displays.size(); i++) { 2553 final Display display = displays.get(i); 2554 if (display != null && display.getDisplayId() == displayId) { 2555 mInputFilter.refreshMagnificationMode(display); 2556 return; 2557 } 2558 } 2559 } 2560 } 2561 isClientInPackageAllowlist( @ullable AccessibilityServiceInfo serviceInfo, Client client)2562 static boolean isClientInPackageAllowlist( 2563 @Nullable AccessibilityServiceInfo serviceInfo, Client client) { 2564 if (serviceInfo == null) return false; 2565 2566 String[] clientPackages = client.mPackageNames; 2567 boolean result = ArrayUtils.isEmpty(serviceInfo.packageNames); 2568 if (!result && clientPackages != null) { 2569 for (String packageName : clientPackages) { 2570 if (ArrayUtils.contains(serviceInfo.packageNames, packageName)) { 2571 result = true; 2572 break; 2573 } 2574 } 2575 } 2576 if (!result) { 2577 if (DEBUG) { 2578 Slog.d(LOG_TAG, "Dropping events: " 2579 + Arrays.toString(clientPackages) + " -> " 2580 + serviceInfo.getComponentName().flattenToShortString() 2581 + " due to not being in package allowlist " 2582 + Arrays.toString(serviceInfo.packageNames)); 2583 } 2584 } 2585 2586 return result; 2587 } 2588 broadcastToClients( AccessibilityUserState userState, Consumer<Client> clientAction)2589 private void broadcastToClients( 2590 AccessibilityUserState userState, Consumer<Client> clientAction) { 2591 mGlobalClients.broadcastForEachCookie(clientAction); 2592 userState.mUserClients.broadcastForEachCookie(clientAction); 2593 } 2594 2595 /** 2596 * Populates a set with the {@link ComponentName}s stored in a colon 2597 * separated value setting for a given user. 2598 * 2599 * @param settingName The setting to parse. 2600 * @param userId The user id. 2601 * @param outComponentNames The output component names. 2602 */ 2603 @VisibleForTesting readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)2604 void readComponentNamesFromSettingLocked(String settingName, int userId, 2605 Set<ComponentName> outComponentNames) { 2606 readColonDelimitedSettingToSet(settingName, userId, 2607 str -> ComponentName.unflattenFromString(str), outComponentNames); 2608 } 2609 2610 /** 2611 * Populates a set with the {@link ComponentName}s contained in a colon-delimited string. 2612 * 2613 * @param names The colon-delimited string to parse. 2614 * @param outComponentNames The set of component names to be populated based on 2615 * the contents of the <code>names</code> string. 2616 * @param doMerge If true, the parsed component names will be merged into the output 2617 * set, rather than replacing the set's existing contents entirely. 2618 */ readComponentNamesFromStringLocked(String names, Set<ComponentName> outComponentNames, boolean doMerge)2619 private void readComponentNamesFromStringLocked(String names, 2620 Set<ComponentName> outComponentNames, 2621 boolean doMerge) { 2622 readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str), 2623 outComponentNames, doMerge); 2624 } 2625 2626 @Override persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)2627 public void persistComponentNamesToSettingLocked(String settingName, 2628 Set<ComponentName> componentNames, int userId) { 2629 persistColonDelimitedSetToSettingLocked(settingName, userId, componentNames, 2630 componentName -> componentName.flattenToShortString()); 2631 } 2632 2633 /** 2634 * Reads a colon delimited setting, 2635 * passes the values through a function, 2636 * then stores the values in a provided set. 2637 * 2638 * @param settingName Name of setting. 2639 * @param userId user id corresponding to setting. 2640 * @param toItem function mapping values to the output set. 2641 * @param outSet output set to write to. 2642 * @param <T> type of output set. 2643 */ 2644 @VisibleForTesting readColonDelimitedSettingToSet(String settingName, int userId, Function<String, T> toItem, Set<T> outSet)2645 <T> void readColonDelimitedSettingToSet(String settingName, int userId, 2646 Function<String, T> toItem, Set<T> outSet) { 2647 final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 2648 settingName, userId); 2649 readColonDelimitedStringToSet(settingValue, toItem, outSet, false); 2650 } 2651 readColonDelimitedStringToSet(String names, Function<String, T> toItem, Set<T> outSet, boolean doMerge)2652 private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem, 2653 Set<T> outSet, boolean doMerge) { 2654 if (!doMerge) { 2655 outSet.clear(); 2656 } 2657 if (!TextUtils.isEmpty(names)) { 2658 final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; 2659 splitter.setString(names); 2660 while (splitter.hasNext()) { 2661 final String str = splitter.next(); 2662 if (TextUtils.isEmpty(str)) { 2663 continue; 2664 } 2665 final T item = toItem.apply(str); 2666 if (item != null) { 2667 outSet.add(item); 2668 } 2669 } 2670 } 2671 } 2672 persistColonDelimitedSetToSettingLocked(String settingName, int userId, Set<T> set, Function<T, String> toString)2673 private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId, 2674 Set<T> set, Function<T, String> toString) { 2675 persistColonDelimitedSetToSettingLocked(settingName, userId, set, 2676 toString, /* defaultEmptyString= */ null); 2677 } 2678 persistColonDelimitedSetToSettingLocked(String settingName, int userId, Set<T> set, Function<T, String> toString, String defaultEmptyString)2679 private <T> void persistColonDelimitedSetToSettingLocked(String settingName, int userId, 2680 Set<T> set, Function<T, String> toString, String defaultEmptyString) { 2681 final StringBuilder builder = new StringBuilder(); 2682 for (T item : set) { 2683 final String str = (item != null ? toString.apply(item) : null); 2684 if (TextUtils.isEmpty(str)) { 2685 continue; 2686 } 2687 if (builder.length() > 0) { 2688 builder.append(COMPONENT_NAME_SEPARATOR); 2689 } 2690 builder.append(str); 2691 } 2692 final String builderValue = builder.toString(); 2693 final String settingValue = TextUtils.isEmpty(builderValue) 2694 ? defaultEmptyString : builderValue; 2695 if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()) { 2696 final String currentValue = Settings.Secure.getStringForUser( 2697 mContext.getContentResolver(), settingName, userId); 2698 if (Objects.equals(settingValue, currentValue)) { 2699 // This logic exists to fix a bug where AccessibilityManagerService was writing 2700 // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot 2701 // during setup, due to a race condition in package scanning making A11yMS think 2702 // that the default service was not installed. 2703 // 2704 // Writing `null` was implicitly causing that Setting to have the default 2705 // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that 2706 // Setting altogether. 2707 // 2708 // The "quick fix" here is to not write `null` if the existing value is already 2709 // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload 2710 // that allows override-by-restore, but the full repercussions of using that here 2711 // have not yet been evaluated. 2712 // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of 2713 // "overridable by restore" when writing secure settings. 2714 return; 2715 } 2716 } 2717 final long identity = Binder.clearCallingIdentity(); 2718 try { 2719 Settings.Secure.putStringForUser(mContext.getContentResolver(), 2720 settingName, settingValue, userId); 2721 } finally { 2722 Binder.restoreCallingIdentity(identity); 2723 } 2724 } 2725 persistIntToSetting(int userId, String settingName, int settingValue)2726 private void persistIntToSetting(int userId, String settingName, int settingValue) { 2727 final long identity = Binder.clearCallingIdentity(); 2728 try { 2729 Settings.Secure.putIntForUser( 2730 mContext.getContentResolver(), settingName, settingValue, userId); 2731 } finally { 2732 Binder.restoreCallingIdentity(identity); 2733 } 2734 } 2735 updateServicesLocked(AccessibilityUserState userState)2736 private void updateServicesLocked(AccessibilityUserState userState) { 2737 Map<ComponentName, AccessibilityServiceConnection> componentNameToServiceMap = 2738 userState.mComponentNameToServiceMap; 2739 boolean isUnlockingOrUnlocked = mUmi.isUserUnlockingOrUnlocked(userState.mUserId); 2740 2741 // Store the list of installed services. 2742 mTempComponentNameSet.clear(); 2743 for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { 2744 AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); 2745 ComponentName componentName = ComponentName.unflattenFromString( 2746 installedService.getId()); 2747 mTempComponentNameSet.add(componentName); 2748 2749 AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName); 2750 2751 // Ignore non-encryption-aware services until user is unlocked 2752 if (!isUnlockingOrUnlocked && !installedService.isDirectBootAware()) { 2753 Slog.d(LOG_TAG, "Ignoring non-encryption-aware service " + componentName); 2754 continue; 2755 } 2756 2757 // Skip the component since it may be in process or crashed. 2758 if (userState.getBindingServicesLocked().contains(componentName) 2759 || userState.getCrashedServicesLocked().contains(componentName)) { 2760 continue; 2761 } 2762 if (userState.mEnabledServices.contains(componentName) 2763 && !mUiAutomationManager.suppressingAccessibilityServicesLocked()) { 2764 // Skip the enabling service disallowed by device admin policy. 2765 if (!isAccessibilityTargetAllowed(componentName.getPackageName(), 2766 installedService.getResolveInfo().serviceInfo.applicationInfo.uid, 2767 userState.mUserId)) { 2768 Slog.d(LOG_TAG, "Skipping enabling service disallowed by device admin policy: " 2769 + componentName); 2770 disableAccessibilityServiceLocked(componentName, userState.mUserId); 2771 continue; 2772 } 2773 if (service == null) { 2774 service = new AccessibilityServiceConnection(userState, mContext, componentName, 2775 installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, 2776 this, getTraceManager(), mWindowManagerService, 2777 getSystemActionPerformer(), mA11yWindowManager, 2778 mActivityTaskManagerService); 2779 } else if (userState.mBoundServices.contains(service)) { 2780 continue; 2781 } 2782 service.bindLocked(); 2783 } else { 2784 if (service != null) { 2785 service.unbindLocked(); 2786 removeShortcutTargetForUnboundServiceLocked(userState, service); 2787 } 2788 } 2789 } 2790 2791 final int count = userState.mBoundServices.size(); 2792 mTempIntArray.clear(); 2793 for (int i = 0; i < count; i++) { 2794 final ResolveInfo resolveInfo = 2795 userState.mBoundServices.get(i).mAccessibilityServiceInfo.getResolveInfo(); 2796 if (resolveInfo != null) { 2797 mTempIntArray.add(resolveInfo.serviceInfo.applicationInfo.uid); 2798 } 2799 } 2800 // Calling out with lock held, but to lower-level services 2801 final AudioManagerInternal audioManager = 2802 LocalServices.getService(AudioManagerInternal.class); 2803 if (audioManager != null) { 2804 audioManager.setAccessibilityServiceUids(mTempIntArray); 2805 } 2806 mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray); 2807 2808 // If any services have been removed, remove them from the enabled list and the touch 2809 // exploration granted list. 2810 boolean anyServiceRemoved = 2811 userState.mEnabledServices.removeIf((comp) -> !mTempComponentNameSet.contains(comp)) 2812 || userState.mTouchExplorationGrantedServices.removeIf( 2813 (comp) -> !mTempComponentNameSet.contains(comp)); 2814 if (anyServiceRemoved) { 2815 // Update the enabled services setting. 2816 persistComponentNamesToSettingLocked( 2817 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 2818 userState.mEnabledServices, 2819 userState.mUserId); 2820 // Update the touch exploration granted services setting. 2821 persistComponentNamesToSettingLocked( 2822 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 2823 userState.mTouchExplorationGrantedServices, 2824 userState.mUserId); 2825 } 2826 updateAccessibilityEnabledSettingLocked(userState); 2827 } 2828 scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState)2829 void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) { 2830 scheduleUpdateClientsIfNeededLocked(userState, false); 2831 } 2832 scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState, boolean forceUpdate)2833 void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState, 2834 boolean forceUpdate) { 2835 final int clientState = getClientStateLocked(userState); 2836 if (((userState.getLastSentClientStateLocked() != clientState || forceUpdate)) 2837 && (mGlobalClients.getRegisteredCallbackCount() > 0 2838 || userState.mUserClients.getRegisteredCallbackCount() > 0)) { 2839 userState.setLastSentClientStateLocked(clientState); 2840 mMainHandler.sendMessage(obtainMessage( 2841 AccessibilityManagerService::sendStateToAllClients, 2842 this, clientState, 2843 userState.mUserId)); 2844 } 2845 } 2846 sendStateToAllClients(int clientState, int userId)2847 private void sendStateToAllClients(int clientState, int userId) { 2848 sendStateToClients(clientState, mGlobalClients); 2849 sendStateToClients(clientState, userId); 2850 } 2851 sendStateToClients(int clientState, int userId)2852 private void sendStateToClients(int clientState, int userId) { 2853 sendStateToClients(clientState, getUserState(userId).mUserClients); 2854 } 2855 sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)2856 private void sendStateToClients(int clientState, 2857 RemoteCallbackList<IAccessibilityManagerClient> clients) { 2858 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) { 2859 mTraceManager.logTrace(LOG_TAG + ".sendStateToClients", 2860 FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "clientState=" + clientState); 2861 } 2862 clients.broadcastForEachCookie(ignoreRemoteException( 2863 client -> { 2864 Client managerClient = ((Client) client); 2865 if (!mProxyManager.isProxyedDeviceId(managerClient.mDeviceId)) { 2866 managerClient.mCallback.setState(clientState); 2867 } 2868 })); 2869 } 2870 scheduleNotifyClientsOfServicesStateChangeLocked( AccessibilityUserState userState)2871 private void scheduleNotifyClientsOfServicesStateChangeLocked( 2872 AccessibilityUserState userState) { 2873 updateRecommendedUiTimeoutLocked(userState); 2874 mMainHandler.sendMessage(obtainMessage( 2875 AccessibilityManagerService::sendServicesStateChanged, 2876 this, userState.mUserClients, getRecommendedTimeoutMillisLocked(userState))); 2877 } 2878 sendServicesStateChanged( RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout)2879 private void sendServicesStateChanged( 2880 RemoteCallbackList<IAccessibilityManagerClient> userClients, long uiTimeout) { 2881 notifyClientsOfServicesStateChange(mGlobalClients, uiTimeout); 2882 notifyClientsOfServicesStateChange(userClients, uiTimeout); 2883 } 2884 notifyClientsOfServicesStateChange( RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout)2885 private void notifyClientsOfServicesStateChange( 2886 RemoteCallbackList<IAccessibilityManagerClient> clients, long uiTimeout) { 2887 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER_CLIENT)) { 2888 mTraceManager.logTrace(LOG_TAG + ".notifyClientsOfServicesStateChange", 2889 FLAGS_ACCESSIBILITY_MANAGER_CLIENT, "uiTimeout=" + uiTimeout); 2890 } 2891 2892 clients.broadcastForEachCookie(ignoreRemoteException( 2893 client -> { 2894 Client managerClient = ((Client) client); 2895 if (!mProxyManager.isProxyedDeviceId(managerClient.mDeviceId)) { 2896 managerClient.mCallback.notifyServicesStateChanged(uiTimeout); 2897 } 2898 })); 2899 } 2900 scheduleUpdateInputFilter(AccessibilityUserState userState)2901 private void scheduleUpdateInputFilter(AccessibilityUserState userState) { 2902 mMainHandler.sendMessage(obtainMessage( 2903 AccessibilityManagerService::updateInputFilter, this, userState)); 2904 } 2905 scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState)2906 private void scheduleUpdateFingerprintGestureHandling(AccessibilityUserState userState) { 2907 mMainHandler.sendMessage(obtainMessage( 2908 AccessibilityManagerService::updateFingerprintGestureHandling, 2909 this, userState)); 2910 } 2911 updateInputFilter(AccessibilityUserState userState)2912 private void updateInputFilter(AccessibilityUserState userState) { 2913 if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return; 2914 2915 boolean setInputFilter = false; 2916 AccessibilityInputFilter inputFilter = null; 2917 synchronized (mLock) { 2918 int flags = 0; 2919 if (userState.isMagnificationSingleFingerTripleTapEnabledLocked()) { 2920 flags |= AccessibilityInputFilter 2921 .FLAG_FEATURE_MAGNIFICATION_SINGLE_FINGER_TRIPLE_TAP; 2922 } 2923 if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { 2924 if (userState.isMagnificationTwoFingerTripleTapEnabledLocked()) { 2925 flags |= AccessibilityInputFilter 2926 .FLAG_FEATURE_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP; 2927 } 2928 } 2929 if (userState.isShortcutMagnificationEnabledLocked()) { 2930 flags |= AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER; 2931 } 2932 if (userHasMagnificationServicesLocked(userState)) { 2933 flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER; 2934 } 2935 // Touch exploration without accessibility makes no sense. 2936 if (userState.isHandlingAccessibilityEventsLocked() 2937 && userState.isTouchExplorationEnabledLocked()) { 2938 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; 2939 if (userState.isServiceHandlesDoubleTapEnabledLocked()) { 2940 flags |= AccessibilityInputFilter.FLAG_SERVICE_HANDLES_DOUBLE_TAP; 2941 } 2942 if (userState.isMultiFingerGesturesEnabledLocked()) { 2943 flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES; 2944 } 2945 if (userState.isTwoFingerPassthroughEnabledLocked()) { 2946 flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH; 2947 } 2948 } 2949 if (userState.isFilterKeyEventsEnabledLocked()) { 2950 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; 2951 } 2952 if (userState.isSendMotionEventsEnabled()) { 2953 flags |= AccessibilityInputFilter.FLAG_SEND_MOTION_EVENTS; 2954 } 2955 if (userState.isAutoclickEnabledLocked()) { 2956 flags |= AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK; 2957 } 2958 if (userState.isPerformGesturesEnabledLocked()) { 2959 flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS; 2960 } 2961 int combinedGenericMotionEventSources = 0; 2962 int combinedMotionEventObservedSources = 0; 2963 for (AccessibilityServiceConnection connection : userState.mBoundServices) { 2964 combinedGenericMotionEventSources |= connection.mGenericMotionEventSources; 2965 combinedMotionEventObservedSources |= connection.mObservedMotionEventSources; 2966 } 2967 if (combinedGenericMotionEventSources != 0) { 2968 flags |= AccessibilityInputFilter.FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS; 2969 } 2970 if (flags != 0) { 2971 if (!mHasInputFilter) { 2972 mHasInputFilter = true; 2973 if (mInputFilter == null) { 2974 mInputFilter = 2975 new AccessibilityInputFilter( 2976 mContext, AccessibilityManagerService.this); 2977 } 2978 inputFilter = mInputFilter; 2979 setInputFilter = true; 2980 } 2981 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags); 2982 mInputFilter.setCombinedGenericMotionEventSources( 2983 combinedGenericMotionEventSources); 2984 mInputFilter.setCombinedMotionEventObservedSources( 2985 combinedMotionEventObservedSources); 2986 } else { 2987 if (mHasInputFilter) { 2988 mHasInputFilter = false; 2989 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0); 2990 mInputFilter.resetServiceDetectsGestures(); 2991 if (userState.isTouchExplorationEnabledLocked()) { 2992 // Service gesture detection is turned on and off on a per-display 2993 // basis. 2994 final ArrayList<Display> displays = getValidDisplayList(); 2995 for (Display display : displays) { 2996 int displayId = display.getDisplayId(); 2997 boolean mode = userState.isServiceDetectsGesturesEnabled(displayId); 2998 mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode); 2999 } 3000 } 3001 inputFilter = null; 3002 setInputFilter = true; 3003 } 3004 } 3005 } 3006 if (setInputFilter) { 3007 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL 3008 | FLAGS_INPUT_FILTER)) { 3009 mTraceManager.logTrace("WindowManagerInternal.setInputFilter", 3010 FLAGS_WINDOW_MANAGER_INTERNAL | FLAGS_INPUT_FILTER, 3011 "inputFilter=" + inputFilter); 3012 } 3013 mWindowManagerService.setInputFilter(inputFilter); 3014 mProxyManager.setAccessibilityInputFilter(inputFilter); 3015 } 3016 } 3017 showEnableTouchExplorationDialog(final AccessibilityServiceConnection service)3018 private void showEnableTouchExplorationDialog(final AccessibilityServiceConnection service) { 3019 synchronized (mLock) { 3020 String label = service.getServiceInfo().getResolveInfo() 3021 .loadLabel(mContext.getPackageManager()).toString(); 3022 3023 final AccessibilityUserState userState = getCurrentUserStateLocked(); 3024 if (userState.isTouchExplorationEnabledLocked()) { 3025 return; 3026 } 3027 if (mEnableTouchExplorationDialog != null 3028 && mEnableTouchExplorationDialog.isShowing()) { 3029 return; 3030 } 3031 mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) 3032 .setIconAttribute(android.R.attr.alertDialogIcon) 3033 .setPositiveButton(android.R.string.ok, new OnClickListener() { 3034 @Override 3035 public void onClick(DialogInterface dialog, int which) { 3036 // The user allowed the service to toggle touch exploration. 3037 userState.mTouchExplorationGrantedServices.add(service.mComponentName); 3038 persistComponentNamesToSettingLocked( 3039 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 3040 userState.mTouchExplorationGrantedServices, userState.mUserId); 3041 // Enable touch exploration. 3042 userState.setTouchExplorationEnabledLocked(true); 3043 final long identity = Binder.clearCallingIdentity(); 3044 try { 3045 Settings.Secure.putIntForUser(mContext.getContentResolver(), 3046 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, 3047 userState.mUserId); 3048 } finally { 3049 Binder.restoreCallingIdentity(identity); 3050 } 3051 onUserStateChangedLocked(userState); 3052 } 3053 }) 3054 .setNegativeButton(android.R.string.cancel, new OnClickListener() { 3055 @Override 3056 public void onClick(DialogInterface dialog, int which) { 3057 dialog.dismiss(); 3058 } 3059 }) 3060 .setTitle(R.string.enable_explore_by_touch_warning_title) 3061 .setMessage(mContext.getString( 3062 R.string.enable_explore_by_touch_warning_message, label)) 3063 .create(); 3064 mEnableTouchExplorationDialog.getWindow().setType( 3065 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 3066 mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags 3067 |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; 3068 mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); 3069 mEnableTouchExplorationDialog.show(); 3070 } 3071 } 3072 onUserVisibilityChanged(@serIdInt int userId, boolean visible)3073 private void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) { 3074 if (DEBUG) { 3075 Slogf.d(LOG_TAG, "onUserVisibilityChanged(): %d => %b", userId, visible); 3076 } 3077 synchronized (mLock) { 3078 if (visible) { 3079 mVisibleBgUserIds.put(userId, visible); 3080 } else { 3081 mVisibleBgUserIds.delete(userId); 3082 } 3083 } 3084 } 3085 3086 /** 3087 * Called when any property of the user state has changed. 3088 * 3089 * @param userState the new user state 3090 */ onUserStateChangedLocked(AccessibilityUserState userState)3091 private void onUserStateChangedLocked(AccessibilityUserState userState) { 3092 onUserStateChangedLocked(userState, false); 3093 } 3094 3095 /** 3096 * Called when any property of the user state has changed. 3097 * 3098 * @param userState the new user state 3099 * @param forceUpdate whether to force an update of the app Clients. 3100 */ onUserStateChangedLocked(AccessibilityUserState userState, boolean forceUpdate)3101 private void onUserStateChangedLocked(AccessibilityUserState userState, boolean forceUpdate) { 3102 if (DEBUG) { 3103 Slog.v(LOG_TAG, "onUserStateChangedLocked for user " + userState.mUserId + " with " 3104 + "forceUpdate: " + forceUpdate); 3105 } 3106 // TODO: Remove this hack 3107 mInitialized = true; 3108 updateLegacyCapabilitiesLocked(userState); 3109 updateServicesLocked(userState); 3110 updateWindowsForAccessibilityCallbackLocked(userState); 3111 updateFilterKeyEventsLocked(userState); 3112 updateTouchExplorationLocked(userState); 3113 updatePerformGesturesLocked(userState); 3114 updateMagnificationLocked(userState); 3115 scheduleUpdateFingerprintGestureHandling(userState); 3116 scheduleUpdateInputFilter(userState); 3117 updateRelevantEventsLocked(userState); 3118 scheduleUpdateClientsIfNeededLocked(userState, forceUpdate); 3119 updateAccessibilityShortcutKeyTargetsLocked(userState); 3120 updateAccessibilityButtonTargetsLocked(userState); 3121 updateAccessibilityQsTargetsLocked(userState); 3122 // Update the capabilities before the mode because we will check the current mode is 3123 // invalid or not.. 3124 updateMagnificationCapabilitiesSettingsChangeLocked(userState); 3125 updateMagnificationModeChangeSettingsForAllDisplaysLocked(userState); 3126 updateFocusAppearanceDataLocked(userState); 3127 } 3128 updateMagnificationModeChangeSettingsForAllDisplaysLocked( AccessibilityUserState userState)3129 private void updateMagnificationModeChangeSettingsForAllDisplaysLocked( 3130 AccessibilityUserState userState) { 3131 final ArrayList<Display> displays = getValidDisplayList(); 3132 for (int i = 0; i < displays.size(); i++) { 3133 final int displayId = displays.get(i).getDisplayId(); 3134 updateMagnificationModeChangeSettingsLocked(userState, displayId); 3135 } 3136 } 3137 updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState)3138 private void updateWindowsForAccessibilityCallbackLocked(AccessibilityUserState userState) { 3139 // We observe windows for accessibility only if there is at least 3140 // one bound service that can retrieve window content that specified 3141 // it is interested in accessing such windows. For services that are 3142 // binding we do an update pass after each bind event, so we run this 3143 // code and register the callback if needed. 3144 3145 boolean observingWindows = mUiAutomationManager.canRetrieveInteractiveWindowsLocked() 3146 || mProxyManager.canRetrieveInteractiveWindowsLocked(); 3147 List<AccessibilityServiceConnection> boundServices = userState.mBoundServices; 3148 final int boundServiceCount = boundServices.size(); 3149 for (int i = 0; !observingWindows && (i < boundServiceCount); i++) { 3150 AccessibilityServiceConnection boundService = boundServices.get(i); 3151 if (boundService.canRetrieveInteractiveWindowsLocked()) { 3152 userState.setAccessibilityFocusOnlyInActiveWindow(false); 3153 observingWindows = true; 3154 } 3155 } 3156 userState.setAccessibilityFocusOnlyInActiveWindow(true); 3157 3158 // Gets all valid displays and start tracking windows of each display if there is at least 3159 // one bound service that can retrieve window content. 3160 final ArrayList<Display> displays = getValidDisplayList(); 3161 for (int i = 0; i < displays.size(); i++) { 3162 final Display display = displays.get(i); 3163 if (display != null) { 3164 if (observingWindows) { 3165 mA11yWindowManager.startTrackingWindows(display.getDisplayId(), 3166 mProxyManager.isProxyedDisplay(display.getDisplayId())); 3167 } else { 3168 mA11yWindowManager.stopTrackingWindows(display.getDisplayId()); 3169 } 3170 } 3171 } 3172 } 3173 updateLegacyCapabilitiesLocked(AccessibilityUserState userState)3174 private void updateLegacyCapabilitiesLocked(AccessibilityUserState userState) { 3175 // Up to JB-MR1 we had a allowlist with services that can enable touch 3176 // exploration. When a service is first started we show a dialog to the 3177 // use to get a permission to allowlist the service. 3178 final int installedServiceCount = userState.mInstalledServices.size(); 3179 for (int i = 0; i < installedServiceCount; i++) { 3180 AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i); 3181 ResolveInfo resolveInfo = serviceInfo.getResolveInfo(); 3182 if ((serviceInfo.getCapabilities() 3183 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0 3184 && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion 3185 <= Build.VERSION_CODES.JELLY_BEAN_MR1) { 3186 ComponentName componentName = new ComponentName( 3187 resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 3188 if (userState.mTouchExplorationGrantedServices.contains(componentName)) { 3189 serviceInfo.setCapabilities(serviceInfo.getCapabilities() 3190 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION); 3191 } 3192 } 3193 } 3194 } 3195 updatePerformGesturesLocked(AccessibilityUserState userState)3196 private void updatePerformGesturesLocked(AccessibilityUserState userState) { 3197 final int serviceCount = userState.mBoundServices.size(); 3198 for (int i = 0; i < serviceCount; i++) { 3199 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 3200 if ((service.getCapabilities() 3201 & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0) { 3202 userState.setPerformGesturesEnabledLocked(true); 3203 return; 3204 } 3205 } 3206 userState.setPerformGesturesEnabledLocked(false); 3207 } 3208 updateFilterKeyEventsLocked(AccessibilityUserState userState)3209 private void updateFilterKeyEventsLocked(AccessibilityUserState userState) { 3210 final int serviceCount = userState.mBoundServices.size(); 3211 for (int i = 0; i < serviceCount; i++) { 3212 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 3213 if (service.mRequestFilterKeyEvents 3214 && (service.getCapabilities() 3215 & AccessibilityServiceInfo 3216 .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) { 3217 userState.setFilterKeyEventsEnabledLocked(true); 3218 return; 3219 } 3220 } 3221 userState.setFilterKeyEventsEnabledLocked(false); 3222 } 3223 readConfigurationForUserStateLocked( AccessibilityUserState userState, List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos, List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos)3224 private boolean readConfigurationForUserStateLocked( 3225 AccessibilityUserState userState, 3226 List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos, 3227 List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos) { 3228 boolean somethingChanged = readInstalledAccessibilityServiceLocked( 3229 userState, parsedAccessibilityServiceInfos); 3230 somethingChanged |= readInstalledAccessibilityShortcutLocked( 3231 userState, parsedAccessibilityShortcutInfos); 3232 somethingChanged |= readEnabledAccessibilityServicesLocked(userState); 3233 somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState); 3234 somethingChanged |= readTouchExplorationEnabledSettingLocked(userState); 3235 somethingChanged |= readHighTextContrastEnabledSettingLocked(userState); 3236 somethingChanged |= readAudioDescriptionEnabledSettingLocked(userState); 3237 somethingChanged |= readMagnificationEnabledSettingsLocked(userState); 3238 somethingChanged |= readAutoclickEnabledSettingLocked(userState); 3239 somethingChanged |= readAccessibilityShortcutKeySettingLocked(userState); 3240 somethingChanged |= readAccessibilityQsTargetsLocked(userState); 3241 somethingChanged |= readAccessibilityButtonTargetsLocked(userState); 3242 somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState); 3243 somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState); 3244 somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState); 3245 somethingChanged |= readMagnificationCapabilitiesLocked(userState); 3246 somethingChanged |= readMagnificationFollowTypingLocked(userState); 3247 somethingChanged |= readAlwaysOnMagnificationLocked(userState); 3248 return somethingChanged; 3249 } 3250 updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState)3251 private void updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState) { 3252 final boolean isA11yEnabled = mUiAutomationManager.canIntrospect() 3253 || userState.isHandlingAccessibilityEventsLocked(); 3254 final long identity = Binder.clearCallingIdentity(); 3255 try { 3256 Settings.Secure.putIntForUser(mContext.getContentResolver(), 3257 Settings.Secure.ACCESSIBILITY_ENABLED, 3258 (isA11yEnabled) ? 1 : 0, 3259 userState.mUserId); 3260 } finally { 3261 Binder.restoreCallingIdentity(identity); 3262 } 3263 } 3264 readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState)3265 private boolean readTouchExplorationEnabledSettingLocked(AccessibilityUserState userState) { 3266 final boolean touchExplorationEnabled = Settings.Secure.getIntForUser( 3267 mContext.getContentResolver(), 3268 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; 3269 if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) { 3270 userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); 3271 return true; 3272 } 3273 return false; 3274 } 3275 readMagnificationEnabledSettingsLocked(AccessibilityUserState userState)3276 private boolean readMagnificationEnabledSettingsLocked(AccessibilityUserState userState) { 3277 final boolean magnificationSingleFingerTripleTapEnabled = Settings.Secure.getIntForUser( 3278 mContext.getContentResolver(), 3279 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 3280 0, userState.mUserId) == 1; 3281 if ((magnificationSingleFingerTripleTapEnabled 3282 != userState.isMagnificationSingleFingerTripleTapEnabledLocked())) { 3283 userState.setMagnificationSingleFingerTripleTapEnabledLocked( 3284 magnificationSingleFingerTripleTapEnabled); 3285 return true; 3286 } 3287 return false; 3288 } 3289 readMagnificationTwoFingerTripleTapSettingsLocked( AccessibilityUserState userState)3290 private boolean readMagnificationTwoFingerTripleTapSettingsLocked( 3291 AccessibilityUserState userState) { 3292 final boolean magnificationTwoFingerTripleTapEnabled = Settings.Secure.getIntForUser( 3293 mContext.getContentResolver(), 3294 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, 3295 0, userState.mUserId) == 1; 3296 if ((magnificationTwoFingerTripleTapEnabled 3297 != userState.isMagnificationTwoFingerTripleTapEnabledLocked())) { 3298 userState.setMagnificationTwoFingerTripleTapEnabledLocked( 3299 magnificationTwoFingerTripleTapEnabled); 3300 return true; 3301 } 3302 return false; 3303 } 3304 readAutoclickEnabledSettingLocked(AccessibilityUserState userState)3305 private boolean readAutoclickEnabledSettingLocked(AccessibilityUserState userState) { 3306 final boolean autoclickEnabled = Settings.Secure.getIntForUser( 3307 mContext.getContentResolver(), 3308 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED, 3309 0, userState.mUserId) == 1; 3310 if (autoclickEnabled != userState.isAutoclickEnabledLocked()) { 3311 userState.setAutoclickEnabledLocked(autoclickEnabled); 3312 return true; 3313 } 3314 return false; 3315 } 3316 readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState)3317 private boolean readHighTextContrastEnabledSettingLocked(AccessibilityUserState userState) { 3318 final boolean highTextContrastEnabled = Settings.Secure.getIntForUser( 3319 mContext.getContentResolver(), 3320 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0, 3321 userState.mUserId) == 1; 3322 if (highTextContrastEnabled != userState.isTextHighContrastEnabledLocked()) { 3323 userState.setTextHighContrastEnabledLocked(highTextContrastEnabled); 3324 return true; 3325 } 3326 return false; 3327 } 3328 readAudioDescriptionEnabledSettingLocked(AccessibilityUserState userState)3329 private boolean readAudioDescriptionEnabledSettingLocked(AccessibilityUserState userState) { 3330 final boolean audioDescriptionByDefaultEnabled = Settings.Secure.getIntForUser( 3331 mContext.getContentResolver(), 3332 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT, 0, 3333 userState.mUserId) == 1; 3334 if (audioDescriptionByDefaultEnabled 3335 != userState.isAudioDescriptionByDefaultEnabledLocked()) { 3336 userState.setAudioDescriptionByDefaultEnabledLocked(audioDescriptionByDefaultEnabled); 3337 return true; 3338 } 3339 return false; 3340 } 3341 updateTouchExplorationLocked(AccessibilityUserState userState)3342 private void updateTouchExplorationLocked(AccessibilityUserState userState) { 3343 boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); 3344 boolean serviceHandlesDoubleTapEnabled = false; 3345 boolean requestMultiFingerGestures = false; 3346 boolean requestTwoFingerPassthrough = false; 3347 boolean sendMotionEvents = false; 3348 final int serviceCount = userState.mBoundServices.size(); 3349 for (int i = 0; i < serviceCount; i++) { 3350 AccessibilityServiceConnection service = userState.mBoundServices.get(i); 3351 if (canRequestAndRequestsTouchExplorationLocked(service, userState)) { 3352 touchExplorationEnabled = true; 3353 serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled(); 3354 requestMultiFingerGestures = service.isMultiFingerGesturesEnabled(); 3355 requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled(); 3356 sendMotionEvents = service.isSendMotionEventsEnabled(); 3357 break; 3358 } 3359 } 3360 if (touchExplorationEnabled != userState.isTouchExplorationEnabledLocked()) { 3361 userState.setTouchExplorationEnabledLocked(touchExplorationEnabled); 3362 final long identity = Binder.clearCallingIdentity(); 3363 try { 3364 Settings.Secure.putIntForUser(mContext.getContentResolver(), 3365 Settings.Secure.TOUCH_EXPLORATION_ENABLED, touchExplorationEnabled ? 1 : 0, 3366 userState.mUserId); 3367 } finally { 3368 Binder.restoreCallingIdentity(identity); 3369 } 3370 } 3371 // Service gesture detection is turned on and off on a per-display 3372 // basis. 3373 userState.resetServiceDetectsGestures(); 3374 final ArrayList<Display> displays = getValidDisplayList(); 3375 for (AccessibilityServiceConnection service: userState.mBoundServices) { 3376 for (Display display : displays) { 3377 int displayId = display.getDisplayId(); 3378 if (service.isServiceDetectsGesturesEnabled(displayId)) { 3379 userState.setServiceDetectsGesturesEnabled(displayId, true); 3380 } 3381 } 3382 } 3383 userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); 3384 userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); 3385 userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough); 3386 userState.setSendMotionEventsEnabled(sendMotionEvents); 3387 } 3388 readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState)3389 private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) { 3390 final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 3391 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId); 3392 final Set<String> targetsFromSetting = new ArraySet<>(); 3393 readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false); 3394 // Fall back to device's default a11y service, only when setting is never updated. 3395 if (settingValue == null) { 3396 final String defaultService = mContext.getString( 3397 R.string.config_defaultAccessibilityService); 3398 if (!TextUtils.isEmpty(defaultService)) { 3399 targetsFromSetting.add(defaultService); 3400 } 3401 } 3402 3403 final Set<String> currentTargets = 3404 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE); 3405 if (targetsFromSetting.equals(currentTargets)) { 3406 return false; 3407 } 3408 currentTargets.clear(); 3409 currentTargets.addAll(targetsFromSetting); 3410 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3411 return true; 3412 } 3413 readAccessibilityQsTargetsLocked(AccessibilityUserState userState)3414 private boolean readAccessibilityQsTargetsLocked(AccessibilityUserState userState) { 3415 final Set<String> targetsFromSetting = new ArraySet<>(); 3416 readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_QS_TARGETS, 3417 userState.mUserId, str -> str, targetsFromSetting); 3418 3419 final Set<String> currentTargets = 3420 userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS); 3421 if (targetsFromSetting.equals(currentTargets)) { 3422 return false; 3423 } 3424 userState.updateA11yQsTargetLocked(targetsFromSetting); 3425 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3426 return true; 3427 } 3428 readAccessibilityButtonTargetsLocked(AccessibilityUserState userState)3429 private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) { 3430 final Set<String> targetsFromSetting = new ArraySet<>(); 3431 readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 3432 userState.mUserId, str -> str, targetsFromSetting); 3433 3434 final Set<String> currentTargets = 3435 userState.getShortcutTargetsLocked(UserShortcutType.SOFTWARE); 3436 if (targetsFromSetting.equals(currentTargets)) { 3437 return false; 3438 } 3439 currentTargets.clear(); 3440 currentTargets.addAll(targetsFromSetting); 3441 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3442 return true; 3443 } 3444 readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState)3445 private boolean readAccessibilityButtonTargetComponentLocked(AccessibilityUserState userState) { 3446 final String componentId = Settings.Secure.getStringForUser(mContext.getContentResolver(), 3447 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, userState.mUserId); 3448 if (TextUtils.isEmpty(componentId)) { 3449 if (userState.getTargetAssignedToAccessibilityButton() == null) { 3450 return false; 3451 } 3452 userState.setTargetAssignedToAccessibilityButton(null); 3453 return true; 3454 } 3455 if (componentId.equals(userState.getTargetAssignedToAccessibilityButton())) { 3456 return false; 3457 } 3458 userState.setTargetAssignedToAccessibilityButton(componentId); 3459 return true; 3460 } 3461 readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState)3462 private boolean readUserRecommendedUiTimeoutSettingsLocked(AccessibilityUserState userState) { 3463 final int nonInteractiveUiTimeout = Settings.Secure.getIntForUser( 3464 mContext.getContentResolver(), 3465 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS, 0, 3466 userState.mUserId); 3467 final int interactiveUiTimeout = Settings.Secure.getIntForUser( 3468 mContext.getContentResolver(), 3469 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, 0, 3470 userState.mUserId); 3471 3472 mProxyManager.updateTimeoutsIfNeeded(nonInteractiveUiTimeout, interactiveUiTimeout); 3473 if (nonInteractiveUiTimeout != userState.getUserNonInteractiveUiTimeoutLocked() 3474 || interactiveUiTimeout != userState.getUserInteractiveUiTimeoutLocked()) { 3475 userState.setUserNonInteractiveUiTimeoutLocked(nonInteractiveUiTimeout); 3476 userState.setUserInteractiveUiTimeoutLocked(interactiveUiTimeout); 3477 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3478 return true; 3479 } 3480 return false; 3481 } 3482 3483 /** 3484 * Check if the target that will be enabled by the accessibility shortcut key is installed. 3485 * If it isn't, remove it from the list and associated setting so a side loaded service can't 3486 * spoof the package name of the default service. 3487 */ updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState)3488 private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) { 3489 final Set<String> currentTargets = 3490 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE); 3491 final int lastSize = currentTargets.size(); 3492 if (lastSize == 0) { 3493 return; 3494 } 3495 currentTargets.removeIf( 3496 name -> !userState.isShortcutTargetInstalledLocked(name)); 3497 if (lastSize == currentTargets.size()) { 3498 return; 3499 } 3500 3501 // Update setting key with new value. 3502 persistColonDelimitedSetToSettingLocked( 3503 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, 3504 userState.mUserId, currentTargets, str -> str); 3505 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3506 } 3507 canRequestAndRequestsTouchExplorationLocked( AccessibilityServiceConnection service, AccessibilityUserState userState)3508 private boolean canRequestAndRequestsTouchExplorationLocked( 3509 AccessibilityServiceConnection service, AccessibilityUserState userState) { 3510 // Service not ready or cannot request the feature - well nothing to do. 3511 if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) { 3512 return false; 3513 } 3514 if (service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 3515 <= Build.VERSION_CODES.JELLY_BEAN_MR1) { 3516 // Up to JB-MR1 we had a allowlist with services that can enable touch 3517 // exploration. When a service is first started we show a dialog to the 3518 // use to get a permission to allowlist the service. 3519 if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) { 3520 return true; 3521 } else if (mEnableTouchExplorationDialog == null 3522 || !mEnableTouchExplorationDialog.isShowing()) { 3523 mMainHandler.sendMessage(obtainMessage( 3524 AccessibilityManagerService::showEnableTouchExplorationDialog, 3525 this, service)); 3526 } 3527 } else { 3528 // Starting in JB-MR2 we request an accessibility service to declare 3529 // certain capabilities in its meta-data to allow it to enable the 3530 // corresponding features. 3531 if ((service.getCapabilities() 3532 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) { 3533 return true; 3534 } 3535 } 3536 return false; 3537 } 3538 updateMagnificationLocked(AccessibilityUserState userState)3539 private void updateMagnificationLocked(AccessibilityUserState userState) { 3540 if (userState.mUserId != mCurrentUserId) { 3541 return; 3542 } 3543 3544 if (mUiAutomationManager.suppressingAccessibilityServicesLocked() 3545 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) { 3546 getMagnificationController().getFullScreenMagnificationController().unregisterAll(); 3547 return; 3548 } 3549 3550 // Get all valid displays and register them if global magnification is enabled. 3551 // We would skip overlay display because it uses overlay window to simulate secondary 3552 // displays in one display. It's not a real display and there's no input events for it. 3553 final ArrayList<Display> displays = getValidDisplayList(); 3554 if (userState.isMagnificationSingleFingerTripleTapEnabledLocked() 3555 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() 3556 && userState.isMagnificationTwoFingerTripleTapEnabledLocked()) 3557 || userState.isShortcutMagnificationEnabledLocked()) { 3558 for (int i = 0; i < displays.size(); i++) { 3559 final Display display = displays.get(i); 3560 getMagnificationController().getFullScreenMagnificationController().register( 3561 display.getDisplayId()); 3562 } 3563 return; 3564 } 3565 3566 // Register if display has listening magnification services. 3567 for (int i = 0; i < displays.size(); i++) { 3568 final Display display = displays.get(i); 3569 final int displayId = display.getDisplayId(); 3570 if (userHasListeningMagnificationServicesLocked(userState, displayId)) { 3571 getMagnificationController().getFullScreenMagnificationController().register( 3572 displayId); 3573 } else if (mMagnificationController.isFullScreenMagnificationControllerInitialized()) { 3574 getMagnificationController().getFullScreenMagnificationController().unregister( 3575 displayId); 3576 } 3577 } 3578 } 3579 updateMagnificationConnectionIfNeeded(AccessibilityUserState userState)3580 private void updateMagnificationConnectionIfNeeded(AccessibilityUserState userState) { 3581 if (!mMagnificationController.supportWindowMagnification()) { 3582 return; 3583 } 3584 3585 final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked() 3586 || userState.isMagnificationSingleFingerTripleTapEnabledLocked() 3587 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() 3588 && userState.isMagnificationTwoFingerTripleTapEnabledLocked())); 3589 3590 final boolean createConnectionForCurrentCapability = 3591 com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder() 3592 || (userState.getMagnificationCapabilitiesLocked() 3593 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); 3594 3595 final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability) 3596 || userHasMagnificationServicesLocked(userState); 3597 3598 getMagnificationConnectionManager().requestConnection(connect); 3599 } 3600 3601 /** 3602 * Returns whether the specified user has any services that are capable of 3603 * controlling magnification. 3604 */ userHasMagnificationServicesLocked(AccessibilityUserState userState)3605 private boolean userHasMagnificationServicesLocked(AccessibilityUserState userState) { 3606 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 3607 for (int i = 0, count = services.size(); i < count; i++) { 3608 final AccessibilityServiceConnection service = services.get(i); 3609 if (mSecurityPolicy.canControlMagnification(service)) { 3610 return true; 3611 } 3612 } 3613 return false; 3614 } 3615 3616 /** 3617 * Returns whether the specified user has any services that are capable of 3618 * controlling magnification and are actively listening for magnification updates. 3619 */ userHasListeningMagnificationServicesLocked(AccessibilityUserState userState, int displayId)3620 private boolean userHasListeningMagnificationServicesLocked(AccessibilityUserState userState, 3621 int displayId) { 3622 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 3623 for (int i = 0, count = services.size(); i < count; i++) { 3624 final AccessibilityServiceConnection service = services.get(i); 3625 if (mSecurityPolicy.canControlMagnification(service) 3626 && service.isMagnificationCallbackEnabled(displayId)) { 3627 return true; 3628 } 3629 } 3630 return false; 3631 } 3632 updateFingerprintGestureHandling(AccessibilityUserState userState)3633 private void updateFingerprintGestureHandling(AccessibilityUserState userState) { 3634 final List<AccessibilityServiceConnection> services; 3635 synchronized (mLock) { 3636 services = userState.mBoundServices; 3637 if ((mFingerprintGestureDispatcher == null) 3638 && mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 3639 // Only create the controller when a service wants to use the feature 3640 int numServices = services.size(); 3641 for (int i = 0; i < numServices; i++) { 3642 if (services.get(i).isCapturingFingerprintGestures()) { 3643 IFingerprintService service = null; 3644 final long identity = Binder.clearCallingIdentity(); 3645 try { 3646 service = IFingerprintService.Stub.asInterface( 3647 ServiceManager.getService(Context.FINGERPRINT_SERVICE)); 3648 } finally { 3649 Binder.restoreCallingIdentity(identity); 3650 } 3651 if (service != null) { 3652 mFingerprintGestureDispatcher = new FingerprintGestureDispatcher( 3653 service, mContext.getResources(), mLock); 3654 break; 3655 } 3656 } 3657 } 3658 } 3659 } 3660 if (mFingerprintGestureDispatcher != null) { 3661 mFingerprintGestureDispatcher.updateClientList(services); 3662 } 3663 } 3664 3665 /** 3666 * 1) Update accessibility button availability to accessibility services. 3667 * 2) Check if the target that will be enabled by the accessibility button is installed. 3668 * If it isn't, remove it from the list and associated setting so a side loaded service can't 3669 * spoof the package name of the default service. 3670 */ updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState)3671 private void updateAccessibilityButtonTargetsLocked(AccessibilityUserState userState) { 3672 // Update accessibility button availability. 3673 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 3674 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 3675 if (service.mRequestAccessibilityButton) { 3676 service.notifyAccessibilityButtonAvailabilityChangedLocked( 3677 service.isAccessibilityButtonAvailableLocked(userState)); 3678 } 3679 } 3680 3681 final Set<String> currentTargets = 3682 userState.getShortcutTargetsLocked(UserShortcutType.SOFTWARE); 3683 final int lastSize = currentTargets.size(); 3684 if (lastSize == 0) { 3685 return; 3686 } 3687 currentTargets.removeIf( 3688 name -> !userState.isShortcutTargetInstalledLocked(name)); 3689 if (lastSize == currentTargets.size()) { 3690 return; 3691 } 3692 3693 // Update setting key with new value. 3694 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 3695 userState.mUserId, currentTargets, str -> str); 3696 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3697 } 3698 3699 /** 3700 * 1) Check if the service assigned to accessibility button target sdk version > Q. 3701 * If it isn't, remove it from the list and associated setting. 3702 * (It happens when an accessibility service package is downgraded.) 3703 * 2) For a service targeting sdk version > Q and requesting a11y button, it should be in the 3704 * enabled list if's assigned to a11y button. 3705 * (It happens when an accessibility service package is same graded, and updated requesting 3706 * a11y button flag) 3707 * 3) Check if an enabled service targeting sdk version > Q and requesting a11y button is 3708 * assigned to a shortcut. If it isn't, assigns it to the accessibility button. 3709 * (It happens when an enabled accessibility service package is upgraded.) 3710 * 3711 * @param packageName The package name to check, or {@code null} to check all services. 3712 * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0} 3713 * if the caller is not related to the restore. 3714 */ migrateAccessibilityButtonSettingsIfNecessaryLocked( AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt)3715 private void migrateAccessibilityButtonSettingsIfNecessaryLocked( 3716 AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) { 3717 // No need to migrate settings if they are restored from a version after Q. 3718 if (restoreFromSdkInt > Build.VERSION_CODES.Q) { 3719 return; 3720 } 3721 final Set<String> buttonTargets = 3722 userState.getShortcutTargetsLocked(UserShortcutType.SOFTWARE); 3723 int lastSize = buttonTargets.size(); 3724 buttonTargets.removeIf(name -> { 3725 if (packageName != null && name != null && !name.contains(packageName)) { 3726 return false; 3727 } 3728 final ComponentName componentName = ComponentName.unflattenFromString(name); 3729 if (componentName == null) { 3730 return false; 3731 } 3732 final AccessibilityServiceInfo serviceInfo = 3733 userState.getInstalledServiceInfoLocked(componentName); 3734 if (serviceInfo == null) { 3735 return false; 3736 } 3737 if (serviceInfo.getResolveInfo().serviceInfo.applicationInfo 3738 .targetSdkVersion <= Build.VERSION_CODES.Q) { 3739 // A11y services targeting sdk version <= Q should not be in the list. 3740 Slog.v(LOG_TAG, "Legacy service " + componentName 3741 + " should not in the button"); 3742 return true; 3743 } 3744 final boolean requestA11yButton = (serviceInfo.flags 3745 & FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 3746 if (requestA11yButton && !userState.mEnabledServices.contains(componentName)) { 3747 // An a11y service targeting sdk version > Q and request A11y button and is assigned 3748 // to a11y btn should be in the enabled list. 3749 Slog.v(LOG_TAG, "Service requesting a11y button and be assigned to the button" 3750 + componentName + " should be enabled state"); 3751 return true; 3752 } 3753 return false; 3754 }); 3755 boolean changed = (lastSize != buttonTargets.size()); 3756 lastSize = buttonTargets.size(); 3757 3758 final Set<String> shortcutKeyTargets = 3759 userState.getShortcutTargetsLocked(UserShortcutType.HARDWARE); 3760 final Set<String> qsShortcutTargets = 3761 userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS); 3762 userState.mEnabledServices.forEach(componentName -> { 3763 if (packageName != null && componentName != null 3764 && !packageName.equals(componentName.getPackageName())) { 3765 return; 3766 } 3767 final AccessibilityServiceInfo serviceInfo = 3768 userState.getInstalledServiceInfoLocked(componentName); 3769 if (serviceInfo == null) { 3770 return; 3771 } 3772 final boolean requestA11yButton = (serviceInfo.flags 3773 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 3774 if (!(serviceInfo.getResolveInfo().serviceInfo.applicationInfo 3775 .targetSdkVersion > Build.VERSION_CODES.Q && requestA11yButton)) { 3776 return; 3777 } 3778 final String serviceName = componentName.flattenToString(); 3779 if (TextUtils.isEmpty(serviceName)) { 3780 return; 3781 } 3782 if (doesShortcutTargetsStringContain(buttonTargets, serviceName) 3783 || doesShortcutTargetsStringContain(shortcutKeyTargets, serviceName) 3784 || doesShortcutTargetsStringContain(qsShortcutTargets, serviceName)) { 3785 return; 3786 } 3787 // For enabled a11y services targeting sdk version > Q and requesting a11y button should 3788 // be assigned to a shortcut. 3789 Slog.v(LOG_TAG, "A enabled service requesting a11y button " + componentName 3790 + " should be assign to the button or shortcut."); 3791 buttonTargets.add(serviceName); 3792 }); 3793 changed |= (lastSize != buttonTargets.size()); 3794 if (!changed) { 3795 return; 3796 } 3797 3798 // Update setting key with new value. 3799 persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, 3800 userState.mUserId, buttonTargets, str -> str); 3801 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3802 } 3803 3804 /** 3805 * Update the Settings.Secure.ACCESSIBILITY_QS_TARGETS so that it only contains valid content, 3806 * and a side loaded service can't spoof the package name of the default service. 3807 * <p> 3808 * 1. Remove the target if the target is no longer installed on the device <br/> 3809 * 2. Add the target if the target is enabled and the target's tile is in the QS Panel <br/> 3810 * </p> 3811 */ updateAccessibilityQsTargetsLocked(AccessibilityUserState userState)3812 private void updateAccessibilityQsTargetsLocked(AccessibilityUserState userState) { 3813 if (!android.view.accessibility.Flags.a11yQsShortcut()) { 3814 return; 3815 } 3816 3817 final Set<String> targets = 3818 userState.getShortcutTargetsLocked(UserShortcutType.QUICK_SETTINGS); 3819 3820 // Removes the targets that are no longer installed on the device. 3821 boolean somethingChanged = targets.removeIf( 3822 name -> !userState.isShortcutTargetInstalledLocked(name)); 3823 // Add the target if the a11y service is enabled and the tile exist in QS panel 3824 Set<ComponentName> enabledServices = userState.getEnabledServicesLocked(); 3825 Map<ComponentName, ComponentName> a11yFeatureToTileService = 3826 userState.getA11yFeatureToTileService(); 3827 Set<ComponentName> currentA11yTilesInQsPanel = userState.getA11yQsTilesInQsPanel(); 3828 for (ComponentName enabledService : enabledServices) { 3829 ComponentName tileService = 3830 a11yFeatureToTileService.getOrDefault(enabledService, null); 3831 if (tileService != null && currentA11yTilesInQsPanel.contains(tileService)) { 3832 somethingChanged |= targets.add(enabledService.flattenToString()); 3833 } 3834 } 3835 3836 if (!somethingChanged) { 3837 return; 3838 } 3839 userState.updateA11yQsTargetLocked(targets); 3840 3841 // Update setting key with new value. 3842 persistColonDelimitedSetToSettingLocked( 3843 Settings.Secure.ACCESSIBILITY_QS_TARGETS, 3844 userState.mUserId, targets, str -> str); 3845 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 3846 } 3847 3848 /** 3849 * Remove the shortcut target for the unbound service which is requesting accessibility button 3850 * and targeting sdk > Q from the accessibility button and shortcut. 3851 * 3852 * @param userState The accessibility user state. 3853 * @param service The unbound service. 3854 */ removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState, AccessibilityServiceConnection service)3855 private void removeShortcutTargetForUnboundServiceLocked(AccessibilityUserState userState, 3856 AccessibilityServiceConnection service) { 3857 if (!service.mRequestAccessibilityButton 3858 || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo 3859 .targetSdkVersion <= Build.VERSION_CODES.Q) { 3860 return; 3861 } 3862 3863 final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = new ArrayList<>(3); 3864 shortcutTypeAndShortcutSetting.add( 3865 new Pair<>(UserShortcutType.HARDWARE, 3866 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)); 3867 shortcutTypeAndShortcutSetting.add( 3868 new Pair<>(UserShortcutType.SOFTWARE, 3869 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS)); 3870 if (android.view.accessibility.Flags.a11yQsShortcut()) { 3871 shortcutTypeAndShortcutSetting.add( 3872 new Pair<>(UserShortcutType.QUICK_SETTINGS, 3873 Settings.Secure.ACCESSIBILITY_QS_TARGETS)); 3874 } 3875 3876 final ComponentName serviceName = service.getComponentName(); 3877 for (Pair<Integer, String> shortcutTypePair : shortcutTypeAndShortcutSetting) { 3878 int shortcutType = shortcutTypePair.first; 3879 String shortcutSettingName = shortcutTypePair.second; 3880 if (userState.removeShortcutTargetLocked(shortcutType, serviceName)) { 3881 final Set<String> currentTargets = userState.getShortcutTargetsLocked(shortcutType); 3882 persistColonDelimitedSetToSettingLocked( 3883 shortcutSettingName, 3884 userState.mUserId, currentTargets, str -> str); 3885 3886 if (shortcutType != UserShortcutType.QUICK_SETTINGS) { 3887 continue; 3888 } 3889 3890 ComponentName tileService = 3891 userState.getA11yFeatureToTileService().getOrDefault(serviceName, null); 3892 3893 final StatusBarManagerInternal statusBarManagerInternal = 3894 LocalServices.getService(StatusBarManagerInternal.class); 3895 // In case it's not initialized yet 3896 if (statusBarManagerInternal == null || tileService == null) { 3897 continue; 3898 } 3899 mMainHandler.sendMessage(obtainMessage(StatusBarManagerInternal::removeQsTile, 3900 statusBarManagerInternal, tileService)); 3901 } 3902 } 3903 } 3904 updateRecommendedUiTimeoutLocked(AccessibilityUserState userState)3905 private void updateRecommendedUiTimeoutLocked(AccessibilityUserState userState) { 3906 int newNonInteractiveUiTimeout = userState.getUserNonInteractiveUiTimeoutLocked(); 3907 int newInteractiveUiTimeout = userState.getUserInteractiveUiTimeoutLocked(); 3908 // read from a11y services if user does not specify value 3909 if (newNonInteractiveUiTimeout == 0 || newInteractiveUiTimeout == 0) { 3910 int serviceNonInteractiveUiTimeout = 0; 3911 int serviceInteractiveUiTimeout = 0; 3912 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 3913 for (int i = 0; i < services.size(); i++) { 3914 int timeout = services.get(i).getServiceInfo().getInteractiveUiTimeoutMillis(); 3915 if (serviceInteractiveUiTimeout < timeout) { 3916 serviceInteractiveUiTimeout = timeout; 3917 } 3918 timeout = services.get(i).getServiceInfo().getNonInteractiveUiTimeoutMillis(); 3919 if (serviceNonInteractiveUiTimeout < timeout) { 3920 serviceNonInteractiveUiTimeout = timeout; 3921 } 3922 } 3923 if (newNonInteractiveUiTimeout == 0) { 3924 newNonInteractiveUiTimeout = serviceNonInteractiveUiTimeout; 3925 } 3926 if (newInteractiveUiTimeout == 0) { 3927 newInteractiveUiTimeout = serviceInteractiveUiTimeout; 3928 } 3929 } 3930 userState.setNonInteractiveUiTimeoutLocked(newNonInteractiveUiTimeout); 3931 userState.setInteractiveUiTimeoutLocked(newInteractiveUiTimeout); 3932 } 3933 3934 @Override getKeyEventDispatcher()3935 public KeyEventDispatcher getKeyEventDispatcher() { 3936 if (mKeyEventDispatcher == null) { 3937 mKeyEventDispatcher = new KeyEventDispatcher( 3938 mMainHandler, MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, mLock, 3939 mPowerManager); 3940 } 3941 return mKeyEventDispatcher; 3942 } 3943 3944 @Override 3945 @SuppressWarnings("AndroidFrameworkPendingIntentMutability") getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)3946 public PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent, 3947 int flags) { 3948 return PendingIntent.getActivity(context, requestCode, intent, flags); 3949 } 3950 3951 /** 3952 * AIDL-exposed method to be called when the accessibility shortcut key is enabled. Requires 3953 * permission to write secure settings, since someone with that permission can enable 3954 * accessibility services themselves. 3955 * 3956 * @param targetName The flattened {@link ComponentName} string or the class name of a system 3957 * class implementing a supported accessibility feature, or {@code null} if there's no 3958 * specified target. 3959 */ 3960 @EnforcePermission(MANAGE_ACCESSIBILITY) 3961 @Override performAccessibilityShortcut(String targetName)3962 public void performAccessibilityShortcut(String targetName) { 3963 performAccessibilityShortcut_enforcePermission(); 3964 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 3965 mTraceManager.logTrace(LOG_TAG + ".performAccessibilityShortcut", 3966 FLAGS_ACCESSIBILITY_MANAGER, "targetName=" + targetName); 3967 } 3968 3969 mMainHandler.sendMessage(obtainMessage( 3970 AccessibilityManagerService::performAccessibilityShortcutInternal, this, 3971 Display.DEFAULT_DISPLAY, UserShortcutType.HARDWARE, targetName)); 3972 } 3973 3974 /** 3975 * Perform the accessibility shortcut action. 3976 * 3977 * @param shortcutType The shortcut type. 3978 * @param displayId The display id of the accessibility button. 3979 * @param targetName The flattened {@link ComponentName} string or the class name of a system 3980 * class implementing a supported accessibility feature, or {@code null} if there's no 3981 * specified target. 3982 */ performAccessibilityShortcutInternal(int displayId, @UserShortcutType int shortcutType, @Nullable String targetName)3983 private void performAccessibilityShortcutInternal(int displayId, 3984 @UserShortcutType int shortcutType, @Nullable String targetName) { 3985 final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType); 3986 if (shortcutTargets.isEmpty()) { 3987 Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType); 3988 return; 3989 } 3990 // In case the caller specified a target name 3991 if (targetName != null && !doesShortcutTargetsStringContain(shortcutTargets, targetName)) { 3992 Slog.v(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName); 3993 targetName = null; 3994 } 3995 if (targetName == null) { 3996 // In case there are many targets assigned to the given shortcut. 3997 if (shortcutTargets.size() > 1) { 3998 showAccessibilityTargetsSelection(displayId, shortcutType); 3999 return; 4000 } 4001 targetName = shortcutTargets.get(0); 4002 } 4003 // In case user assigned magnification to the given shortcut. 4004 if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) { 4005 final boolean enabled = 4006 !getMagnificationController().getFullScreenMagnificationController() 4007 .isActivated(displayId); 4008 logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType, 4009 enabled); 4010 sendAccessibilityButtonToInputFilter(displayId); 4011 return; 4012 } 4013 final ComponentName targetComponentName = ComponentName.unflattenFromString(targetName); 4014 if (targetComponentName == null) { 4015 Slog.d(LOG_TAG, "Perform shortcut failed, invalid target name:" + targetName); 4016 return; 4017 } 4018 // In case user assigned an accessibility framework feature to the given shortcut. 4019 if (performAccessibilityFrameworkFeature(displayId, targetComponentName, shortcutType)) { 4020 return; 4021 } 4022 // In case user assigned an accessibility shortcut target to the given shortcut. 4023 if (performAccessibilityShortcutTargetActivity(displayId, targetComponentName)) { 4024 logAccessibilityShortcutActivated(mContext, targetComponentName, shortcutType); 4025 return; 4026 } 4027 // in case user assigned an accessibility service to the given shortcut. 4028 if (performAccessibilityShortcutTargetService( 4029 displayId, shortcutType, targetComponentName)) { 4030 return; 4031 } 4032 } 4033 performAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget, @UserShortcutType int shortcutType)4034 private boolean performAccessibilityFrameworkFeature(int displayId, 4035 ComponentName assignedTarget, @UserShortcutType int shortcutType) { 4036 final Map<ComponentName, FrameworkFeatureInfo> frameworkFeatureMap = 4037 AccessibilityShortcutController.getFrameworkShortcutFeaturesMap(); 4038 if (!frameworkFeatureMap.containsKey(assignedTarget)) { 4039 return false; 4040 } 4041 final FrameworkFeatureInfo featureInfo = frameworkFeatureMap.get(assignedTarget); 4042 final SettingStringHelper setting = new SettingStringHelper(mContext.getContentResolver(), 4043 featureInfo.getSettingKey(), mCurrentUserId); 4044 4045 if (featureInfo instanceof LaunchableFrameworkFeatureInfo) { 4046 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 4047 /* serviceEnabled= */ true); 4048 launchAccessibilityFrameworkFeature(displayId, assignedTarget); 4049 return true; 4050 } 4051 4052 // Assuming that the default state will be to have the feature off 4053 if (!TextUtils.equals(featureInfo.getSettingOnValue(), setting.read())) { 4054 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 4055 /* serviceEnabled= */ true); 4056 setting.write(featureInfo.getSettingOnValue()); 4057 } else { 4058 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 4059 /* serviceEnabled= */ false); 4060 setting.write(featureInfo.getSettingOffValue()); 4061 } 4062 return true; 4063 } 4064 performAccessibilityShortcutTargetActivity(int displayId, ComponentName assignedTarget)4065 private boolean performAccessibilityShortcutTargetActivity(int displayId, 4066 ComponentName assignedTarget) { 4067 synchronized (mLock) { 4068 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4069 for (int i = 0; i < userState.mInstalledShortcuts.size(); i++) { 4070 final AccessibilityShortcutInfo shortcutInfo = userState.mInstalledShortcuts.get(i); 4071 if (!shortcutInfo.getComponentName().equals(assignedTarget)) { 4072 continue; 4073 } 4074 launchShortcutTargetActivity(displayId, assignedTarget); 4075 return true; 4076 } 4077 } 4078 return false; 4079 } 4080 4081 /** 4082 * Perform accessibility service shortcut action. 4083 * 4084 * 1) For {@link UserShortcutType#SOFTWARE} type and services targeting sdk 4085 * version <= Q: callbacks to accessibility service if service is bounded and requests 4086 * accessibility button. 4087 * 2) For {@link UserShortcutType#HARDWARE} type and service targeting sdk 4088 * version <= Q: turns on / off the accessibility service. 4089 * 3) For {@link UserShortcutType#HARDWARE} type and service targeting sdk 4090 * version > Q and request accessibility button: turn on the accessibility service if it's 4091 * not in the enabled state. 4092 * (It'll happen when a service is disabled and assigned to shortcut then upgraded.) 4093 * 4) For services targeting sdk version > Q: 4094 * a) Turns on / off the accessibility service, if service does not request accessibility 4095 * button. 4096 * b) Callbacks to accessibility service if service is bounded and requests accessibility 4097 * button. 4098 */ performAccessibilityShortcutTargetService(int displayId, @UserShortcutType int shortcutType, ComponentName assignedTarget)4099 private boolean performAccessibilityShortcutTargetService(int displayId, 4100 @UserShortcutType int shortcutType, ComponentName assignedTarget) { 4101 synchronized (mLock) { 4102 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4103 final AccessibilityServiceInfo installedServiceInfo = 4104 userState.getInstalledServiceInfoLocked(assignedTarget); 4105 if (installedServiceInfo == null) { 4106 Slog.d(LOG_TAG, "Perform shortcut failed, invalid component name:" 4107 + assignedTarget); 4108 return false; 4109 } 4110 4111 final AccessibilityServiceConnection serviceConnection = 4112 userState.getServiceConnectionLocked(assignedTarget); 4113 final int targetSdk = installedServiceInfo.getResolveInfo() 4114 .serviceInfo.applicationInfo.targetSdkVersion; 4115 final boolean requestA11yButton = (installedServiceInfo.flags 4116 & FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 4117 // Turns on / off the accessibility service 4118 if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == UserShortcutType.HARDWARE) 4119 || (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) { 4120 if (serviceConnection == null) { 4121 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 4122 /* serviceEnabled= */ true); 4123 enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); 4124 4125 } else { 4126 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 4127 /* serviceEnabled= */ false); 4128 disableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); 4129 } 4130 return true; 4131 } 4132 if (shortcutType == UserShortcutType.HARDWARE && targetSdk > Build.VERSION_CODES.Q 4133 && requestA11yButton) { 4134 if (!userState.getEnabledServicesLocked().contains(assignedTarget)) { 4135 enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId); 4136 return true; 4137 } 4138 } 4139 // Callbacks to a11y service if it's bounded and requests a11y button. 4140 if (serviceConnection == null 4141 || !userState.mBoundServices.contains(serviceConnection) 4142 || !serviceConnection.mRequestAccessibilityButton) { 4143 Slog.d(LOG_TAG, "Perform shortcut failed, service is not ready:" 4144 + assignedTarget); 4145 return false; 4146 } 4147 // ServiceConnection means service enabled. 4148 logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType, 4149 /* serviceEnabled= */ true); 4150 serviceConnection.notifyAccessibilityButtonClickedLocked(displayId); 4151 return true; 4152 } 4153 } 4154 launchAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget)4155 private void launchAccessibilityFrameworkFeature(int displayId, ComponentName assignedTarget) { 4156 if (assignedTarget.equals(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME)) { 4157 //import com.android.systemui.Flags; 4158 if (com.android.systemui.Flags.hearingAidsQsTileDialog()) { 4159 launchHearingDevicesDialog(); 4160 } else { 4161 launchAccessibilitySubSettings(displayId, 4162 ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME); 4163 } 4164 } 4165 } 4166 4167 /** 4168 * Turns on or off a shortcut type of the accessibility features. The {@code shortcutTypes} is a 4169 * flag that contains values defined in the 4170 * {@link ShortcutConstants.USER_SHORTCUT_TYPES}. 4171 * 4172 * @hide 4173 */ 4174 @Override 4175 @EnforcePermission(MANAGE_ACCESSIBILITY) enableShortcutsForTargets( boolean enable, @UserShortcutType int shortcutTypes, @NonNull List<String> shortcutTargets, @UserIdInt int userId)4176 public void enableShortcutsForTargets( 4177 boolean enable, @UserShortcutType int shortcutTypes, 4178 @NonNull List<String> shortcutTargets, @UserIdInt int userId) { 4179 enableShortcutsForTargets_enforcePermission(); 4180 for (int shortcutType : USER_SHORTCUT_TYPES) { 4181 if ((shortcutTypes & shortcutType) == shortcutType) { 4182 enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId); 4183 } 4184 } 4185 } 4186 enableShortcutForTargets( boolean enable, @UserShortcutType int shortcutType, @NonNull List<String> shortcutTargets, @UserIdInt int userId)4187 private void enableShortcutForTargets( 4188 boolean enable, @UserShortcutType int shortcutType, 4189 @NonNull List<String> shortcutTargets, @UserIdInt int userId) { 4190 final String shortcutTypeSettingKey = ShortcutUtils.convertToKey(shortcutType); 4191 if (shortcutType == UserShortcutType.TRIPLETAP 4192 || shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) { 4193 for (String target : shortcutTargets) { 4194 if (MAGNIFICATION_CONTROLLER_NAME.equals(target)) { 4195 persistIntToSetting( 4196 userId, 4197 shortcutTypeSettingKey, 4198 enable ? AccessibilityUtils.State.ON : AccessibilityUtils.State.OFF); 4199 } else { 4200 Slog.w(LOG_TAG, 4201 "Triple tap or two-fingers double-tap is not supported for " + target); 4202 } 4203 } 4204 return; 4205 } 4206 Set<String> validNewTargets; 4207 Set<String> currentTargets; 4208 4209 Map<ComponentName, ComponentName> featureToTileMap = 4210 getA11yFeatureToTileMapInternal(userId); 4211 synchronized (mLock) { 4212 AccessibilityUserState userState = getUserStateLocked(userId); 4213 currentTargets = 4214 ShortcutUtils.getShortcutTargetsFromSettings(mContext, shortcutType, userId); 4215 4216 Set<String> newTargets = new ArraySet<>(currentTargets); 4217 if (enable) { 4218 newTargets.addAll(shortcutTargets); 4219 } else { 4220 newTargets.removeAll(shortcutTargets); 4221 } 4222 validNewTargets = newTargets; 4223 4224 // filter out targets that doesn't have qs shortcut 4225 if (shortcutType == UserShortcutType.QUICK_SETTINGS) { 4226 validNewTargets = newTargets.stream().filter(target -> { 4227 ComponentName targetComponent = ComponentName.unflattenFromString(target); 4228 return featureToTileMap.containsKey(targetComponent); 4229 }).collect(Collectors.toUnmodifiableSet()); 4230 } 4231 4232 if (currentTargets.equals(validNewTargets)) { 4233 return; 4234 } 4235 persistColonDelimitedSetToSettingLocked( 4236 shortcutTypeSettingKey, 4237 userId, 4238 validNewTargets, 4239 str -> str, 4240 /* defaultEmptyString= */ "" 4241 ); 4242 4243 if (shortcutType == UserShortcutType.QUICK_SETTINGS) { 4244 int numOfFeatureChanged = Math.abs(currentTargets.size() - validNewTargets.size()); 4245 logMetricForQsShortcutConfiguration(enable, numOfFeatureChanged); 4246 userState.updateA11yQsTargetLocked(validNewTargets); 4247 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 4248 onUserStateChangedLocked(userState); 4249 } 4250 } 4251 final long identity = Binder.clearCallingIdentity(); 4252 try { 4253 ShortcutUtils.updateInvisibleToggleAccessibilityServiceEnableState( 4254 mContext, new ArraySet<>(shortcutTargets), userId); 4255 } finally { 4256 Binder.restoreCallingIdentity(identity); 4257 } 4258 4259 // Add or Remove tile in QS Panel 4260 if (shortcutType == UserShortcutType.QUICK_SETTINGS) { 4261 mMainHandler.sendMessage(obtainMessage( 4262 AccessibilityManagerService::updateA11yTileServicesInQuickSettingsPanel, 4263 this, validNewTargets, currentTargets, userId)); 4264 } 4265 4266 if (!enable) { 4267 return; 4268 } 4269 if (shortcutType == UserShortcutType.HARDWARE) { 4270 skipVolumeShortcutDialogTimeoutRestriction(userId); 4271 if (com.android.server.accessibility.Flags.enableHardwareShortcutDisablesWarning()) { 4272 persistIntToSetting( 4273 userId, 4274 Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 4275 AccessibilityShortcutController.DialogStatus.SHOWN 4276 ); 4277 } 4278 } else if (shortcutType == UserShortcutType.SOFTWARE) { 4279 // Update the A11y FAB size to large when the Magnification shortcut is 4280 // enabled and the user hasn't changed the floating button size 4281 if (shortcutTargets.contains(MAGNIFICATION_CONTROLLER_NAME) 4282 && Settings.Secure.getIntForUser(mContext.getContentResolver(), 4283 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, 4284 FloatingMenuSize.UNKNOWN, userId) == FloatingMenuSize.UNKNOWN) { 4285 persistIntToSetting( 4286 userId, 4287 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, 4288 FloatingMenuSize.LARGE); 4289 } 4290 } 4291 } 4292 4293 /** 4294 * Add or remove the TileServices of the a11y features in the Quick Settings panel based on the 4295 * changes in the new targets and current targets. 4296 * 4297 * <p> 4298 * The framework tiles implemented in the SysUi are automatically added/removed via the 4299 * SystemUI's AutoAddable framework. This method only handles updating the TileServices 4300 * provided by AccessibilityService or Accessibility Activity. 4301 * </p> 4302 * 4303 * @see com.android.systemui.qs.pipeline.domain.model.AutoAddable AutoAddable QS Tiles 4304 */ updateA11yTileServicesInQuickSettingsPanel( Set<String> newQsTargets, Set<String> currentQsTargets, @UserIdInt int userId)4305 private void updateA11yTileServicesInQuickSettingsPanel( 4306 Set<String> newQsTargets, 4307 Set<String> currentQsTargets, @UserIdInt int userId) { 4308 // Call StatusBarManager to add/remove tiles 4309 final StatusBarManagerInternal statusBarManagerInternal = 4310 LocalServices.getService(StatusBarManagerInternal.class); 4311 // In case it's not initialized yet 4312 if (statusBarManagerInternal == null) { 4313 return; 4314 } 4315 4316 Map<ComponentName, ComponentName> a11yFeatureToTileMap = 4317 getA11yFeatureToTileMapInternal(userId); 4318 Set<String> targetWithNoTile = new ArraySet<>(); 4319 4320 // Add TileServices to QS Panel that are added to the new targets 4321 newQsTargets.stream() 4322 .filter(target -> !currentQsTargets.contains(target)) 4323 .forEach( 4324 target -> { 4325 ComponentName targetComponent = 4326 ComponentName.unflattenFromString(target); 4327 if (targetComponent == null 4328 || !a11yFeatureToTileMap.containsKey(targetComponent)) { 4329 targetWithNoTile.add(target); 4330 return; 4331 } 4332 4333 if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey( 4334 targetComponent)) { 4335 // a11y framework tile is handled by the SysUi autoaddable framework 4336 return; 4337 } 4338 statusBarManagerInternal.addQsTileToFrontOrEnd( 4339 a11yFeatureToTileMap.get(targetComponent), /* end= */ true); 4340 } 4341 ); 4342 4343 // Remove TileServices from QS Panel that are no longer in the new targets. 4344 currentQsTargets.stream() 4345 .filter(target -> !newQsTargets.contains(target)) 4346 .forEach( 4347 target -> { 4348 ComponentName targetComponent = 4349 ComponentName.unflattenFromString(target); 4350 if (targetComponent == null 4351 || !a11yFeatureToTileMap.containsKey(targetComponent)) { 4352 targetWithNoTile.add(target); 4353 return; 4354 } 4355 4356 if (ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE.containsKey( 4357 targetComponent)) { 4358 // a11y framework tile is handled by the SysUi autoaddable framework 4359 return; 4360 } 4361 statusBarManagerInternal.removeQsTile( 4362 a11yFeatureToTileMap.get(targetComponent)); 4363 } 4364 ); 4365 4366 if (!targetWithNoTile.isEmpty()) { 4367 Slog.e(LOG_TAG, 4368 "Unable to add/remove Tiles for a11y features: " + targetWithNoTile 4369 + "as the Tiles aren't provided"); 4370 } 4371 } 4372 4373 @Override 4374 @EnforcePermission(MANAGE_ACCESSIBILITY) getA11yFeatureToTileMap(@serIdInt int userId)4375 public Bundle getA11yFeatureToTileMap(@UserIdInt int userId) { 4376 getA11yFeatureToTileMap_enforcePermission(); 4377 Bundle bundle = new Bundle(); 4378 Map<ComponentName, ComponentName> a11yFeatureToTile = 4379 getA11yFeatureToTileMapInternal(userId); 4380 for (Map.Entry<ComponentName, ComponentName> entry : a11yFeatureToTile.entrySet()) { 4381 bundle.putParcelable(entry.getKey().flattenToString(), entry.getValue()); 4382 } 4383 return bundle; 4384 } 4385 4386 4387 4388 /** 4389 * Returns accessibility feature's component and the provided tile map. This includes the 4390 * TileService provided by the AccessibilityService or Accessibility Activity and the tile 4391 * component provided by the framework's feature. 4392 * 4393 * @return a map of a feature's component name, and its provided tile's component name. The 4394 * returned map's keys and values are not null. If a feature doesn't provide a tile, it won't 4395 * have an entry in this map. 4396 * 4397 * @see ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE 4398 */ 4399 @NonNull getA11yFeatureToTileMapInternal( @serIdInt int userId)4400 private Map<ComponentName, ComponentName> getA11yFeatureToTileMapInternal( 4401 @UserIdInt int userId) { 4402 final Map<ComponentName, ComponentName> a11yFeatureToTileService; 4403 Map<ComponentName, ComponentName> a11yFeatureToTile = new ArrayMap<>(); 4404 final int resolvedUserId; 4405 4406 synchronized (mLock) { 4407 resolvedUserId = mSecurityPolicy 4408 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 4409 AccessibilityUserState userState = getUserStateLocked(resolvedUserId); 4410 a11yFeatureToTileService = userState.getA11yFeatureToTileService(); 4411 } 4412 final boolean shouldFilterAppAccess = Binder.getCallingPid() != OWN_PROCESS_ID; 4413 final int callingUid = Binder.getCallingUid(); 4414 final PackageManagerInternal pm = LocalServices.getService( 4415 PackageManagerInternal.class); 4416 4417 for (Map.Entry<ComponentName, ComponentName> entry : 4418 a11yFeatureToTileService.entrySet()) { 4419 if (shouldFilterAppAccess 4420 && pm.filterAppAccess( 4421 entry.getKey().getPackageName(), callingUid, resolvedUserId)) { 4422 continue; 4423 } 4424 a11yFeatureToTile.put(entry.getKey(), entry.getValue()); 4425 } 4426 4427 a11yFeatureToTile.putAll(ShortcutConstants.A11Y_FEATURE_TO_FRAMEWORK_TILE); 4428 return a11yFeatureToTile; 4429 } 4430 4431 @Override 4432 @EnforcePermission(MANAGE_ACCESSIBILITY) getAccessibilityShortcutTargets(@serShortcutType int shortcutType)4433 public List<String> getAccessibilityShortcutTargets(@UserShortcutType int shortcutType) { 4434 getAccessibilityShortcutTargets_enforcePermission(); 4435 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4436 mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets", 4437 FLAGS_ACCESSIBILITY_MANAGER, "shortcutType=" + shortcutType); 4438 } 4439 return getAccessibilityShortcutTargetsInternal(shortcutType); 4440 } 4441 getAccessibilityShortcutTargetsInternal( @serShortcutType int shortcutType)4442 private List<String> getAccessibilityShortcutTargetsInternal( 4443 @UserShortcutType int shortcutType) { 4444 synchronized (mLock) { 4445 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4446 final ArrayList<String> shortcutTargets = new ArrayList<>( 4447 userState.getShortcutTargetsLocked(shortcutType)); 4448 if (shortcutType != UserShortcutType.SOFTWARE) { 4449 return shortcutTargets; 4450 } 4451 // Adds legacy a11y services requesting a11y button into the list. 4452 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 4453 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 4454 if (!service.mRequestAccessibilityButton 4455 || service.getServiceInfo().getResolveInfo().serviceInfo.applicationInfo 4456 .targetSdkVersion > Build.VERSION_CODES.Q) { 4457 continue; 4458 } 4459 final String serviceName = service.getComponentName().flattenToString(); 4460 if (!TextUtils.isEmpty(serviceName)) { 4461 shortcutTargets.add(serviceName); 4462 } 4463 } 4464 return shortcutTargets; 4465 } 4466 } 4467 4468 /** 4469 * Enables accessibility service specified by {@param componentName} for the {@param userId}. 4470 */ enableAccessibilityServiceLocked(ComponentName componentName, int userId)4471 private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) { 4472 mTempComponentNameSet.clear(); 4473 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 4474 userId, mTempComponentNameSet); 4475 mTempComponentNameSet.add(componentName); 4476 persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 4477 mTempComponentNameSet, userId); 4478 4479 AccessibilityUserState userState = getUserStateLocked(userId); 4480 if (userState.mEnabledServices.add(componentName)) { 4481 onUserStateChangedLocked(userState); 4482 } 4483 } 4484 4485 /** 4486 * Disables accessibility service specified by {@param componentName} for the {@param userId}. 4487 */ disableAccessibilityServiceLocked(ComponentName componentName, int userId)4488 private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) { 4489 mTempComponentNameSet.clear(); 4490 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 4491 userId, mTempComponentNameSet); 4492 mTempComponentNameSet.remove(componentName); 4493 persistComponentNamesToSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 4494 mTempComponentNameSet, userId); 4495 4496 AccessibilityUserState userState = getUserStateLocked(userId); 4497 if (userState.mEnabledServices.remove(componentName)) { 4498 onUserStateChangedLocked(userState); 4499 } 4500 } 4501 4502 @Override sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event)4503 public void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event) { 4504 if (event.getWindowChanges() == AccessibilityEvent.WINDOWS_CHANGE_ADDED) { 4505 // We need to ensure the window is available before sending pending 4506 // window_state_changed events. 4507 sendPendingWindowStateChangedEventsForAvailableWindowLocked(event.getWindowId()); 4508 } 4509 sendAccessibilityEventLocked(event, mCurrentUserId); 4510 } 4511 sendAccessibilityEventLocked(AccessibilityEvent event, int userId)4512 private void sendAccessibilityEventLocked(AccessibilityEvent event, int userId) { 4513 // Resync to avoid calling out with the lock held 4514 event.setEventTime(SystemClock.uptimeMillis()); 4515 mMainHandler.sendMessage(obtainMessage( 4516 AccessibilityManagerService::sendAccessibilityEvent, 4517 this, event, userId)); 4518 } 4519 4520 /** 4521 * AIDL-exposed method. System only. 4522 * Inform accessibility that a fingerprint gesture was performed 4523 * 4524 * @param gestureKeyCode The key code corresponding to the fingerprint gesture. 4525 * @return {@code true} if accessibility consumes the fingerprint gesture, {@code false} if it 4526 * doesn't. 4527 */ 4528 @Override 4529 @RequiresNoPermission sendFingerprintGesture(int gestureKeyCode)4530 public boolean sendFingerprintGesture(int gestureKeyCode) { 4531 if (mTraceManager.isA11yTracingEnabledForTypes( 4532 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT)) { 4533 mTraceManager.logTrace(LOG_TAG + ".sendFingerprintGesture", 4534 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_FINGERPRINT, 4535 "gestureKeyCode=" + gestureKeyCode); 4536 } 4537 4538 synchronized(mLock) { 4539 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { 4540 // TODO(b/333547153) remove the AIDL definitions for these functions that are 4541 // restricted to system server and move them to AccessibilityManagerInternal. 4542 throw new SecurityException("Only SYSTEM can call sendFingerprintGesture"); 4543 } 4544 } 4545 if (mFingerprintGestureDispatcher == null) { 4546 return false; 4547 } 4548 return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode); 4549 } 4550 4551 /** 4552 * AIDL-exposed method. System only. 4553 * Gets accessibility window id from window token. 4554 * 4555 * @param windowToken Window token to get accessibility window id. 4556 * @return Accessibility window id for the window token. Returns -1 if no such token is 4557 * registered. 4558 */ 4559 @Override 4560 @RequiresNoPermission getAccessibilityWindowId(@ullable IBinder windowToken)4561 public int getAccessibilityWindowId(@Nullable IBinder windowToken) { 4562 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4563 mTraceManager.logTrace(LOG_TAG + ".getAccessibilityWindowId", 4564 FLAGS_ACCESSIBILITY_MANAGER, "windowToken=" + windowToken); 4565 } 4566 4567 synchronized (mLock) { 4568 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { 4569 throw new SecurityException("Only SYSTEM can call getAccessibilityWindowId"); 4570 } 4571 4572 return mA11yWindowManager.findWindowIdLocked(mCurrentUserId, windowToken); 4573 } 4574 } 4575 4576 /** 4577 * Get the recommended timeout of interactive controls and non-interactive controls. 4578 * 4579 * @return A long for pair of {@code int}s. First integer for interactive one, and second 4580 * integer for non-interactive one. 4581 */ 4582 @Override 4583 @RequiresNoPermission getRecommendedTimeoutMillis()4584 public long getRecommendedTimeoutMillis() { 4585 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4586 mTraceManager.logTrace( 4587 LOG_TAG + ".getRecommendedTimeoutMillis", FLAGS_ACCESSIBILITY_MANAGER); 4588 } 4589 4590 synchronized(mLock) { 4591 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 4592 Binder.getCallingUid()); 4593 if (mProxyManager.isProxyedDeviceId(deviceId)) { 4594 return mProxyManager.getRecommendedTimeoutMillisLocked(deviceId); 4595 } else { 4596 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4597 return getRecommendedTimeoutMillisLocked(userState); 4598 } 4599 } 4600 } 4601 getRecommendedTimeoutMillisLocked(AccessibilityUserState userState)4602 private long getRecommendedTimeoutMillisLocked(AccessibilityUserState userState) { 4603 return IntPair.of(userState.getInteractiveUiTimeoutLocked(), 4604 userState.getNonInteractiveUiTimeoutLocked()); 4605 } 4606 4607 @Override 4608 @EnforcePermission(STATUS_BAR_SERVICE) setMagnificationConnection( IMagnificationConnection connection)4609 public void setMagnificationConnection( 4610 IMagnificationConnection connection) throws RemoteException { 4611 setMagnificationConnection_enforcePermission(); 4612 if (mTraceManager.isA11yTracingEnabledForTypes( 4613 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_MAGNIFICATION_CONNECTION)) { 4614 mTraceManager.logTrace(LOG_TAG + ".setMagnificationConnection", 4615 FLAGS_ACCESSIBILITY_MANAGER | FLAGS_MAGNIFICATION_CONNECTION, 4616 "connection=" + connection); 4617 } 4618 4619 getMagnificationConnectionManager().setConnection(connection); 4620 4621 if (com.android.window.flags.Flags.alwaysDrawMagnificationFullscreenBorder() 4622 && connection == null 4623 && mMagnificationController.isFullScreenMagnificationControllerInitialized()) { 4624 // Since the connection does not exist, the system ui cannot provide the border 4625 // implementation for fullscreen magnification. So we call reset to deactivate the 4626 // fullscreen magnification to prevent the magnified but no border situation. 4627 final ArrayList<Display> displays = getValidDisplayList(); 4628 for (int i = 0; i < displays.size(); i++) { 4629 final Display display = displays.get(i); 4630 getMagnificationController().getFullScreenMagnificationController() 4631 .reset(display.getDisplayId(), false); 4632 } 4633 } 4634 } 4635 4636 /** 4637 * Getter of {@link MagnificationConnectionManager}. 4638 * 4639 * @return MagnificationManager 4640 */ getMagnificationConnectionManager()4641 public MagnificationConnectionManager getMagnificationConnectionManager() { 4642 synchronized (mLock) { 4643 return mMagnificationController.getMagnificationConnectionManager(); 4644 } 4645 } 4646 4647 /** 4648 * Getter of {@link MagnificationController}. 4649 * 4650 * @return MagnificationController 4651 */ getMagnificationController()4652 MagnificationController getMagnificationController() { 4653 return mMagnificationController; 4654 } 4655 4656 @Override 4657 @RequiresNoPermission associateEmbeddedHierarchy(@onNull IBinder host, @NonNull IBinder embedded)4658 public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) { 4659 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4660 mTraceManager.logTrace(LOG_TAG + ".associateEmbeddedHierarchy", 4661 FLAGS_ACCESSIBILITY_MANAGER, "host=" + host + ";embedded=" + embedded); 4662 } 4663 4664 synchronized (mLock) { 4665 mA11yWindowManager.associateEmbeddedHierarchyLocked(host, embedded); 4666 } 4667 } 4668 4669 @Override 4670 @RequiresNoPermission disassociateEmbeddedHierarchy(@onNull IBinder token)4671 public void disassociateEmbeddedHierarchy(@NonNull IBinder token) { 4672 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4673 mTraceManager.logTrace(LOG_TAG + ".disassociateEmbeddedHierarchy", 4674 FLAGS_ACCESSIBILITY_MANAGER, "token=" + token); 4675 } 4676 4677 synchronized (mLock) { 4678 mA11yWindowManager.disassociateEmbeddedHierarchyLocked(token); 4679 } 4680 } 4681 4682 /** 4683 * Gets the stroke width of the focus rectangle. 4684 * @return The stroke width. 4685 */ 4686 @Override 4687 @RequiresNoPermission getFocusStrokeWidth()4688 public int getFocusStrokeWidth() { 4689 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4690 mTraceManager.logTrace(LOG_TAG + ".getFocusStrokeWidth", FLAGS_ACCESSIBILITY_MANAGER); 4691 } 4692 synchronized (mLock) { 4693 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 4694 Binder.getCallingUid()); 4695 if (mProxyManager.isProxyedDeviceId(deviceId)) { 4696 return mProxyManager.getFocusStrokeWidthLocked(deviceId); 4697 } 4698 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4699 4700 return userState.getFocusStrokeWidthLocked(); 4701 } 4702 } 4703 4704 /** 4705 * Gets the color of the focus rectangle. 4706 * @return The color. 4707 */ 4708 @Override 4709 @RequiresNoPermission getFocusColor()4710 public int getFocusColor() { 4711 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4712 mTraceManager.logTrace(LOG_TAG + ".getFocusColor", FLAGS_ACCESSIBILITY_MANAGER); 4713 } 4714 synchronized (mLock) { 4715 final int deviceId = mProxyManager.getFirstDeviceIdForUidLocked( 4716 Binder.getCallingUid()); 4717 if (mProxyManager.isProxyedDeviceId(deviceId)) { 4718 return mProxyManager.getFocusColorLocked(deviceId); 4719 } 4720 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4721 4722 return userState.getFocusColorLocked(); 4723 } 4724 } 4725 4726 /** 4727 * Gets the status of the audio description preference. 4728 * @return {@code true} if the audio description is enabled, {@code false} otherwise. 4729 */ 4730 @Override 4731 @RequiresNoPermission isAudioDescriptionByDefaultEnabled()4732 public boolean isAudioDescriptionByDefaultEnabled() { 4733 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4734 mTraceManager.logTrace(LOG_TAG + ".isAudioDescriptionByDefaultEnabled", 4735 FLAGS_ACCESSIBILITY_MANAGER); 4736 } 4737 synchronized (mLock) { 4738 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4739 4740 return userState.isAudioDescriptionByDefaultEnabledLocked(); 4741 } 4742 } 4743 4744 /** 4745 * Sets the {@link AccessibilityWindowAttributes} to the window associated with the given 4746 * window id. 4747 * 4748 * @param displayId The display id of the window. 4749 * @param windowId The id of the window 4750 * @param userId The user id. 4751 * @param attributes The accessibility window attributes. 4752 */ 4753 @Override 4754 @RequiresNoPermission setAccessibilityWindowAttributes(int displayId, int windowId, int userId, AccessibilityWindowAttributes attributes)4755 public void setAccessibilityWindowAttributes(int displayId, int windowId, int userId, 4756 AccessibilityWindowAttributes attributes) { 4757 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) { 4758 mTraceManager.logTrace(LOG_TAG + ".setAccessibilityWindowAttributes", 4759 FLAGS_ACCESSIBILITY_MANAGER); 4760 } 4761 mA11yWindowManager.setAccessibilityWindowAttributes(displayId, windowId, userId, 4762 attributes); 4763 } 4764 4765 @Override 4766 @EnforcePermission(SET_SYSTEM_AUDIO_CAPTION) setSystemAudioCaptioningEnabled(boolean isEnabled, int userId)4767 public void setSystemAudioCaptioningEnabled(boolean isEnabled, int userId) { 4768 setSystemAudioCaptioningEnabled_enforcePermission(); 4769 mCaptioningManagerImpl.setSystemAudioCaptioningEnabled(isEnabled, userId); 4770 } 4771 4772 @Override 4773 @RequiresNoPermission isSystemAudioCaptioningUiEnabled(int userId)4774 public boolean isSystemAudioCaptioningUiEnabled(int userId) { 4775 return mCaptioningManagerImpl.isSystemAudioCaptioningUiEnabled(userId); 4776 } 4777 4778 @Override 4779 @EnforcePermission(SET_SYSTEM_AUDIO_CAPTION) setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId)4780 public void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId) { 4781 setSystemAudioCaptioningUiEnabled_enforcePermission(); 4782 mCaptioningManagerImpl.setSystemAudioCaptioningUiEnabled(isEnabled, userId); 4783 } 4784 4785 @Override 4786 @EnforcePermission(CREATE_VIRTUAL_DEVICE) registerProxyForDisplay(IAccessibilityServiceClient client, int displayId)4787 public boolean registerProxyForDisplay(IAccessibilityServiceClient client, int displayId) 4788 throws RemoteException { 4789 registerProxyForDisplay_enforcePermission(); 4790 mSecurityPolicy.checkForAccessibilityPermissionOrRole(); 4791 if (client == null) { 4792 return false; 4793 } 4794 if (displayId < 0) { 4795 throw new IllegalArgumentException("The display id " + displayId + " is invalid."); 4796 } 4797 if (!isTrackedDisplay(displayId)) { 4798 throw new IllegalArgumentException("The display " + displayId + " does not exist or is" 4799 + " not tracked by accessibility."); 4800 } 4801 if (mProxyManager.isProxyedDisplay(displayId)) { 4802 throw new IllegalArgumentException("The display " + displayId + " is already being" 4803 + " proxy-ed"); 4804 } 4805 if (!mProxyManager.displayBelongsToCaller(Binder.getCallingUid(), displayId)) { 4806 throw new SecurityException("The display " + displayId + " does not belong to" 4807 + " the caller."); 4808 } 4809 4810 final long identity = Binder.clearCallingIdentity(); 4811 try { 4812 mProxyManager.registerProxy(client, displayId, sIdCounter++, mSecurityPolicy, 4813 this, getTraceManager(), mWindowManagerService); 4814 4815 synchronized (mLock) { 4816 notifyClearAccessibilityCacheLocked(); 4817 } 4818 } finally { 4819 Binder.restoreCallingIdentity(identity); 4820 } 4821 return true; 4822 } 4823 4824 @Override 4825 @EnforcePermission(CREATE_VIRTUAL_DEVICE) unregisterProxyForDisplay(int displayId)4826 public boolean unregisterProxyForDisplay(int displayId) { 4827 unregisterProxyForDisplay_enforcePermission(); 4828 mSecurityPolicy.checkForAccessibilityPermissionOrRole(); 4829 final long identity = Binder.clearCallingIdentity(); 4830 try { 4831 return mProxyManager.unregisterProxy(displayId); 4832 } finally { 4833 Binder.restoreCallingIdentity(identity); 4834 } 4835 } 4836 isDisplayProxyed(int displayId)4837 boolean isDisplayProxyed(int displayId) { 4838 return mProxyManager.isProxyedDisplay(displayId); 4839 } 4840 4841 @Override 4842 @RequiresNoPermission startFlashNotificationSequence(String opPkg, @FlashNotificationReason int reason, IBinder token)4843 public boolean startFlashNotificationSequence(String opPkg, 4844 @FlashNotificationReason int reason, IBinder token) { 4845 final long identity = Binder.clearCallingIdentity(); 4846 try { 4847 return mFlashNotificationsController.startFlashNotificationSequence(opPkg, 4848 reason, token); 4849 } finally { 4850 Binder.restoreCallingIdentity(identity); 4851 } 4852 } 4853 4854 @Override 4855 @RequiresNoPermission stopFlashNotificationSequence(String opPkg)4856 public boolean stopFlashNotificationSequence(String opPkg) { 4857 final long identity = Binder.clearCallingIdentity(); 4858 try { 4859 return mFlashNotificationsController.stopFlashNotificationSequence(opPkg); 4860 } finally { 4861 Binder.restoreCallingIdentity(identity); 4862 } 4863 } 4864 4865 @Override 4866 @RequiresNoPermission startFlashNotificationEvent(String opPkg, @FlashNotificationReason int reason, String reasonPkg)4867 public boolean startFlashNotificationEvent(String opPkg, 4868 @FlashNotificationReason int reason, String reasonPkg) { 4869 final long identity = Binder.clearCallingIdentity(); 4870 try { 4871 return mFlashNotificationsController.startFlashNotificationEvent(opPkg, 4872 reason, reasonPkg); 4873 } finally { 4874 Binder.restoreCallingIdentity(identity); 4875 } 4876 } 4877 4878 @Override 4879 @RequiresNoPermission isAccessibilityTargetAllowed(String packageName, int uid, int userId)4880 public boolean isAccessibilityTargetAllowed(String packageName, int uid, int userId) { 4881 final long identity = Binder.clearCallingIdentity(); 4882 try { 4883 final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); 4884 final List<String> permittedServices = dpm.getPermittedAccessibilityServices(userId); 4885 4886 // permittedServices null means all accessibility services are allowed. 4887 boolean allowed = permittedServices == null || permittedServices.contains(packageName); 4888 if (allowed) { 4889 if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled() 4890 && android.security.Flags.extendEcmToAllSettings()) { 4891 try { 4892 return !mContext.getSystemService(EnhancedConfirmationManager.class) 4893 .isRestricted(packageName, 4894 AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE); 4895 } catch (PackageManager.NameNotFoundException e) { 4896 Log.e(LOG_TAG, "Exception when retrieving package:" + packageName, e); 4897 return false; 4898 } 4899 } else { 4900 try { 4901 final int mode = mContext.getSystemService(AppOpsManager.class) 4902 .noteOpNoThrow(AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, 4903 uid, packageName); 4904 final boolean ecmEnabled = mContext.getResources().getBoolean( 4905 com.android.internal.R.bool.config_enhancedConfirmationModeEnabled); 4906 return !ecmEnabled || mode == AppOpsManager.MODE_ALLOWED 4907 || mode == AppOpsManager.MODE_DEFAULT; 4908 } catch (Exception e) { 4909 // Fallback in case if app ops is not available in testing. 4910 return false; 4911 } 4912 } 4913 } 4914 return false; 4915 } finally { 4916 Binder.restoreCallingIdentity(identity); 4917 } 4918 } 4919 4920 @Override 4921 @RequiresNoPermission sendRestrictedDialogIntent(String packageName, int uid, int userId)4922 public boolean sendRestrictedDialogIntent(String packageName, int uid, int userId) { 4923 // The accessibility service is allowed. Don't show the restricted dialog. 4924 if (isAccessibilityTargetAllowed(packageName, uid, userId)) { 4925 return false; 4926 } 4927 4928 final EnforcedAdmin admin = 4929 RestrictedLockUtilsInternal.checkIfAccessibilityServiceDisallowed( 4930 mContext, packageName, userId); 4931 if (admin != null) { 4932 RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin); 4933 return true; 4934 } 4935 4936 if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled() 4937 && android.security.Flags.extendEcmToAllSettings()) { 4938 try { 4939 Intent settingDialogIntent = mContext 4940 .getSystemService(EnhancedConfirmationManager.class) 4941 .createRestrictedSettingDialogIntent(packageName, 4942 AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE); 4943 mContext.startActivity(settingDialogIntent); 4944 } catch (PackageManager.NameNotFoundException e) { 4945 Log.e(LOG_TAG, "Exception when retrieving package:" + packageName, e); 4946 } 4947 } else { 4948 RestrictedLockUtils.sendShowRestrictedSettingDialogIntent(mContext, 4949 packageName, uid); 4950 } 4951 return true; 4952 } 4953 4954 @Override 4955 @EnforcePermission(MANAGE_ACCESSIBILITY) isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info)4956 public boolean isAccessibilityServiceWarningRequired(AccessibilityServiceInfo info) { 4957 isAccessibilityServiceWarningRequired_enforcePermission(); 4958 final ComponentName componentName = info.getComponentName(); 4959 4960 // Warning is not required if the service is already enabled. 4961 synchronized (mLock) { 4962 final AccessibilityUserState userState = getCurrentUserStateLocked(); 4963 if (userState.getEnabledServicesLocked().contains(componentName)) { 4964 return false; 4965 } 4966 } 4967 // Warning is not required if the service is already assigned to a shortcut. 4968 for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) { 4969 if (getAccessibilityShortcutTargets(shortcutType).contains( 4970 componentName.flattenToString())) { 4971 return false; 4972 } 4973 } 4974 // Warning is not required if the service is preinstalled and in the 4975 // trustedAccessibilityServices allowlist. 4976 if (android.view.accessibility.Flags.skipAccessibilityWarningDialogForTrustedServices() 4977 && isAccessibilityServicePreinstalledAndTrusted(info)) { 4978 return false; 4979 } 4980 4981 // Warning is required by default. 4982 return true; 4983 } 4984 isAccessibilityServicePreinstalledAndTrusted(AccessibilityServiceInfo info)4985 private boolean isAccessibilityServicePreinstalledAndTrusted(AccessibilityServiceInfo info) { 4986 final ComponentName componentName = info.getComponentName(); 4987 final boolean isPreinstalled = 4988 info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp(); 4989 if (isPreinstalled) { 4990 final String[] trustedAccessibilityServices = 4991 mContext.getResources().getStringArray( 4992 R.array.config_trustedAccessibilityServices); 4993 if (Arrays.stream(trustedAccessibilityServices) 4994 .map(ComponentName::unflattenFromString) 4995 .anyMatch(componentName::equals)) { 4996 return true; 4997 } 4998 } 4999 return false; 5000 } 5001 5002 @Override 5003 @PermissionManuallyEnforced // DUMP dump(FileDescriptor fd, final PrintWriter pw, String[] args)5004 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 5005 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; 5006 synchronized (mLock) { 5007 pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)"); 5008 pw.println(); 5009 pw.append("currentUserId=").append(String.valueOf(mCurrentUserId)); 5010 if (mRealCurrentUserId != UserHandle.USER_CURRENT 5011 && mCurrentUserId != mRealCurrentUserId) { 5012 pw.append(" (set for UiAutomation purposes; \"real\" current user is ") 5013 .append(String.valueOf(mRealCurrentUserId)).append(")"); 5014 } 5015 pw.println(); 5016 if (mVisibleBgUserIds != null) { 5017 pw.append("visibleBgUserIds=").append(mVisibleBgUserIds.toString()); 5018 pw.println(); 5019 } 5020 pw.append("hasMagnificationConnection=").append( 5021 String.valueOf(getMagnificationConnectionManager().isConnected())); 5022 pw.println(); 5023 mMagnificationProcessor.dump(pw, getValidDisplayList()); 5024 final int userCount = mUserStates.size(); 5025 for (int i = 0; i < userCount; i++) { 5026 mUserStates.valueAt(i).dump(fd, pw, args); 5027 } 5028 if (mUiAutomationManager.isUiAutomationRunningLocked()) { 5029 mUiAutomationManager.dumpUiAutomationService(fd, pw, args); 5030 pw.println(); 5031 } 5032 mA11yWindowManager.dump(fd, pw, args); 5033 if (mHasInputFilter && mInputFilter != null) { 5034 mInputFilter.dump(fd, pw, args); 5035 } 5036 pw.println("Global client list info:{"); 5037 mGlobalClients.dump(pw, " Client list "); 5038 pw.println(" Registered clients:{"); 5039 for (int i = 0; i < mGlobalClients.getRegisteredCallbackCount(); i++) { 5040 AccessibilityManagerService.Client client = (AccessibilityManagerService.Client) 5041 mGlobalClients.getRegisteredCallbackCookie(i); 5042 pw.append(Arrays.toString(client.mPackageNames)); 5043 } 5044 pw.println(); 5045 mProxyManager.dump(fd, pw, args); 5046 mA11yDisplayListener.dump(fd, pw, args); 5047 } 5048 } 5049 5050 //TODO remove after refactoring KeyEventDispatcherTest 5051 final class MainHandler extends Handler { 5052 public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8; 5053 MainHandler(Looper looper)5054 public MainHandler(Looper looper) { 5055 super(looper); 5056 } 5057 5058 @Override handleMessage(Message msg)5059 public void handleMessage(Message msg) { 5060 if (msg.what == MSG_SEND_KEY_EVENT_TO_INPUT_FILTER) { 5061 KeyEvent event = (KeyEvent) msg.obj; 5062 final int policyFlags = msg.arg1; 5063 synchronized (mLock) { 5064 if (mHasInputFilter && mInputFilter != null) { 5065 mInputFilter.sendInputEvent(event, policyFlags); 5066 } 5067 } 5068 event.recycle(); 5069 } 5070 } 5071 } 5072 5073 @Override getMagnificationProcessor()5074 public MagnificationProcessor getMagnificationProcessor() { 5075 return mMagnificationProcessor; 5076 } 5077 5078 @Override onClientChangeLocked(boolean serviceInfoChanged)5079 public void onClientChangeLocked(boolean serviceInfoChanged) { 5080 onClientChangeLocked(serviceInfoChanged, false); 5081 } 5082 5083 /** 5084 * Called when the state of a service or proxy has changed 5085 * @param serviceInfoChanged if the service info has changed 5086 * @param forceUpdate whether to force an update of state for app clients 5087 */ onClientChangeLocked(boolean serviceInfoChanged, boolean forceUpdate)5088 public void onClientChangeLocked(boolean serviceInfoChanged, boolean forceUpdate) { 5089 AccessibilityUserState userState = getUserStateLocked(mCurrentUserId); 5090 onUserStateChangedLocked(userState, forceUpdate); 5091 if (serviceInfoChanged) { 5092 scheduleNotifyClientsOfServicesStateChangeLocked(userState); 5093 } 5094 } 5095 5096 5097 @Override onProxyChanged(int deviceId)5098 public void onProxyChanged(int deviceId) { 5099 mProxyManager.onProxyChanged(deviceId); 5100 } 5101 5102 /** 5103 * Removes the device from tracking. This will reset any AccessibilityManagerClients to be 5104 * associated with the default user id. 5105 */ 5106 @Override removeDeviceIdLocked(int deviceId)5107 public void removeDeviceIdLocked(int deviceId) { 5108 resetClientsLocked(deviceId, getCurrentUserStateLocked().mUserClients); 5109 resetClientsLocked(deviceId, mGlobalClients); 5110 // Force an update of A11yManagers if the state was previously a proxy state and needs to be 5111 // returned to the default device state. 5112 onClientChangeLocked(true, true); 5113 } 5114 resetClientsLocked(int deviceId, RemoteCallbackList<IAccessibilityManagerClient> clients)5115 private void resetClientsLocked(int deviceId, 5116 RemoteCallbackList<IAccessibilityManagerClient> clients) { 5117 if (clients == null || clients.getRegisteredCallbackCount() == 0) { 5118 return; 5119 } 5120 synchronized (mLock) { 5121 for (int i = 0; i < clients.getRegisteredCallbackCount(); i++) { 5122 final Client appClient = ((Client) clients.getRegisteredCallbackCookie(i)); 5123 if (appClient.mDeviceId == deviceId) { 5124 appClient.mDeviceId = DEVICE_ID_DEFAULT; 5125 } 5126 } 5127 } 5128 } 5129 5130 @Override updateWindowsForAccessibilityCallbackLocked()5131 public void updateWindowsForAccessibilityCallbackLocked() { 5132 updateWindowsForAccessibilityCallbackLocked(getUserStateLocked(mCurrentUserId)); 5133 } 5134 5135 @Override getGlobalClientsLocked()5136 public RemoteCallbackList<IAccessibilityManagerClient> getGlobalClientsLocked() { 5137 return mGlobalClients; 5138 } 5139 5140 @Override getCurrentUserClientsLocked()5141 public RemoteCallbackList<IAccessibilityManagerClient> getCurrentUserClientsLocked() { 5142 return getCurrentUserState().mUserClients; 5143 } 5144 5145 @Override 5146 @RequiresNoPermission onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)5147 public void onShellCommand(FileDescriptor in, FileDescriptor out, 5148 FileDescriptor err, String[] args, ShellCallback callback, 5149 ResultReceiver resultReceiver) { 5150 new AccessibilityShellCommand(mContext, this, mSystemActionPerformer) 5151 .exec(this, in, out, err, args, callback, resultReceiver); 5152 } 5153 5154 private final class InteractionBridge { 5155 private final ComponentName COMPONENT_NAME = 5156 new ComponentName("com.android.server.accessibility", "InteractionBridge"); 5157 5158 private final Display mDefaultDisplay; 5159 private final int mConnectionId; 5160 private final AccessibilityInteractionClient mClient; 5161 InteractionBridge()5162 public InteractionBridge() { 5163 final AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 5164 info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); 5165 info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 5166 info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 5167 info.setAccessibilityTool(true); 5168 final AccessibilityUserState userState; 5169 synchronized (mLock) { 5170 userState = getCurrentUserStateLocked(); 5171 } 5172 AccessibilityServiceConnection service = new AccessibilityServiceConnection( 5173 userState, mContext, 5174 COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy, 5175 AccessibilityManagerService.this, 5176 AccessibilityManagerService.this.getTraceManager(), mWindowManagerService, 5177 getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) { 5178 @Override 5179 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { 5180 return true; 5181 } 5182 }; 5183 5184 mConnectionId = service.mId; 5185 5186 mClient = AccessibilityInteractionClient.getInstance(mContext); 5187 mClient.addConnection(mConnectionId, service, /*initializeCache=*/false); 5188 5189 //TODO: (multi-display) We need to support multiple displays. 5190 DisplayManager displayManager = (DisplayManager) 5191 mContext.getSystemService(Context.DISPLAY_SERVICE); 5192 mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 5193 } 5194 5195 /** 5196 * Gets a point within the accessibility focused node where we can send down and up events 5197 * to perform a click. 5198 * 5199 * @param outPoint The click point to populate. 5200 * @return Whether accessibility a click point was found and set. 5201 */ 5202 // TODO: (multi-display) Make sure this works for multiple displays. getAccessibilityFocusClickPointInScreen(Point outPoint)5203 boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { 5204 return getInteractionBridge() 5205 .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); 5206 } 5207 5208 /** 5209 * Perform an accessibility action on the view that currently has accessibility focus. 5210 * Has no effect if no item has accessibility focus, if the item with accessibility 5211 * focus does not expose the specified action, or if the action fails. 5212 * 5213 * @param action The action to perform. 5214 * 5215 * @return {@code true} if the action was performed. {@code false} if it was not. 5216 */ performActionOnAccessibilityFocusedItemNotLocked( AccessibilityNodeInfo.AccessibilityAction action)5217 public boolean performActionOnAccessibilityFocusedItemNotLocked( 5218 AccessibilityNodeInfo.AccessibilityAction action) { 5219 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); 5220 if ((focus == null) || !focus.getActionList().contains(action)) { 5221 return false; 5222 } 5223 return focus.performAction(action.getId()); 5224 } 5225 getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint)5226 public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { 5227 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); 5228 if (focus == null) { 5229 return false; 5230 } 5231 5232 synchronized (mLock) { 5233 Rect boundsInScreenBeforeMagnification = mTempRect; 5234 5235 focus.getBoundsInScreen(boundsInScreenBeforeMagnification); 5236 final Point nodeCenter = new Point(boundsInScreenBeforeMagnification.centerX(), 5237 boundsInScreenBeforeMagnification.centerY()); 5238 5239 // Invert magnification if needed. 5240 final Pair<float[], MagnificationSpec> pair = 5241 getWindowTransformationMatrixAndMagnificationSpec(focus.getWindowId()); 5242 MagnificationSpec spec = null; 5243 if (pair != null && pair.second != null) { 5244 spec = new MagnificationSpec(); 5245 spec.setTo(pair.second); 5246 } 5247 5248 if (spec != null && !spec.isNop()) { 5249 boundsInScreenBeforeMagnification.offset((int) -spec.offsetX, 5250 (int) -spec.offsetY); 5251 boundsInScreenBeforeMagnification.scale(1 / spec.scale); 5252 } 5253 5254 //Clip to the window bounds. 5255 Rect windowBounds = mTempRect1; 5256 AccessibilityWindowInfo window = focus.getWindow(); 5257 if (window != null) { 5258 window.getBoundsInScreen(windowBounds); 5259 } 5260 if (!boundsInScreenBeforeMagnification.intersect(windowBounds)) { 5261 return false; 5262 } 5263 5264 //Clip to the screen bounds. 5265 Point screenSize = mTempPoint; 5266 mDefaultDisplay.getRealSize(screenSize); 5267 if (!boundsInScreenBeforeMagnification.intersect(0, 0, screenSize.x, 5268 screenSize.y)) { 5269 return false; 5270 } 5271 5272 outPoint.set(nodeCenter.x, nodeCenter.y); 5273 } 5274 5275 return true; 5276 } 5277 getAccessibilityFocusNotLocked()5278 private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { 5279 final int focusedWindowId; 5280 synchronized (mLock) { 5281 focusedWindowId = mA11yWindowManager.getFocusedWindowId( 5282 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 5283 if (focusedWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { 5284 return null; 5285 } 5286 } 5287 return getAccessibilityFocusNotLocked(focusedWindowId); 5288 } 5289 getAccessibilityFocusNotLocked(int windowId)5290 private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) { 5291 return mClient.findFocus(mConnectionId, 5292 windowId, AccessibilityNodeInfo.ROOT_NODE_ID, 5293 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 5294 } 5295 } 5296 5297 /** 5298 * Gets all currently valid logical displays. 5299 * 5300 * @return An array list containing all valid logical displays. 5301 */ getValidDisplayList()5302 public ArrayList<Display> getValidDisplayList() { 5303 return mA11yDisplayListener.getValidDisplayList(); 5304 } 5305 5306 5307 /** 5308 * Returns {@code true} if the display id is in the list of currently valid logical displays 5309 * being tracked by a11y. 5310 */ isTrackedDisplay(int displayId)5311 private boolean isTrackedDisplay(int displayId) { 5312 final ArrayList<Display> displays = getValidDisplayList(); 5313 for (Display display : displays) { 5314 if (display.getDisplayId() == displayId) { 5315 return true; 5316 } 5317 } 5318 return false; 5319 } 5320 5321 /** 5322 * A Utility class to handle display state. 5323 */ 5324 public class AccessibilityDisplayListener implements DisplayManager.DisplayListener { 5325 private final DisplayManager mDisplayManager; 5326 private final ArrayList<Display> mDisplaysList = new ArrayList<>(); 5327 private int mSystemUiUid = 0; 5328 AccessibilityDisplayListener(Context context, Handler handler)5329 AccessibilityDisplayListener(Context context, Handler handler) { 5330 // Avoid concerns about one thread adding displays while another thread removes 5331 // them by ensuring the looper is the main looper and the DisplayListener 5332 // callbacks are always executed on the one main thread. 5333 final boolean isMainHandler = handler.getLooper() == Looper.getMainLooper(); 5334 final String errorMessage = 5335 "AccessibilityDisplayListener must use the main handler"; 5336 if (Build.IS_USERDEBUG || Build.IS_ENG) { 5337 Preconditions.checkArgument(isMainHandler, errorMessage); 5338 } else if (!isMainHandler) { 5339 Slog.e(LOG_TAG, errorMessage); 5340 } 5341 5342 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 5343 mDisplayManager.registerDisplayListener(this, handler); 5344 initializeDisplayList(); 5345 5346 final PackageManagerInternal pm = 5347 LocalServices.getService(PackageManagerInternal.class); 5348 if (pm != null) { 5349 mSystemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(), 5350 PackageManager.MATCH_SYSTEM_ONLY, mCurrentUserId); 5351 } 5352 } 5353 5354 /** 5355 * Gets all currently valid logical displays. 5356 * 5357 * @return An array list containing all valid logical displays. 5358 */ getValidDisplayList()5359 public ArrayList<Display> getValidDisplayList() { 5360 synchronized (mLock) { 5361 return mDisplaysList; 5362 } 5363 } 5364 initializeDisplayList()5365 private void initializeDisplayList() { 5366 final Display[] displays = mDisplayManager.getDisplays(); 5367 synchronized (mLock) { 5368 mDisplaysList.clear(); 5369 for (int i = 0; i < displays.length; i++) { 5370 // Exclude overlay virtual displays. The display list is for A11yInputFilter 5371 // to create event handler per display. The events should be handled by the 5372 // display which is overlaid by it. 5373 final Display display = displays[i]; 5374 if (isValidDisplay(display)) { 5375 mDisplaysList.add(display); 5376 } 5377 } 5378 } 5379 } 5380 5381 @Override onDisplayAdded(int displayId)5382 public void onDisplayAdded(int displayId) { 5383 final boolean isMainThread = Looper.getMainLooper().isCurrentThread(); 5384 final String errorMessage = "onDisplayAdded must be called from the main thread"; 5385 if (Build.IS_USERDEBUG || Build.IS_ENG) { 5386 Preconditions.checkArgument(isMainThread, errorMessage); 5387 } else if (!isMainThread) { 5388 Slog.e(LOG_TAG, errorMessage); 5389 } 5390 final Display display = mDisplayManager.getDisplay(displayId); 5391 if (!isValidDisplay(display)) { 5392 return; 5393 } 5394 5395 final List<AccessibilityServiceConnection> services; 5396 synchronized (mLock) { 5397 mDisplaysList.add(display); 5398 mA11yOverlayLayers.put( 5399 displayId, mWindowManagerService.getA11yOverlayLayer(displayId)); 5400 if (mInputFilter != null) { 5401 mInputFilter.onDisplayAdded(display); 5402 } 5403 AccessibilityUserState userState = getCurrentUserStateLocked(); 5404 services = new ArrayList<>(userState.mBoundServices); 5405 updateMagnificationLocked(userState); 5406 updateWindowsForAccessibilityCallbackLocked(userState); 5407 notifyClearAccessibilityCacheLocked(); 5408 } 5409 if (displayId != Display.DEFAULT_DISPLAY) { 5410 for (int i = 0; i < services.size(); i++) { 5411 AccessibilityServiceConnection boundClient = services.get(i); 5412 boundClient.addWindowTokenForDisplay(displayId); 5413 } 5414 } 5415 } 5416 5417 @Override onDisplayRemoved(int displayId)5418 public void onDisplayRemoved(int displayId) { 5419 final boolean isMainThread = Looper.getMainLooper().isCurrentThread(); 5420 final String errorMessage = "onDisplayRemoved must be called from the main thread"; 5421 if (Build.IS_USERDEBUG || Build.IS_ENG) { 5422 Preconditions.checkArgument(isMainThread, errorMessage); 5423 } else if (!isMainThread) { 5424 Slog.e(LOG_TAG, errorMessage); 5425 } 5426 synchronized (mLock) { 5427 if (!removeDisplayFromList(displayId)) { 5428 return; 5429 } 5430 mA11yOverlayLayers.remove(displayId); 5431 if (mInputFilter != null) { 5432 mInputFilter.onDisplayRemoved(displayId); 5433 } 5434 AccessibilityUserState userState = getCurrentUserStateLocked(); 5435 if (displayId != Display.DEFAULT_DISPLAY) { 5436 final List<AccessibilityServiceConnection> services = userState.mBoundServices; 5437 for (int i = 0; i < services.size(); i++) { 5438 AccessibilityServiceConnection boundClient = services.get(i); 5439 boundClient.onDisplayRemoved(displayId); 5440 } 5441 } 5442 } 5443 mMagnificationController.onDisplayRemoved(displayId); 5444 mA11yWindowManager.stopTrackingWindows(displayId); 5445 } 5446 5447 @GuardedBy("mLock") removeDisplayFromList(int displayId)5448 private boolean removeDisplayFromList(int displayId) { 5449 for (int i = 0; i < mDisplaysList.size(); i++) { 5450 if (mDisplaysList.get(i).getDisplayId() == displayId) { 5451 mDisplaysList.remove(i); 5452 return true; 5453 } 5454 } 5455 return false; 5456 } 5457 5458 @Override onDisplayChanged(int displayId)5459 public void onDisplayChanged(int displayId) { 5460 /* do nothing */ 5461 } 5462 dump(FileDescriptor fd, PrintWriter pw, String[] args)5463 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5464 pw.println("Accessibility Display Listener:"); 5465 pw.println(" SystemUI uid: " + mSystemUiUid); 5466 int size = mDisplaysList.size(); 5467 pw.printf(" %d valid display%s: ", size, (size == 1 ? "" : "s")); 5468 for (int i = 0; i < size; i++) { 5469 pw.print(mDisplaysList.get(i).getDisplayId()); 5470 if (i < size - 1) { 5471 pw.print(", "); 5472 } 5473 } 5474 pw.println(); 5475 } 5476 isValidDisplay(@ullable Display display)5477 private boolean isValidDisplay(@Nullable Display display) { 5478 if (display == null || display.getType() == Display.TYPE_OVERLAY) { 5479 return false; 5480 } 5481 // Private virtual displays are created by the ap and is not allowed to access by other 5482 // aps. We assume we could ignore them. 5483 // The exceptional case is for bubbles. Because the bubbles use the activityView, and 5484 // the virtual display of the activityView is private, so if the owner UID of the 5485 // private virtual display is the one of system ui which creates the virtual display of 5486 // bubbles, then this private virtual display should track the windows. 5487 if (display.getType() == Display.TYPE_VIRTUAL 5488 && (display.getFlags() & Display.FLAG_PRIVATE) != 0 5489 && display.getOwnerUid() != mSystemUiUid) { 5490 return false; 5491 } 5492 return true; 5493 } 5494 } 5495 5496 /** Represents an {@link AccessibilityManager} */ 5497 class Client { 5498 final IAccessibilityManagerClient mCallback; 5499 final String[] mPackageNames; 5500 int mLastSentRelevantEventTypes; 5501 int mUid; 5502 int mDeviceId = DEVICE_ID_DEFAULT; 5503 Client(IAccessibilityManagerClient callback, int clientUid, AccessibilityUserState userState, int deviceId)5504 private Client(IAccessibilityManagerClient callback, int clientUid, 5505 AccessibilityUserState userState, int deviceId) { 5506 mCallback = callback; 5507 mPackageNames = mPackageManager.getPackagesForUid(clientUid); 5508 mUid = clientUid; 5509 mDeviceId = deviceId; 5510 synchronized (mLock) { 5511 if (mProxyManager.isProxyedDeviceId(deviceId)) { 5512 mLastSentRelevantEventTypes = 5513 mProxyManager.computeRelevantEventTypesLocked(this); 5514 } else { 5515 mLastSentRelevantEventTypes = computeRelevantEventTypesLocked(userState, this); 5516 } 5517 } 5518 } 5519 } 5520 5521 private final class AccessibilityContentObserver extends ContentObserver { 5522 5523 private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor( 5524 Settings.Secure.TOUCH_EXPLORATION_ENABLED); 5525 5526 private final Uri mMagnificationmSingleFingerTripleTapEnabledUri = Settings.Secure 5527 .getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 5528 5529 private final Uri mMagnificationTwoFingerTripleTapEnabledUri = Settings.Secure.getUriFor( 5530 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED); 5531 5532 private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor( 5533 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED); 5534 5535 private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor( 5536 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 5537 5538 private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure 5539 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); 5540 5541 private final Uri mHighTextContrastUri = Settings.Secure.getUriFor( 5542 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED); 5543 5544 private final Uri mAudioDescriptionByDefaultUri = Settings.Secure.getUriFor( 5545 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT); 5546 5547 private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor( 5548 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); 5549 5550 private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor( 5551 Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); 5552 5553 private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor( 5554 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); 5555 5556 private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor( 5557 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT); 5558 5559 private final Uri mAccessibilityButtonTargetsUri = Settings.Secure.getUriFor( 5560 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS); 5561 5562 private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor( 5563 Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS); 5564 5565 private final Uri mUserInteractiveUiTimeoutUri = Settings.Secure.getUriFor( 5566 Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS); 5567 5568 private final Uri mMagnificationModeUri = Settings.Secure.getUriFor( 5569 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE); 5570 5571 private final Uri mMagnificationCapabilityUri = Settings.Secure.getUriFor( 5572 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY); 5573 5574 private final Uri mMagnificationFollowTypingUri = Settings.Secure.getUriFor( 5575 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED); 5576 5577 private final Uri mAlwaysOnMagnificationUri = Settings.Secure.getUriFor( 5578 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED); 5579 AccessibilityContentObserver(Handler handler)5580 public AccessibilityContentObserver(Handler handler) { 5581 super(handler); 5582 } 5583 register(ContentResolver contentResolver)5584 public void register(ContentResolver contentResolver) { 5585 contentResolver.registerContentObserver(mTouchExplorationEnabledUri, 5586 false, this, UserHandle.USER_ALL); 5587 contentResolver.registerContentObserver(mMagnificationmSingleFingerTripleTapEnabledUri, 5588 false, this, UserHandle.USER_ALL); 5589 if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) { 5590 contentResolver.registerContentObserver(mMagnificationTwoFingerTripleTapEnabledUri, 5591 false, this, UserHandle.USER_ALL); 5592 } 5593 contentResolver.registerContentObserver(mAutoclickEnabledUri, 5594 false, this, UserHandle.USER_ALL); 5595 contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri, 5596 false, this, UserHandle.USER_ALL); 5597 contentResolver.registerContentObserver( 5598 mTouchExplorationGrantedAccessibilityServicesUri, 5599 false, this, UserHandle.USER_ALL); 5600 contentResolver.registerContentObserver( 5601 mHighTextContrastUri, false, this, UserHandle.USER_ALL); 5602 contentResolver.registerContentObserver( 5603 mAudioDescriptionByDefaultUri, false, this, UserHandle.USER_ALL); 5604 contentResolver.registerContentObserver( 5605 mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL); 5606 contentResolver.registerContentObserver( 5607 mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL); 5608 contentResolver.registerContentObserver( 5609 mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL); 5610 contentResolver.registerContentObserver( 5611 mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL); 5612 contentResolver.registerContentObserver( 5613 mAccessibilityButtonTargetsUri, false, this, UserHandle.USER_ALL); 5614 contentResolver.registerContentObserver( 5615 mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); 5616 contentResolver.registerContentObserver( 5617 mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL); 5618 contentResolver.registerContentObserver( 5619 mMagnificationModeUri, false, this, UserHandle.USER_ALL); 5620 contentResolver.registerContentObserver( 5621 mMagnificationCapabilityUri, false, this, UserHandle.USER_ALL); 5622 contentResolver.registerContentObserver( 5623 mMagnificationFollowTypingUri, false, this, UserHandle.USER_ALL); 5624 contentResolver.registerContentObserver( 5625 mAlwaysOnMagnificationUri, false, this, UserHandle.USER_ALL); 5626 } 5627 5628 @Override onChange(boolean selfChange, Uri uri)5629 public void onChange(boolean selfChange, Uri uri) { 5630 synchronized (mLock) { 5631 // Profiles share the accessibility state of the parent. Therefore, 5632 // we are checking for changes only the parent settings. 5633 AccessibilityUserState userState = getCurrentUserStateLocked(); 5634 5635 if (mTouchExplorationEnabledUri.equals(uri)) { 5636 if (readTouchExplorationEnabledSettingLocked(userState)) { 5637 onUserStateChangedLocked(userState); 5638 } 5639 } else if (mMagnificationmSingleFingerTripleTapEnabledUri.equals(uri)) { 5640 if (readMagnificationEnabledSettingsLocked(userState)) { 5641 onUserStateChangedLocked(userState); 5642 } 5643 } else if (Flags.enableMagnificationMultipleFingerMultipleTapGesture() 5644 && mMagnificationTwoFingerTripleTapEnabledUri.equals(uri)) { 5645 if (readMagnificationTwoFingerTripleTapSettingsLocked(userState)) { 5646 onUserStateChangedLocked(userState); 5647 } 5648 } else if (mAutoclickEnabledUri.equals(uri)) { 5649 if (readAutoclickEnabledSettingLocked(userState)) { 5650 onUserStateChangedLocked(userState); 5651 } 5652 } else if (mEnabledAccessibilityServicesUri.equals(uri)) { 5653 if (readEnabledAccessibilityServicesLocked(userState)) { 5654 mSecurityPolicy.onEnabledServicesChangedLocked(userState.mUserId, 5655 userState.mEnabledServices); 5656 userState.removeDisabledServicesFromTemporaryStatesLocked(); 5657 onUserStateChangedLocked(userState); 5658 } 5659 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { 5660 if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) { 5661 onUserStateChangedLocked(userState); 5662 } 5663 } else if (mHighTextContrastUri.equals(uri)) { 5664 if (readHighTextContrastEnabledSettingLocked(userState)) { 5665 onUserStateChangedLocked(userState); 5666 } 5667 } else if (mAudioDescriptionByDefaultUri.equals(uri)) { 5668 if (readAudioDescriptionEnabledSettingLocked(userState)) { 5669 onUserStateChangedLocked(userState); 5670 } 5671 } else if (mAccessibilitySoftKeyboardModeUri.equals(uri) 5672 || mShowImeWithHardKeyboardUri.equals(uri)) { 5673 userState.reconcileSoftKeyboardModeWithSettingsLocked(); 5674 } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) { 5675 if (readAccessibilityShortcutKeySettingLocked(userState)) { 5676 onUserStateChangedLocked(userState); 5677 } 5678 } else if (mAccessibilityButtonComponentIdUri.equals(uri)) { 5679 if (readAccessibilityButtonTargetComponentLocked(userState)) { 5680 onUserStateChangedLocked(userState); 5681 } 5682 } else if (mAccessibilityButtonTargetsUri.equals(uri)) { 5683 if (readAccessibilityButtonTargetsLocked(userState)) { 5684 onUserStateChangedLocked(userState); 5685 } 5686 } else if (mUserNonInteractiveUiTimeoutUri.equals(uri) 5687 || mUserInteractiveUiTimeoutUri.equals(uri)) { 5688 readUserRecommendedUiTimeoutSettingsLocked(userState); 5689 } else if (mMagnificationModeUri.equals(uri)) { 5690 if (readMagnificationModeForDefaultDisplayLocked(userState)) { 5691 updateMagnificationModeChangeSettingsLocked(userState, 5692 Display.DEFAULT_DISPLAY); 5693 } 5694 } else if (mMagnificationCapabilityUri.equals(uri)) { 5695 if (readMagnificationCapabilitiesLocked(userState)) { 5696 updateMagnificationCapabilitiesSettingsChangeLocked(userState); 5697 } 5698 } else if (mMagnificationFollowTypingUri.equals(uri)) { 5699 readMagnificationFollowTypingLocked(userState); 5700 } else if (mAlwaysOnMagnificationUri.equals(uri)) { 5701 readAlwaysOnMagnificationLocked(userState); 5702 } 5703 } 5704 } 5705 } 5706 updateMagnificationCapabilitiesSettingsChangeLocked( AccessibilityUserState userState)5707 private void updateMagnificationCapabilitiesSettingsChangeLocked( 5708 AccessibilityUserState userState) { 5709 final ArrayList<Display> displays = getValidDisplayList(); 5710 for (int i = 0; i < displays.size(); i++) { 5711 final int displayId = displays.get(i).getDisplayId(); 5712 if (fallBackMagnificationModeSettingsLocked(userState, displayId)) { 5713 updateMagnificationModeChangeSettingsLocked(userState, displayId); 5714 } 5715 } 5716 updateMagnificationConnectionIfNeeded(userState); 5717 // Remove magnification button UI when the magnification capability is not all mode or 5718 // magnification is disabled. 5719 if (!(userState.isMagnificationSingleFingerTripleTapEnabledLocked() 5720 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() 5721 && userState.isMagnificationTwoFingerTripleTapEnabledLocked()) 5722 || userState.isShortcutMagnificationEnabledLocked()) 5723 || userState.getMagnificationCapabilitiesLocked() 5724 != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { 5725 5726 for (int i = 0; i < displays.size(); i++) { 5727 final int displayId = displays.get(i).getDisplayId(); 5728 getMagnificationConnectionManager().removeMagnificationButton(displayId); 5729 } 5730 } 5731 } 5732 fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState, int displayId)5733 private boolean fallBackMagnificationModeSettingsLocked(AccessibilityUserState userState, 5734 int displayId) { 5735 if (userState.isValidMagnificationModeLocked(displayId)) { 5736 return false; 5737 } 5738 Slog.w(LOG_TAG, "displayId " + displayId + ", invalid magnification mode:" 5739 + userState.getMagnificationModeLocked(displayId)); 5740 final int capabilities = userState.getMagnificationCapabilitiesLocked(); 5741 userState.setMagnificationModeLocked(displayId, capabilities); 5742 if (displayId == Display.DEFAULT_DISPLAY) { 5743 persistMagnificationModeSettingsLocked(capabilities); 5744 } 5745 return true; 5746 } 5747 persistMagnificationModeSettingsLocked(int mode)5748 private void persistMagnificationModeSettingsLocked(int mode) { 5749 BackgroundThread.getHandler().post(() -> { 5750 final long identity = Binder.clearCallingIdentity(); 5751 try { 5752 Settings.Secure.putIntForUser(mContext.getContentResolver(), 5753 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, mode, mCurrentUserId); 5754 } finally { 5755 Binder.restoreCallingIdentity(identity); 5756 } 5757 }); 5758 } 5759 5760 /** 5761 * Gets the magnification mode of the specified display. 5762 * 5763 * @param displayId The logical displayId. 5764 * @return magnification mode. It's either ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN or 5765 * ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW. 5766 */ getMagnificationMode(int displayId)5767 public int getMagnificationMode(int displayId) { 5768 synchronized (mLock) { 5769 return getCurrentUserStateLocked().getMagnificationModeLocked(displayId); 5770 } 5771 } 5772 5773 // Only the value of the default display is from user settings because not each of displays has 5774 // a unique id. readMagnificationModeForDefaultDisplayLocked(AccessibilityUserState userState)5775 private boolean readMagnificationModeForDefaultDisplayLocked(AccessibilityUserState userState) { 5776 final int magnificationMode = Settings.Secure.getIntForUser( 5777 mContext.getContentResolver(), 5778 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 5779 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); 5780 if (magnificationMode != userState.getMagnificationModeLocked(Display.DEFAULT_DISPLAY)) { 5781 userState.setMagnificationModeLocked(Display.DEFAULT_DISPLAY, magnificationMode); 5782 return true; 5783 } 5784 return false; 5785 } 5786 readMagnificationCapabilitiesLocked(AccessibilityUserState userState)5787 private boolean readMagnificationCapabilitiesLocked(AccessibilityUserState userState) { 5788 final int capabilities = Settings.Secure.getIntForUser( 5789 mContext.getContentResolver(), 5790 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY, 5791 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, userState.mUserId); 5792 if (capabilities != userState.getMagnificationCapabilitiesLocked()) { 5793 userState.setMagnificationCapabilitiesLocked(capabilities); 5794 mMagnificationController.setMagnificationCapabilities(capabilities); 5795 return true; 5796 } 5797 return false; 5798 } 5799 readMagnificationFollowTypingLocked(AccessibilityUserState userState)5800 boolean readMagnificationFollowTypingLocked(AccessibilityUserState userState) { 5801 final boolean followTypeEnabled = Settings.Secure.getIntForUser( 5802 mContext.getContentResolver(), 5803 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED, 5804 1, userState.mUserId) == 1; 5805 if (followTypeEnabled != userState.isMagnificationFollowTypingEnabled()) { 5806 userState.setMagnificationFollowTypingEnabled(followTypeEnabled); 5807 mMagnificationController.setMagnificationFollowTypingEnabled(followTypeEnabled); 5808 return true; 5809 } 5810 return false; 5811 } 5812 5813 /** 5814 * Called when always on magnification feature flag flips to check if the feature should be 5815 * enabled for current user state. 5816 */ updateAlwaysOnMagnification()5817 public void updateAlwaysOnMagnification() { 5818 synchronized (mLock) { 5819 readAlwaysOnMagnificationLocked(getCurrentUserState()); 5820 } 5821 } 5822 5823 @GuardedBy("mLock") readAlwaysOnMagnificationLocked(AccessibilityUserState userState)5824 boolean readAlwaysOnMagnificationLocked(AccessibilityUserState userState) { 5825 final boolean isSettingsAlwaysOnEnabled = Settings.Secure.getIntForUser( 5826 mContext.getContentResolver(), 5827 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, 5828 1, userState.mUserId) == 1; 5829 final boolean isAlwaysOnFeatureFlagEnabled = mMagnificationController 5830 .isAlwaysOnMagnificationFeatureFlagEnabled(); 5831 final boolean isAlwaysOnEnabled = isAlwaysOnFeatureFlagEnabled && isSettingsAlwaysOnEnabled; 5832 if (isAlwaysOnEnabled != userState.isAlwaysOnMagnificationEnabled()) { 5833 userState.setAlwaysOnMagnificationEnabled(isAlwaysOnEnabled); 5834 mMagnificationController.setAlwaysOnMagnificationEnabled(isAlwaysOnEnabled); 5835 return true; 5836 } 5837 return false; 5838 } 5839 5840 @Override setGestureDetectionPassthroughRegion(int displayId, Region region)5841 public void setGestureDetectionPassthroughRegion(int displayId, Region region) { 5842 mMainHandler.sendMessage( 5843 obtainMessage( 5844 AccessibilityManagerService::setGestureDetectionPassthroughRegionInternal, 5845 this, 5846 displayId, 5847 region)); 5848 } 5849 5850 @Override setTouchExplorationPassthroughRegion(int displayId, Region region)5851 public void setTouchExplorationPassthroughRegion(int displayId, Region region) { 5852 mMainHandler.sendMessage( 5853 obtainMessage( 5854 AccessibilityManagerService::setTouchExplorationPassthroughRegionInternal, 5855 this, 5856 displayId, 5857 region)); 5858 } 5859 setTouchExplorationPassthroughRegionInternal(int displayId, Region region)5860 private void setTouchExplorationPassthroughRegionInternal(int displayId, Region region) { 5861 synchronized (mLock) { 5862 if (mHasInputFilter && mInputFilter != null) { 5863 mInputFilter.setTouchExplorationPassthroughRegion(displayId, region); 5864 } 5865 } 5866 } 5867 setGestureDetectionPassthroughRegionInternal(int displayId, Region region)5868 private void setGestureDetectionPassthroughRegionInternal(int displayId, Region region) { 5869 synchronized (mLock) { 5870 if (mHasInputFilter && mInputFilter != null) { 5871 mInputFilter.setGestureDetectionPassthroughRegion(displayId, region); 5872 } 5873 } 5874 } 5875 5876 @Override setServiceDetectsGesturesEnabled(int displayId, boolean mode)5877 public void setServiceDetectsGesturesEnabled(int displayId, boolean mode) { 5878 mMainHandler.sendMessage( 5879 obtainMessage(AccessibilityManagerService::setServiceDetectsGesturesInternal, this, 5880 displayId, mode)); 5881 } 5882 setServiceDetectsGesturesInternal(int displayId, boolean mode)5883 private void setServiceDetectsGesturesInternal(int displayId, boolean mode) { 5884 synchronized (mLock) { 5885 getCurrentUserStateLocked().setServiceDetectsGesturesEnabled(displayId, mode); 5886 if (mHasInputFilter && mInputFilter != null) { 5887 mInputFilter.setServiceDetectsGesturesEnabled(displayId, mode); 5888 } 5889 } 5890 } 5891 5892 @Override requestTouchExploration(int displayId)5893 public void requestTouchExploration(int displayId) { 5894 mMainHandler.sendMessage(obtainMessage( 5895 AccessibilityManagerService::requestTouchExplorationInternal, this, displayId)); 5896 } 5897 requestTouchExplorationInternal(int displayId)5898 private void requestTouchExplorationInternal(int displayId) { 5899 synchronized (mLock) { 5900 if (mHasInputFilter && mInputFilter != null) { 5901 mInputFilter.requestTouchExploration(displayId); 5902 } 5903 } 5904 } 5905 5906 @Override requestDragging(int displayId, int pointerId)5907 public void requestDragging(int displayId, int pointerId) { 5908 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::requestDraggingInternal, 5909 this, displayId, pointerId)); 5910 } 5911 requestDraggingInternal(int displayId, int pointerId)5912 private void requestDraggingInternal(int displayId, int pointerId) { 5913 synchronized (mLock) { 5914 if (mHasInputFilter && mInputFilter != null) { 5915 mInputFilter.requestDragging(displayId, pointerId); 5916 } 5917 } 5918 } 5919 5920 @Override requestDelegating(int displayId)5921 public void requestDelegating(int displayId) { 5922 mMainHandler.sendMessage( 5923 obtainMessage( 5924 AccessibilityManagerService::requestDelegatingInternal, this, displayId)); 5925 } 5926 requestDelegatingInternal(int displayId)5927 private void requestDelegatingInternal(int displayId) { 5928 synchronized (mLock) { 5929 if (mHasInputFilter && mInputFilter != null) { 5930 mInputFilter.requestDelegating(displayId); 5931 } 5932 } 5933 } 5934 5935 @Override onDoubleTap(int displayId)5936 public void onDoubleTap(int displayId) { 5937 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapInternal, 5938 this, displayId)); 5939 } 5940 onDoubleTapInternal(int displayId)5941 private void onDoubleTapInternal(int displayId) { 5942 AccessibilityInputFilter inputFilter = null; 5943 synchronized (mLock) { 5944 if (mHasInputFilter && mInputFilter != null) { 5945 inputFilter = mInputFilter; 5946 } 5947 } 5948 if (inputFilter != null) { 5949 inputFilter.onDoubleTap(displayId); 5950 } 5951 } 5952 5953 @Override onDoubleTapAndHold(int displayId)5954 public void onDoubleTapAndHold(int displayId) { 5955 mMainHandler 5956 .sendMessage(obtainMessage(AccessibilityManagerService::onDoubleTapAndHoldInternal, 5957 this, displayId)); 5958 } 5959 5960 @Override requestImeLocked(AbstractAccessibilityServiceConnection connection)5961 public void requestImeLocked(AbstractAccessibilityServiceConnection connection) { 5962 if (!(connection instanceof AccessibilityServiceConnection) 5963 || (connection instanceof ProxyAccessibilityServiceConnection)) { 5964 if (DEBUG) { 5965 Slog.d(LOG_TAG, "The connection should be a real connection but was " 5966 + connection); 5967 } 5968 return; 5969 } 5970 AccessibilityServiceConnection realConnection = (AccessibilityServiceConnection) connection; 5971 mMainHandler.sendMessage(obtainMessage( 5972 AccessibilityManagerService::createSessionForConnection, this, realConnection)); 5973 mMainHandler.sendMessage(obtainMessage( 5974 AccessibilityManagerService::bindAndStartInputForConnection, this, realConnection)); 5975 } 5976 5977 @Override unbindImeLocked(AbstractAccessibilityServiceConnection connection)5978 public void unbindImeLocked(AbstractAccessibilityServiceConnection connection) { 5979 if (!(connection instanceof AccessibilityServiceConnection) 5980 || (connection instanceof ProxyAccessibilityServiceConnection)) { 5981 if (DEBUG) { 5982 Slog.d(LOG_TAG, "The connection should be a real connection but was " 5983 + connection); 5984 } 5985 return; 5986 } 5987 AccessibilityServiceConnection realConnection = (AccessibilityServiceConnection) connection; 5988 mMainHandler.sendMessage(obtainMessage( 5989 AccessibilityManagerService::unbindInputForConnection, this, realConnection)); 5990 } 5991 createSessionForConnection(AccessibilityServiceConnection connection)5992 private void createSessionForConnection(AccessibilityServiceConnection connection) { 5993 synchronized (mLock) { 5994 if (mInputSessionRequested) { 5995 connection.createImeSessionLocked(); 5996 } 5997 } 5998 } 5999 bindAndStartInputForConnection(AccessibilityServiceConnection connection)6000 private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) { 6001 synchronized (mLock) { 6002 if (mInputBound) { 6003 connection.bindInputLocked(); 6004 connection.startInputLocked(mRemoteInputConnection, mEditorInfo, mRestarting); 6005 } 6006 } 6007 } 6008 unbindInputForConnection(AccessibilityServiceConnection connection)6009 private void unbindInputForConnection(AccessibilityServiceConnection connection) { 6010 InputMethodManagerInternal.get() 6011 .unbindAccessibilityFromCurrentClient(connection.mId, connection.mUserId); 6012 synchronized (mLock) { 6013 connection.unbindInputLocked(); 6014 } 6015 } 6016 onDoubleTapAndHoldInternal(int displayId)6017 private void onDoubleTapAndHoldInternal(int displayId) { 6018 synchronized (mLock) { 6019 if (mHasInputFilter && mInputFilter != null) { 6020 mInputFilter.onDoubleTapAndHold(displayId); 6021 } 6022 } 6023 } 6024 updateFocusAppearanceDataLocked(AccessibilityUserState userState)6025 private void updateFocusAppearanceDataLocked(AccessibilityUserState userState) { 6026 if (userState.mUserId != mCurrentUserId) { 6027 return; 6028 } 6029 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_SERVICE_CLIENT)) { 6030 mTraceManager.logTrace(LOG_TAG + ".updateFocusAppearanceDataLocked", 6031 FLAGS_ACCESSIBILITY_SERVICE_CLIENT, "userState=" + userState); 6032 } 6033 mMainHandler.post(() -> { 6034 broadcastToClients(userState, ignoreRemoteException(client -> { 6035 if (!mProxyManager.isProxyedDeviceId(client.mDeviceId)) { 6036 client.mCallback.setFocusAppearance(userState.getFocusStrokeWidthLocked(), 6037 userState.getFocusColorLocked()); 6038 } 6039 })); 6040 }); 6041 6042 } 6043 getTraceManager()6044 public AccessibilityTraceManager getTraceManager() { 6045 return mTraceManager; 6046 } 6047 6048 /** 6049 * Bind input for accessibility services which request ime capabilities. 6050 */ scheduleBindInput()6051 public void scheduleBindInput() { 6052 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::bindInput, this)); 6053 } 6054 bindInput()6055 private void bindInput() { 6056 synchronized (mLock) { 6057 // Keep records of these in case new Accessibility Services are enabled. 6058 mInputBound = true; 6059 AccessibilityUserState userState = getCurrentUserStateLocked(); 6060 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 6061 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 6062 if (service.requestImeApis()) { 6063 service.bindInputLocked(); 6064 } 6065 } 6066 } 6067 } 6068 6069 /** 6070 * Unbind input for accessibility services which request ime capabilities. 6071 */ scheduleUnbindInput()6072 public void scheduleUnbindInput() { 6073 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::unbindInput, this)); 6074 } 6075 unbindInput()6076 private void unbindInput() { 6077 synchronized (mLock) { 6078 mInputBound = false; 6079 AccessibilityUserState userState = getCurrentUserStateLocked(); 6080 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 6081 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 6082 if (service.requestImeApis()) { 6083 service.unbindInputLocked(); 6084 } 6085 } 6086 } 6087 } 6088 6089 /** 6090 * Start input for accessibility services which request ime capabilities. 6091 */ scheduleStartInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, boolean restarting)6092 public void scheduleStartInput(IRemoteAccessibilityInputConnection connection, 6093 EditorInfo editorInfo, boolean restarting) { 6094 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::startInput, this, 6095 connection, editorInfo, restarting)); 6096 } 6097 startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, boolean restarting)6098 private void startInput(IRemoteAccessibilityInputConnection connection, EditorInfo editorInfo, 6099 boolean restarting) { 6100 synchronized (mLock) { 6101 // Keep records of these in case new Accessibility Services are enabled. 6102 mRemoteInputConnection = connection; 6103 mEditorInfo = editorInfo; 6104 mRestarting = restarting; 6105 AccessibilityUserState userState = getCurrentUserStateLocked(); 6106 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 6107 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 6108 if (service.requestImeApis()) { 6109 service.startInputLocked(connection, editorInfo, restarting); 6110 } 6111 } 6112 } 6113 } 6114 6115 /** 6116 * Request input sessions from all accessibility services which request ime capabilities and 6117 * whose id is not in the ignoreSet 6118 */ scheduleCreateImeSession(ArraySet<Integer> ignoreSet)6119 public void scheduleCreateImeSession(ArraySet<Integer> ignoreSet) { 6120 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::createImeSession, 6121 this, ignoreSet)); 6122 } 6123 createImeSession(ArraySet<Integer> ignoreSet)6124 private void createImeSession(ArraySet<Integer> ignoreSet) { 6125 synchronized (mLock) { 6126 mInputSessionRequested = true; 6127 AccessibilityUserState userState = getCurrentUserStateLocked(); 6128 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 6129 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 6130 if ((!ignoreSet.contains(service.mId)) && service.requestImeApis()) { 6131 service.createImeSessionLocked(); 6132 } 6133 } 6134 } 6135 } 6136 6137 /** 6138 * Enable or disable the sessions. 6139 * 6140 * @param sessions Sessions to enable or disable. 6141 * @param enabled True if enable the sessions or false if disable the sessions. 6142 */ scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)6143 public void scheduleSetImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, 6144 boolean enabled) { 6145 mMainHandler.sendMessage(obtainMessage(AccessibilityManagerService::setImeSessionEnabled, 6146 this, sessions, enabled)); 6147 } 6148 setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, boolean enabled)6149 private void setImeSessionEnabled(SparseArray<IAccessibilityInputMethodSession> sessions, 6150 boolean enabled) { 6151 synchronized (mLock) { 6152 AccessibilityUserState userState = getCurrentUserStateLocked(); 6153 for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) { 6154 final AccessibilityServiceConnection service = userState.mBoundServices.get(i); 6155 if (sessions.contains(service.mId) && service.requestImeApis()) { 6156 service.setImeSessionEnabledLocked(sessions.get(service.mId), enabled); 6157 } 6158 } 6159 } 6160 } 6161 6162 @Override 6163 @EnforcePermission(INJECT_EVENTS) injectInputEventToInputFilter(InputEvent event)6164 public void injectInputEventToInputFilter(InputEvent event) { 6165 injectInputEventToInputFilter_enforcePermission(); 6166 synchronized (mLock) { 6167 final long endMillis = 6168 SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS; 6169 while (!mInputFilterInstalled && (SystemClock.uptimeMillis() < endMillis)) { 6170 try { 6171 mLock.wait(endMillis - SystemClock.uptimeMillis()); 6172 } catch (InterruptedException ie) { 6173 /* ignore */ 6174 } 6175 } 6176 } 6177 6178 if (mInputFilterInstalled && mInputFilter != null) { 6179 mInputFilter.onInputEvent(event, 6180 WindowManagerPolicy.FLAG_PASS_TO_USER | WindowManagerPolicy.FLAG_INJECTED); 6181 } else { 6182 Slog.w(LOG_TAG, "Cannot injectInputEventToInputFilter because the " 6183 + "AccessibilityInputFilter is not installed."); 6184 } 6185 } 6186 6187 private final class SendWindowStateChangedEventRunnable implements Runnable { 6188 6189 private final AccessibilityEvent mPendingEvent; 6190 private final int mWindowId; 6191 SendWindowStateChangedEventRunnable(@onNull AccessibilityEvent event)6192 SendWindowStateChangedEventRunnable(@NonNull AccessibilityEvent event) { 6193 mPendingEvent = event; 6194 mWindowId = event.getWindowId(); 6195 } 6196 6197 @Override run()6198 public void run() { 6199 synchronized (mLock) { 6200 Slog.w(LOG_TAG, " wait for adding window timeout: " + mWindowId); 6201 sendPendingEventLocked(); 6202 } 6203 } 6204 sendPendingEventLocked()6205 private void sendPendingEventLocked() { 6206 mSendWindowStateChangedEventRunnables.remove(this); 6207 dispatchAccessibilityEventLocked(mPendingEvent); 6208 } 6209 getWindowId()6210 private int getWindowId() { 6211 return mWindowId; 6212 } 6213 } 6214 6215 @VisibleForTesting 6216 public static class ManagerPackageMonitor extends PackageMonitor { 6217 private final AccessibilityManagerService mManagerService; ManagerPackageMonitor(AccessibilityManagerService managerService)6218 public ManagerPackageMonitor(AccessibilityManagerService managerService) { 6219 super(/* supportsPackageRestartQuery = */ true); 6220 mManagerService = managerService; 6221 } 6222 6223 @Override onSomePackagesChanged()6224 public void onSomePackagesChanged() { 6225 if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes( 6226 FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 6227 mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onSomePackagesChanged", 6228 FLAGS_PACKAGE_BROADCAST_RECEIVER); 6229 } 6230 6231 final int userId = getChangingUserId(); 6232 List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService 6233 .parseAccessibilityServiceInfos(userId); 6234 List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = mManagerService 6235 .parseAccessibilityShortcutInfos(userId); 6236 synchronized (mManagerService.getLock()) { 6237 // Only the profile parent can install accessibility services. 6238 // Therefore we ignore packages from linked profiles. 6239 if (userId != mManagerService.getCurrentUserIdLocked()) { 6240 return; 6241 } 6242 6243 // Only continue setting up the packages if the service has been initialized. 6244 // See: b/340927041 6245 if (Flags.skipPackageChangeBeforeUserSwitch() 6246 && !mManagerService.isServiceInitializedLocked()) { 6247 Slog.w(LOG_TAG, 6248 "onSomePackagesChanged: service not initialized, skip the callback."); 6249 return; 6250 } 6251 mManagerService.onSomePackagesChangedLocked(parsedAccessibilityServiceInfos, 6252 parsedAccessibilityShortcutInfos); 6253 } 6254 } 6255 6256 @Override onPackageUpdateFinished(String packageName, int uid)6257 public void onPackageUpdateFinished(String packageName, int uid) { 6258 // The package should already be removed from mBoundServices, and added into 6259 // mBindingServices in binderDied() during updating. Remove services from this 6260 // package from mBindingServices, and then update the user state to re-bind new 6261 // versions of them. 6262 if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes( 6263 FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 6264 mManagerService.mTraceManager.logTrace( 6265 LOG_TAG + ".PM.onPackageUpdateFinished", 6266 FLAGS_PACKAGE_BROADCAST_RECEIVER, 6267 "packageName=" + packageName + ";uid=" + uid); 6268 } 6269 final int userId = getChangingUserId(); 6270 List<AccessibilityServiceInfo> parsedAccessibilityServiceInfos = mManagerService 6271 .parseAccessibilityServiceInfos(userId); 6272 List<AccessibilityShortcutInfo> parsedAccessibilityShortcutInfos = 6273 mManagerService.parseAccessibilityShortcutInfos(userId); 6274 synchronized (mManagerService.getLock()) { 6275 if (userId != mManagerService.getCurrentUserIdLocked()) { 6276 return; 6277 } 6278 final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId); 6279 final boolean reboundAService = userState.getBindingServicesLocked().removeIf( 6280 component -> component != null 6281 && component.getPackageName().equals(packageName)) 6282 || userState.mCrashedServices.removeIf(component -> component != null 6283 && component.getPackageName().equals(packageName)); 6284 // Reloads the installed services info to make sure the rebound service could 6285 // get a new one. 6286 userState.mInstalledServices.clear(); 6287 final boolean configurationChanged; 6288 configurationChanged = mManagerService.readConfigurationForUserStateLocked( 6289 userState, parsedAccessibilityServiceInfos, 6290 parsedAccessibilityShortcutInfos); 6291 if (reboundAService || configurationChanged) { 6292 mManagerService.onUserStateChangedLocked(userState); 6293 } 6294 // Passing 0 for restoreFromSdkInt to have this migration check execute each 6295 // time. It can make sure a11y button settings are correctly if there's an a11y 6296 // service updated and modifies the a11y button configuration. 6297 mManagerService.migrateAccessibilityButtonSettingsIfNecessaryLocked( 6298 userState, packageName, /* restoreFromSdkInt = */0); 6299 } 6300 } 6301 6302 @Override onPackageRemoved(String packageName, int uid)6303 public void onPackageRemoved(String packageName, int uid) { 6304 if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes( 6305 FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 6306 mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onPackageRemoved", 6307 FLAGS_PACKAGE_BROADCAST_RECEIVER, 6308 "packageName=" + packageName + ";uid=" + uid); 6309 } 6310 6311 synchronized (mManagerService.getLock()) { 6312 final int userId = getChangingUserId(); 6313 // Only the profile parent can install accessibility services. 6314 // Therefore we ignore packages from linked profiles. 6315 if (userId != mManagerService.getCurrentUserIdLocked()) { 6316 return; 6317 } 6318 mManagerService.onPackageRemovedLocked(packageName); 6319 } 6320 } 6321 6322 /** 6323 * Handles instances in which a package or packages have forcibly stopped. 6324 * 6325 * @param intent intent containing package event information. 6326 * @param uid linux process user id (different from Android user id). 6327 * @param packages array of package names that have stopped. 6328 * @param doit whether to try and handle the stop or just log the trace. 6329 * 6330 * @return {@code true} if doit == {@code false} 6331 * and at least one of the provided packages is enabled. 6332 * In any other case, returns {@code false}. 6333 * This is to indicate whether further action is necessary. 6334 */ 6335 @Override onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit)6336 public boolean onHandleForceStop(Intent intent, String[] packages, 6337 int uid, boolean doit) { 6338 if (mManagerService.mTraceManager.isA11yTracingEnabledForTypes( 6339 FLAGS_PACKAGE_BROADCAST_RECEIVER)) { 6340 mManagerService.mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop", 6341 FLAGS_PACKAGE_BROADCAST_RECEIVER, 6342 "intent=" + intent + ";packages=" + Arrays.toString(packages) 6343 + ";uid=" + uid + ";doit=" + doit); 6344 } 6345 synchronized (mManagerService.getLock()) { 6346 final int userId = getChangingUserId(); 6347 // Only the profile parent can install accessibility services. 6348 // Therefore we ignore packages from linked profiles. 6349 if (userId != mManagerService.getCurrentUserIdLocked()) { 6350 return false; 6351 } 6352 final AccessibilityUserState userState = mManagerService.getUserStateLocked(userId); 6353 6354 if (Flags.managerPackageMonitorLogicFix()) { 6355 if (!doit) { 6356 // if we're not handling the stop here, then we only need to know 6357 // if any of the force-stopped packages are currently enabled. 6358 return userState.mEnabledServices.stream().anyMatch( 6359 (comp) -> Arrays.stream(packages).anyMatch( 6360 (pkg) -> pkg.equals(comp.getPackageName())) 6361 ); 6362 } else if (mManagerService.onPackagesForceStoppedLocked(packages, userState)) { 6363 mManagerService.onUserStateChangedLocked(userState); 6364 } 6365 return false; 6366 } else { 6367 // this old logic did not properly indicate when base packageMonitor's routine 6368 // should handle stopping the package. 6369 if (doit && mManagerService.onPackagesForceStoppedLocked(packages, userState)) { 6370 mManagerService.onUserStateChangedLocked(userState); 6371 return false; 6372 } else { 6373 return true; 6374 } 6375 } 6376 } 6377 } 6378 6379 @Override onPackageChanged(String packageName, int uid, String[] components)6380 public boolean onPackageChanged(String packageName, int uid, String[] components) { 6381 // We care about all package changes, not just the whole package itself which is 6382 // default behavior. 6383 return true; 6384 } 6385 } 6386 sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId)6387 void sendPendingWindowStateChangedEventsForAvailableWindowLocked(int windowId) { 6388 final int eventSize = mSendWindowStateChangedEventRunnables.size(); 6389 for (int i = eventSize - 1; i >= 0; i--) { 6390 final SendWindowStateChangedEventRunnable runnable = 6391 mSendWindowStateChangedEventRunnables.get(i); 6392 if (runnable.getWindowId() == windowId) { 6393 mMainHandler.removeCallbacks(runnable); 6394 runnable.sendPendingEventLocked(); 6395 } 6396 } 6397 } 6398 6399 /** 6400 * Postpones the {@link AccessibilityEvent} with 6401 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED} 6402 * which doesn't have the corresponding window until the window is added or timeout. 6403 * 6404 * @return {@code true} if the event is postponed. 6405 */ postponeWindowStateEvent(AccessibilityEvent event)6406 private boolean postponeWindowStateEvent(AccessibilityEvent event) { 6407 synchronized (mLock) { 6408 final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked( 6409 event.getWindowId()); 6410 if (mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId) != null) { 6411 return false; 6412 } 6413 final SendWindowStateChangedEventRunnable pendingRunnable = 6414 new SendWindowStateChangedEventRunnable(new AccessibilityEvent(event)); 6415 mMainHandler.postDelayed(pendingRunnable, 6416 POSTPONE_WINDOW_STATE_CHANGED_EVENT_TIMEOUT_MILLIS); 6417 mSendWindowStateChangedEventRunnables.add(pendingRunnable); 6418 return true; 6419 } 6420 } 6421 6422 /** Used to attach accessibility overlays from the system itself i.e. magnification. */ 6423 @EnforcePermission(INTERNAL_SYSTEM_WINDOW) 6424 @Override attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc)6425 public void attachAccessibilityOverlayToDisplay(int displayId, SurfaceControl sc) { 6426 attachAccessibilityOverlayToDisplay_enforcePermission(); 6427 mMainHandler.sendMessage( 6428 obtainMessage( 6429 AccessibilityManagerService::attachAccessibilityOverlayToDisplayInternal, 6430 this, 6431 -1, 6432 displayId, 6433 sc, 6434 null)); 6435 } 6436 6437 /** Called by services to attach accessibility overlays. */ 6438 @Override attachAccessibilityOverlayToDisplay( int interactionId, int displayId, SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback)6439 public void attachAccessibilityOverlayToDisplay( 6440 int interactionId, 6441 int displayId, 6442 SurfaceControl sc, 6443 IAccessibilityInteractionConnectionCallback callback) { 6444 mMainHandler.sendMessage( 6445 obtainMessage( 6446 AccessibilityManagerService::attachAccessibilityOverlayToDisplayInternal, 6447 this, 6448 interactionId, 6449 displayId, 6450 sc, 6451 callback)); 6452 } 6453 attachAccessibilityOverlayToDisplayInternal( int interactionId, int displayId, SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback)6454 void attachAccessibilityOverlayToDisplayInternal( 6455 int interactionId, 6456 int displayId, 6457 SurfaceControl sc, 6458 IAccessibilityInteractionConnectionCallback callback) { 6459 int result; 6460 if (!mA11yOverlayLayers.contains(displayId)) { 6461 mA11yOverlayLayers.put(displayId, mWindowManagerService.getA11yOverlayLayer(displayId)); 6462 } 6463 SurfaceControl parent = mA11yOverlayLayers.get(displayId); 6464 if (parent == null) { 6465 Slog.e(LOG_TAG, "Unable to get accessibility overlay SurfaceControl."); 6466 mA11yOverlayLayers.remove(displayId); 6467 result = AccessibilityService.OVERLAY_RESULT_INVALID; 6468 } else { 6469 SurfaceControl.Transaction t = new SurfaceControl.Transaction(); 6470 t.reparent(sc, parent).setTrustedOverlay(sc, true).apply(); 6471 t.close(); 6472 result = AccessibilityService.OVERLAY_RESULT_SUCCESS; 6473 } 6474 6475 if (callback != null) { 6476 // Send the result back to the service. 6477 try { 6478 callback.sendAttachOverlayResult(result, interactionId); 6479 } catch (RemoteException re) { 6480 Slog.e(LOG_TAG, "Exception while attaching overlay.", re); 6481 // the other side will time out 6482 } 6483 } 6484 } 6485 6486 /** 6487 * Bypasses the timeout restriction if volume key shortcut assigned. 6488 */ skipVolumeShortcutDialogTimeoutRestriction(int userId)6489 private void skipVolumeShortcutDialogTimeoutRestriction(int userId) { 6490 persistIntToSetting( 6491 userId, 6492 Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION, 6493 /* true */ 1); 6494 } 6495 6496 /** 6497 * Log the metric when the user add/remove qs shortcut for accessibility features. Use the 6498 * callingUid to know where the users configure the a11y qs shortcuts. 6499 */ logMetricForQsShortcutConfiguration(boolean enable, int numOfFeatures)6500 private void logMetricForQsShortcutConfiguration(boolean enable, int numOfFeatures) { 6501 if (numOfFeatures <= 0) { 6502 // Skip logging metric if no a11y features are configured 6503 return; 6504 } 6505 String metricId = enable ? METRIC_ID_QS_SHORTCUT_ADD : METRIC_ID_QS_SHORTCUT_REMOVE; 6506 Counter.logIncrementWithUid(metricId, Binder.getCallingUid(), numOfFeatures); 6507 } 6508 } 6509