1 /* 2 ** Copyright 2009, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.server.accessibility; 18 19 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT; 20 21 import android.Manifest; 22 import android.accessibilityservice.AccessibilityService; 23 import android.accessibilityservice.AccessibilityServiceInfo; 24 import android.accessibilityservice.IAccessibilityServiceClient; 25 import android.accessibilityservice.IAccessibilityServiceConnection; 26 import android.app.AlertDialog; 27 import android.app.PendingIntent; 28 import android.app.StatusBarManager; 29 import android.content.BroadcastReceiver; 30 import android.content.ComponentName; 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.content.DialogInterface; 34 import android.content.DialogInterface.OnClickListener; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.ServiceConnection; 38 import android.content.pm.PackageManager; 39 import android.content.pm.ResolveInfo; 40 import android.content.pm.ServiceInfo; 41 import android.content.pm.UserInfo; 42 import android.database.ContentObserver; 43 import android.graphics.Point; 44 import android.graphics.Rect; 45 import android.graphics.Region; 46 import android.hardware.display.DisplayManager; 47 import android.hardware.input.InputManager; 48 import android.net.Uri; 49 import android.os.Binder; 50 import android.os.Build; 51 import android.os.Bundle; 52 import android.os.Handler; 53 import android.os.IBinder; 54 import android.os.Looper; 55 import android.os.Message; 56 import android.os.Process; 57 import android.os.RemoteCallbackList; 58 import android.os.RemoteException; 59 import android.os.ServiceManager; 60 import android.os.SystemClock; 61 import android.os.UserHandle; 62 import android.os.UserManager; 63 import android.provider.Settings; 64 import android.text.TextUtils; 65 import android.text.TextUtils.SimpleStringSplitter; 66 import android.util.Pools.Pool; 67 import android.util.Pools.SimplePool; 68 import android.util.Slog; 69 import android.util.SparseArray; 70 import android.view.Display; 71 import android.view.IWindow; 72 import android.view.InputDevice; 73 import android.view.InputEventConsistencyVerifier; 74 import android.view.KeyCharacterMap; 75 import android.view.KeyEvent; 76 import android.view.MagnificationSpec; 77 import android.view.WindowInfo; 78 import android.view.WindowManager; 79 import android.view.WindowManagerInternal; 80 import android.view.WindowManagerPolicy; 81 import android.view.accessibility.AccessibilityEvent; 82 import android.view.accessibility.AccessibilityInteractionClient; 83 import android.view.accessibility.AccessibilityManager; 84 import android.view.accessibility.AccessibilityNodeInfo; 85 import android.view.accessibility.AccessibilityWindowInfo; 86 import android.view.accessibility.IAccessibilityInteractionConnection; 87 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 88 import android.view.accessibility.IAccessibilityManager; 89 import android.view.accessibility.IAccessibilityManagerClient; 90 91 import com.android.internal.R; 92 import com.android.internal.content.PackageMonitor; 93 import com.android.internal.statusbar.IStatusBarService; 94 import com.android.internal.widget.LockPatternUtils; 95 import com.android.server.LocalServices; 96 97 import org.xmlpull.v1.XmlPullParserException; 98 99 import java.io.FileDescriptor; 100 import java.io.IOException; 101 import java.io.PrintWriter; 102 import java.util.ArrayList; 103 import java.util.Arrays; 104 import java.util.Collections; 105 import java.util.HashMap; 106 import java.util.HashSet; 107 import java.util.Iterator; 108 import java.util.List; 109 import java.util.Map; 110 import java.util.Set; 111 import java.util.concurrent.CopyOnWriteArrayList; 112 113 /** 114 * This class is instantiated by the system as a system level service and can be 115 * accessed only by the system. The task of this service is to be a centralized 116 * event dispatch for {@link AccessibilityEvent}s generated across all processes 117 * on the device. Events are dispatched to {@link AccessibilityService}s. 118 */ 119 public class AccessibilityManagerService extends IAccessibilityManager.Stub { 120 121 private static final boolean DEBUG = false; 122 123 private static final String LOG_TAG = "AccessibilityManagerService"; 124 125 // TODO: This is arbitrary. When there is time implement this by watching 126 // when that accessibility services are bound. 127 private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000; 128 129 private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000; 130 131 private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE = 132 "registerUiTestAutomationService"; 133 134 private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED = 135 "temporaryEnableAccessibilityStateUntilKeyguardRemoved"; 136 137 private static final String GET_WINDOW_TOKEN = "getWindowToken"; 138 139 private static final ComponentName sFakeAccessibilityServiceComponentName = 140 new ComponentName("foo.bar", "FakeService"); 141 142 private static final String FUNCTION_DUMP = "dump"; 143 144 private static final char COMPONENT_NAME_SEPARATOR = ':'; 145 146 private static final int OWN_PROCESS_ID = android.os.Process.myPid(); 147 148 private static final int MAX_POOL_SIZE = 10; 149 150 private static final int WINDOW_ID_UNKNOWN = -1; 151 152 private static int sIdCounter = 0; 153 154 private static int sNextWindowId; 155 156 private final Context mContext; 157 158 private final Object mLock = new Object(); 159 160 private final Pool<PendingEvent> mPendingEventPool = 161 new SimplePool<>(MAX_POOL_SIZE); 162 163 private final SimpleStringSplitter mStringColonSplitter = 164 new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); 165 166 private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = 167 new ArrayList<>(); 168 169 private final Region mTempRegion = new Region(); 170 171 private final Rect mTempRect = new Rect(); 172 173 private final Point mTempPoint = new Point(); 174 175 private final PackageManager mPackageManager; 176 177 private final WindowManagerInternal mWindowManagerService; 178 179 private final SecurityPolicy mSecurityPolicy; 180 181 private final MainHandler mMainHandler; 182 183 private InteractionBridge mInteractionBridge; 184 185 private AlertDialog mEnableTouchExplorationDialog; 186 187 private AccessibilityInputFilter mInputFilter; 188 189 private boolean mHasInputFilter; 190 191 private final Set<ComponentName> mTempComponentNameSet = new HashSet<>(); 192 193 private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList = 194 new ArrayList<>(); 195 196 private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients = 197 new RemoteCallbackList<>(); 198 199 private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections = 200 new SparseArray<>(); 201 202 private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>(); 203 204 private final SparseArray<UserState> mUserStates = new SparseArray<>(); 205 206 private final UserManager mUserManager; 207 208 private final LockPatternUtils mLockPatternUtils; 209 210 private int mCurrentUserId = UserHandle.USER_OWNER; 211 212 //TODO: Remove this hack 213 private boolean mInitialized; 214 215 private WindowsForAccessibilityCallback mWindowsForAccessibilityCallback; 216 getCurrentUserStateLocked()217 private UserState getCurrentUserStateLocked() { 218 return getUserStateLocked(mCurrentUserId); 219 } 220 221 /** 222 * Creates a new instance. 223 * 224 * @param context A {@link Context} instance. 225 */ AccessibilityManagerService(Context context)226 public AccessibilityManagerService(Context context) { 227 mContext = context; 228 mPackageManager = mContext.getPackageManager(); 229 mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); 230 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 231 mSecurityPolicy = new SecurityPolicy(); 232 mMainHandler = new MainHandler(mContext.getMainLooper()); 233 mLockPatternUtils = new LockPatternUtils(context); 234 registerBroadcastReceivers(); 235 new AccessibilityContentObserver(mMainHandler).register( 236 context.getContentResolver()); 237 } 238 getUserStateLocked(int userId)239 private UserState getUserStateLocked(int userId) { 240 UserState state = mUserStates.get(userId); 241 if (state == null) { 242 state = new UserState(userId); 243 mUserStates.put(userId, state); 244 } 245 return state; 246 } 247 registerBroadcastReceivers()248 private void registerBroadcastReceivers() { 249 PackageMonitor monitor = new PackageMonitor() { 250 @Override 251 public void onSomePackagesChanged() { 252 synchronized (mLock) { 253 // Only the profile parent can install accessibility services. 254 // Therefore we ignore packages from linked profiles. 255 if (getChangingUserId() != mCurrentUserId) { 256 return; 257 } 258 // We will update when the automation service dies. 259 UserState userState = getCurrentUserStateLocked(); 260 // We have to reload the installed services since some services may 261 // have different attributes, resolve info (does not support equals), 262 // etc. Remove them then to force reload. Do it even if automation is 263 // running since when it goes away, we will have to reload as well. 264 userState.mInstalledServices.clear(); 265 if (userState.mUiAutomationService == null) { 266 if (readConfigurationForUserStateLocked(userState)) { 267 onUserStateChangedLocked(userState); 268 } 269 } 270 } 271 } 272 273 @Override 274 public void onPackageRemoved(String packageName, int uid) { 275 synchronized (mLock) { 276 final int userId = getChangingUserId(); 277 // Only the profile parent can install accessibility services. 278 // Therefore we ignore packages from linked profiles. 279 if (userId != mCurrentUserId) { 280 return; 281 } 282 UserState userState = getUserStateLocked(userId); 283 Iterator<ComponentName> it = userState.mEnabledServices.iterator(); 284 while (it.hasNext()) { 285 ComponentName comp = it.next(); 286 String compPkg = comp.getPackageName(); 287 if (compPkg.equals(packageName)) { 288 it.remove(); 289 // Update the enabled services setting. 290 persistComponentNamesToSettingLocked( 291 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 292 userState.mEnabledServices, userId); 293 // Update the touch exploration granted services setting. 294 userState.mTouchExplorationGrantedServices.remove(comp); 295 persistComponentNamesToSettingLocked( 296 Settings.Secure. 297 TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 298 userState.mTouchExplorationGrantedServices, userId); 299 // We will update when the automation service dies. 300 if (userState.mUiAutomationService == null) { 301 onUserStateChangedLocked(userState); 302 } 303 return; 304 } 305 } 306 } 307 } 308 309 @Override 310 public boolean onHandleForceStop(Intent intent, String[] packages, 311 int uid, boolean doit) { 312 synchronized (mLock) { 313 final int userId = getChangingUserId(); 314 // Only the profile parent can install accessibility services. 315 // Therefore we ignore packages from linked profiles. 316 if (userId != mCurrentUserId) { 317 return false; 318 } 319 UserState userState = getUserStateLocked(userId); 320 Iterator<ComponentName> it = userState.mEnabledServices.iterator(); 321 while (it.hasNext()) { 322 ComponentName comp = it.next(); 323 String compPkg = comp.getPackageName(); 324 for (String pkg : packages) { 325 if (compPkg.equals(pkg)) { 326 if (!doit) { 327 return true; 328 } 329 it.remove(); 330 persistComponentNamesToSettingLocked( 331 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 332 userState.mEnabledServices, userId); 333 // We will update when the automation service dies. 334 if (userState.mUiAutomationService == null) { 335 onUserStateChangedLocked(userState); 336 } 337 } 338 } 339 } 340 return false; 341 } 342 } 343 }; 344 345 // package changes 346 monitor.register(mContext, null, UserHandle.ALL, true); 347 348 // user change and unlock 349 IntentFilter intentFilter = new IntentFilter(); 350 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 351 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 352 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 353 354 mContext.registerReceiverAsUser(new BroadcastReceiver() { 355 @Override 356 public void onReceive(Context context, Intent intent) { 357 String action = intent.getAction(); 358 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 359 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 360 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 361 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 362 } else if (Intent.ACTION_USER_PRESENT.equals(action)) { 363 // We will update when the automation service dies. 364 UserState userState = getCurrentUserStateLocked(); 365 if (userState.mUiAutomationService == null) { 366 if (readConfigurationForUserStateLocked(userState)) { 367 onUserStateChangedLocked(userState); 368 } 369 } 370 } 371 } 372 }, UserHandle.ALL, intentFilter, null, null); 373 } 374 375 @Override addClient(IAccessibilityManagerClient client, int userId)376 public int addClient(IAccessibilityManagerClient client, int userId) { 377 synchronized (mLock) { 378 // We treat calls from a profile as if made by its parent as profiles 379 // share the accessibility state of the parent. The call below 380 // performs the current profile parent resolution. 381 final int resolvedUserId = mSecurityPolicy 382 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 383 // If the client is from a process that runs across users such as 384 // the system UI or the system we add it to the global state that 385 // is shared across users. 386 UserState userState = getUserStateLocked(resolvedUserId); 387 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 388 mGlobalClients.register(client); 389 if (DEBUG) { 390 Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); 391 } 392 return userState.getClientState(); 393 } else { 394 userState.mClients.register(client); 395 // If this client is not for the current user we do not 396 // return a state since it is not for the foreground user. 397 // We will send the state to the client on a user switch. 398 if (DEBUG) { 399 Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid() 400 + " and userId:" + mCurrentUserId); 401 } 402 return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0; 403 } 404 } 405 } 406 407 @Override sendAccessibilityEvent(AccessibilityEvent event, int userId)408 public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) { 409 synchronized (mLock) { 410 // We treat calls from a profile as if made by its parent as profiles 411 // share the accessibility state of the parent. The call below 412 // performs the current profile parent resolution.. 413 final int resolvedUserId = mSecurityPolicy 414 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 415 // This method does nothing for a background user. 416 if (resolvedUserId != mCurrentUserId) { 417 return true; // yes, recycle the event 418 } 419 if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) { 420 mSecurityPolicy.updateActiveAndAccessibilityFocusedWindowLocked(event.getWindowId(), 421 event.getSourceNodeId(), event.getEventType()); 422 mSecurityPolicy.updateEventSourceLocked(event); 423 notifyAccessibilityServicesDelayedLocked(event, false); 424 notifyAccessibilityServicesDelayedLocked(event, true); 425 } 426 if (mHasInputFilter && mInputFilter != null) { 427 mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER, 428 AccessibilityEvent.obtain(event)).sendToTarget(); 429 } 430 event.recycle(); 431 getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0; 432 } 433 return (OWN_PROCESS_ID != Binder.getCallingPid()); 434 } 435 436 @Override getInstalledAccessibilityServiceList(int userId)437 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { 438 synchronized (mLock) { 439 // We treat calls from a profile as if made by its parent as profiles 440 // share the accessibility state of the parent. The call below 441 // performs the current profile parent resolution. 442 final int resolvedUserId = mSecurityPolicy 443 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 444 // The automation service is a fake one and should not be reported 445 // to clients as being installed - it really is not. 446 UserState userState = getUserStateLocked(resolvedUserId); 447 if (userState.mUiAutomationService != null) { 448 List<AccessibilityServiceInfo> installedServices = new ArrayList<>(); 449 installedServices.addAll(userState.mInstalledServices); 450 installedServices.remove(userState.mUiAutomationService.mAccessibilityServiceInfo); 451 return installedServices; 452 } 453 return userState.mInstalledServices; 454 } 455 } 456 457 @Override getEnabledAccessibilityServiceList(int feedbackType, int userId)458 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, 459 int userId) { 460 List<AccessibilityServiceInfo> result = null; 461 synchronized (mLock) { 462 // We treat calls from a profile as if made by its parent as profiles 463 // share the accessibility state of the parent. The call below 464 // performs the current profile parent resolution. 465 final int resolvedUserId = mSecurityPolicy 466 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 467 468 // The automation service is a fake one and should not be reported 469 // to clients as being enabled. The automation service is always the 470 // only active one, if it exists. 471 UserState userState = getUserStateLocked(resolvedUserId); 472 if (userState.mUiAutomationService != null) { 473 return Collections.emptyList(); 474 } 475 476 result = mEnabledServicesForFeedbackTempList; 477 result.clear(); 478 List<Service> services = userState.mBoundServices; 479 while (feedbackType != 0) { 480 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); 481 feedbackType &= ~feedbackTypeBit; 482 final int serviceCount = services.size(); 483 for (int i = 0; i < serviceCount; i++) { 484 Service service = services.get(i); 485 if ((service.mFeedbackType & feedbackTypeBit) != 0) { 486 result.add(service.mAccessibilityServiceInfo); 487 } 488 } 489 } 490 } 491 return result; 492 } 493 494 @Override interrupt(int userId)495 public void interrupt(int userId) { 496 CopyOnWriteArrayList<Service> services; 497 synchronized (mLock) { 498 // We treat calls from a profile as if made by its parent as profiles 499 // share the accessibility state of the parent. The call below 500 // performs the current profile parent resolution. 501 final int resolvedUserId = mSecurityPolicy 502 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 503 // This method does nothing for a background user. 504 if (resolvedUserId != mCurrentUserId) { 505 return; 506 } 507 services = getUserStateLocked(resolvedUserId).mBoundServices; 508 } 509 for (int i = 0, count = services.size(); i < count; i++) { 510 Service service = services.get(i); 511 try { 512 service.mServiceInterface.onInterrupt(); 513 } catch (RemoteException re) { 514 Slog.e(LOG_TAG, "Error during sending interrupt request to " 515 + service.mService, re); 516 } 517 } 518 } 519 520 @Override addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection, int userId)521 public int addAccessibilityInteractionConnection(IWindow windowToken, 522 IAccessibilityInteractionConnection connection, int userId) throws RemoteException { 523 synchronized (mLock) { 524 // We treat calls from a profile as if made by its parent as profiles 525 // share the accessibility state of the parent. The call below 526 // performs the current profile parent resolution. 527 final int resolvedUserId = mSecurityPolicy 528 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 529 final int windowId = sNextWindowId++; 530 // If the window is from a process that runs across users such as 531 // the system UI or the system we add it to the global state that 532 // is shared across users. 533 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 534 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( 535 windowId, connection, UserHandle.USER_ALL); 536 wrapper.linkToDeath(); 537 mGlobalInteractionConnections.put(windowId, wrapper); 538 mGlobalWindowTokens.put(windowId, windowToken.asBinder()); 539 if (DEBUG) { 540 Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid() 541 + " with windowId: " + windowId + " and token: " + windowToken.asBinder()); 542 } 543 } else { 544 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( 545 windowId, connection, resolvedUserId); 546 wrapper.linkToDeath(); 547 UserState userState = getUserStateLocked(resolvedUserId); 548 userState.mInteractionConnections.put(windowId, wrapper); 549 userState.mWindowTokens.put(windowId, windowToken.asBinder()); 550 if (DEBUG) { 551 Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid() 552 + " with windowId: " + windowId + " and userId:" + mCurrentUserId 553 + " and token: " + windowToken.asBinder()); 554 } 555 } 556 return windowId; 557 } 558 } 559 560 @Override removeAccessibilityInteractionConnection(IWindow window)561 public void removeAccessibilityInteractionConnection(IWindow window) { 562 synchronized (mLock) { 563 // We treat calls from a profile as if made by its parent as profiles 564 // share the accessibility state of the parent. The call below 565 // performs the current profile parent resolution. 566 mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( 567 UserHandle.getCallingUserId()); 568 IBinder token = window.asBinder(); 569 final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked( 570 token, mGlobalWindowTokens, mGlobalInteractionConnections); 571 if (removedWindowId >= 0) { 572 if (DEBUG) { 573 Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid() 574 + " with windowId: " + removedWindowId + " and token: " + window.asBinder()); 575 } 576 return; 577 } 578 final int userCount = mUserStates.size(); 579 for (int i = 0; i < userCount; i++) { 580 UserState userState = mUserStates.valueAt(i); 581 final int removedWindowIdForUser = 582 removeAccessibilityInteractionConnectionInternalLocked( 583 token, userState.mWindowTokens, userState.mInteractionConnections); 584 if (removedWindowIdForUser >= 0) { 585 if (DEBUG) { 586 Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid() 587 + " with windowId: " + removedWindowIdForUser + " and userId:" 588 + mUserStates.keyAt(i) + " and token: " + window.asBinder()); 589 } 590 return; 591 } 592 } 593 } 594 } 595 removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, SparseArray<IBinder> windowTokens, SparseArray<AccessibilityConnectionWrapper> interactionConnections)596 private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, 597 SparseArray<IBinder> windowTokens, 598 SparseArray<AccessibilityConnectionWrapper> interactionConnections) { 599 final int count = windowTokens.size(); 600 for (int i = 0; i < count; i++) { 601 if (windowTokens.valueAt(i) == windowToken) { 602 final int windowId = windowTokens.keyAt(i); 603 windowTokens.removeAt(i); 604 AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId); 605 wrapper.unlinkToDeath(); 606 interactionConnections.remove(windowId); 607 return windowId; 608 } 609 } 610 return -1; 611 } 612 613 @Override registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo)614 public void registerUiTestAutomationService(IBinder owner, 615 IAccessibilityServiceClient serviceClient, 616 AccessibilityServiceInfo accessibilityServiceInfo) { 617 mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, 618 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE); 619 620 accessibilityServiceInfo.setComponentName(sFakeAccessibilityServiceComponentName); 621 622 synchronized (mLock) { 623 UserState userState = getCurrentUserStateLocked(); 624 625 if (userState.mUiAutomationService != null) { 626 throw new IllegalStateException("UiAutomationService " + serviceClient 627 + "already registered!"); 628 } 629 630 try { 631 owner.linkToDeath(userState.mUiAutomationSerivceOnwerDeathRecipient, 0); 632 } catch (RemoteException re) { 633 Slog.e(LOG_TAG, "Couldn't register for the death of a" 634 + " UiTestAutomationService!", re); 635 return; 636 } 637 638 userState.mUiAutomationServiceOwner = owner; 639 userState.mUiAutomationServiceClient = serviceClient; 640 641 // Set the temporary state. 642 userState.mIsAccessibilityEnabled = true; 643 userState.mIsTouchExplorationEnabled = false; 644 userState.mIsEnhancedWebAccessibilityEnabled = false; 645 userState.mIsDisplayMagnificationEnabled = false; 646 userState.mInstalledServices.add(accessibilityServiceInfo); 647 userState.mEnabledServices.clear(); 648 userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName); 649 userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName); 650 651 // Use the new state instead of settings. 652 onUserStateChangedLocked(userState); 653 } 654 } 655 656 @Override unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)657 public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { 658 synchronized (mLock) { 659 UserState userState = getCurrentUserStateLocked(); 660 // Automation service is not bound, so pretend it died to perform clean up. 661 if (userState.mUiAutomationService != null 662 && serviceClient != null 663 && userState.mUiAutomationService.mServiceInterface != null 664 && userState.mUiAutomationService.mServiceInterface.asBinder() 665 == serviceClient.asBinder()) { 666 userState.mUiAutomationService.binderDied(); 667 } else { 668 throw new IllegalStateException("UiAutomationService " + serviceClient 669 + " not registered!"); 670 } 671 } 672 } 673 674 @Override temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled)675 public void temporaryEnableAccessibilityStateUntilKeyguardRemoved( 676 ComponentName service, boolean touchExplorationEnabled) { 677 mSecurityPolicy.enforceCallingPermission( 678 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY, 679 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED); 680 if (!mWindowManagerService.isKeyguardLocked()) { 681 return; 682 } 683 synchronized (mLock) { 684 // Set the temporary state. 685 UserState userState = getCurrentUserStateLocked(); 686 687 // This is a nop if UI automation is enabled. 688 if (userState.mUiAutomationService != null) { 689 return; 690 } 691 692 userState.mIsAccessibilityEnabled = true; 693 userState.mIsTouchExplorationEnabled = touchExplorationEnabled; 694 userState.mIsEnhancedWebAccessibilityEnabled = false; 695 userState.mIsDisplayMagnificationEnabled = false; 696 userState.mEnabledServices.clear(); 697 userState.mEnabledServices.add(service); 698 userState.mBindingServices.clear(); 699 userState.mTouchExplorationGrantedServices.clear(); 700 userState.mTouchExplorationGrantedServices.add(service); 701 702 // User the current state instead settings. 703 onUserStateChangedLocked(userState); 704 } 705 } 706 707 @Override getWindowToken(int windowId)708 public IBinder getWindowToken(int windowId) { 709 mSecurityPolicy.enforceCallingPermission( 710 Manifest.permission.RETRIEVE_WINDOW_TOKEN, 711 GET_WINDOW_TOKEN); 712 synchronized (mLock) { 713 // We treat calls from a profile as if made by its parent as profiles 714 // share the accessibility state of the parent. The call below 715 // performs the current profile parent resolution. 716 final int resolvedUserId = mSecurityPolicy 717 .resolveCallingUserIdEnforcingPermissionsLocked( 718 UserHandle.getCallingUserId()); 719 if (resolvedUserId != mCurrentUserId) { 720 return null; 721 } 722 if (mSecurityPolicy.findWindowById(windowId) == null) { 723 return null; 724 } 725 IBinder token = mGlobalWindowTokens.get(windowId); 726 if (token != null) { 727 return token; 728 } 729 return getCurrentUserStateLocked().mWindowTokens.get(windowId); 730 } 731 } 732 onGesture(int gestureId)733 boolean onGesture(int gestureId) { 734 synchronized (mLock) { 735 boolean handled = notifyGestureLocked(gestureId, false); 736 if (!handled) { 737 handled = notifyGestureLocked(gestureId, true); 738 } 739 return handled; 740 } 741 } 742 notifyKeyEvent(KeyEvent event, int policyFlags)743 boolean notifyKeyEvent(KeyEvent event, int policyFlags) { 744 synchronized (mLock) { 745 KeyEvent localClone = KeyEvent.obtain(event); 746 boolean handled = notifyKeyEventLocked(localClone, policyFlags, false); 747 if (!handled) { 748 handled = notifyKeyEventLocked(localClone, policyFlags, true); 749 } 750 return handled; 751 } 752 } 753 754 /** 755 * Gets a point within the accessibility focused node where we can send down 756 * and up events to perform a click. 757 * 758 * @param outPoint The click point to populate. 759 * @return Whether accessibility a click point was found and set. 760 */ 761 // TODO: (multi-display) Make sure this works for multiple displays. getAccessibilityFocusClickPointInScreen(Point outPoint)762 boolean getAccessibilityFocusClickPointInScreen(Point outPoint) { 763 return getInteractionBridgeLocked() 764 .getAccessibilityFocusClickPointInScreenNotLocked(outPoint); 765 } 766 767 /** 768 * Gets the bounds of the active window. 769 * 770 * @param outBounds The output to which to write the bounds. 771 */ getActiveWindowBounds(Rect outBounds)772 boolean getActiveWindowBounds(Rect outBounds) { 773 // TODO: This should be refactored to work with accessibility 774 // focus in multiple windows. 775 IBinder token; 776 synchronized (mLock) { 777 final int windowId = mSecurityPolicy.mActiveWindowId; 778 token = mGlobalWindowTokens.get(windowId); 779 if (token == null) { 780 token = getCurrentUserStateLocked().mWindowTokens.get(windowId); 781 } 782 } 783 mWindowManagerService.getWindowFrame(token, outBounds); 784 if (!outBounds.isEmpty()) { 785 return true; 786 } 787 return false; 788 } 789 accessibilityFocusOnlyInActiveWindow()790 boolean accessibilityFocusOnlyInActiveWindow() { 791 synchronized (mLock) { 792 return mWindowsForAccessibilityCallback == null; 793 } 794 } 795 getActiveWindowId()796 int getActiveWindowId() { 797 return mSecurityPolicy.getActiveWindowId(); 798 } 799 onTouchInteractionStart()800 void onTouchInteractionStart() { 801 mSecurityPolicy.onTouchInteractionStart(); 802 } 803 onTouchInteractionEnd()804 void onTouchInteractionEnd() { 805 mSecurityPolicy.onTouchInteractionEnd(); 806 } 807 onMagnificationStateChanged()808 void onMagnificationStateChanged() { 809 notifyClearAccessibilityCacheLocked(); 810 } 811 switchUser(int userId)812 private void switchUser(int userId) { 813 synchronized (mLock) { 814 if (mCurrentUserId == userId && mInitialized) { 815 return; 816 } 817 818 // Disconnect from services for the old user. 819 UserState oldUserState = getCurrentUserStateLocked(); 820 oldUserState.onSwitchToAnotherUser(); 821 822 // Disable the local managers for the old user. 823 if (oldUserState.mClients.getRegisteredCallbackCount() > 0) { 824 mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER, 825 oldUserState.mUserId, 0).sendToTarget(); 826 } 827 828 // Announce user changes only if more that one exist. 829 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 830 final boolean announceNewUser = userManager.getUsers().size() > 1; 831 832 // The user changed. 833 mCurrentUserId = userId; 834 835 UserState userState = getCurrentUserStateLocked(); 836 if (userState.mUiAutomationService != null) { 837 // Switching users disables the UI automation service. 838 userState.mUiAutomationService.binderDied(); 839 } 840 841 readConfigurationForUserStateLocked(userState); 842 // Even if reading did not yield change, we have to update 843 // the state since the context in which the current user 844 // state was used has changed since it was inactive. 845 onUserStateChangedLocked(userState); 846 847 if (announceNewUser) { 848 // Schedule announcement of the current user if needed. 849 mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED, 850 WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS); 851 } 852 } 853 } 854 removeUser(int userId)855 private void removeUser(int userId) { 856 synchronized (mLock) { 857 mUserStates.remove(userId); 858 } 859 } 860 getInteractionBridgeLocked()861 private InteractionBridge getInteractionBridgeLocked() { 862 if (mInteractionBridge == null) { 863 mInteractionBridge = new InteractionBridge(); 864 } 865 return mInteractionBridge; 866 } 867 notifyGestureLocked(int gestureId, boolean isDefault)868 private boolean notifyGestureLocked(int gestureId, boolean isDefault) { 869 // TODO: Now we are giving the gestures to the last enabled 870 // service that can handle them which is the last one 871 // in our list since we write the last enabled as the 872 // last record in the enabled services setting. Ideally, 873 // the user should make the call which service handles 874 // gestures. However, only one service should handle 875 // gestures to avoid user frustration when different 876 // behavior is observed from different combinations of 877 // enabled accessibility services. 878 UserState state = getCurrentUserStateLocked(); 879 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 880 Service service = state.mBoundServices.get(i); 881 if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) { 882 service.notifyGesture(gestureId); 883 return true; 884 } 885 } 886 return false; 887 } 888 notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault)889 private boolean notifyKeyEventLocked(KeyEvent event, int policyFlags, boolean isDefault) { 890 // TODO: Now we are giving the key events to the last enabled 891 // service that can handle them Ideally, the user should 892 // make the call which service handles key events. However, 893 // only one service should handle key events to avoid user 894 // frustration when different behavior is observed from 895 // different combinations of enabled accessibility services. 896 UserState state = getCurrentUserStateLocked(); 897 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 898 Service service = state.mBoundServices.get(i); 899 // Key events are handled only by services that declared 900 // this capability and requested to filter key events. 901 if (!service.mRequestFilterKeyEvents || 902 (service.mAccessibilityServiceInfo.getCapabilities() & AccessibilityServiceInfo 903 .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) { 904 continue; 905 } 906 if (service.mIsDefault == isDefault) { 907 service.notifyKeyEvent(event, policyFlags); 908 return true; 909 } 910 } 911 return false; 912 } 913 notifyClearAccessibilityCacheLocked()914 private void notifyClearAccessibilityCacheLocked() { 915 UserState state = getCurrentUserStateLocked(); 916 for (int i = state.mBoundServices.size() - 1; i >= 0; i--) { 917 Service service = state.mBoundServices.get(i); 918 service.notifyClearAccessibilityNodeInfoCache(); 919 } 920 } 921 922 /** 923 * Removes an AccessibilityInteractionConnection. 924 * 925 * @param windowId The id of the window to which the connection is targeted. 926 * @param userId The id of the user owning the connection. UserHandle.USER_ALL 927 * if global. 928 */ removeAccessibilityInteractionConnectionLocked(int windowId, int userId)929 private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) { 930 if (userId == UserHandle.USER_ALL) { 931 mGlobalWindowTokens.remove(windowId); 932 mGlobalInteractionConnections.remove(windowId); 933 } else { 934 UserState userState = getCurrentUserStateLocked(); 935 userState.mWindowTokens.remove(windowId); 936 userState.mInteractionConnections.remove(windowId); 937 } 938 if (DEBUG) { 939 Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); 940 } 941 } 942 readInstalledAccessibilityServiceLocked(UserState userState)943 private boolean readInstalledAccessibilityServiceLocked(UserState userState) { 944 mTempAccessibilityServiceInfoList.clear(); 945 946 List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( 947 new Intent(AccessibilityService.SERVICE_INTERFACE), 948 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 949 mCurrentUserId); 950 951 for (int i = 0, count = installedServices.size(); i < count; i++) { 952 ResolveInfo resolveInfo = installedServices.get(i); 953 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 954 if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals( 955 serviceInfo.permission)) { 956 Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName( 957 serviceInfo.packageName, serviceInfo.name).flattenToShortString() 958 + ": it does not require the permission " 959 + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE); 960 continue; 961 } 962 AccessibilityServiceInfo accessibilityServiceInfo; 963 try { 964 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); 965 mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo); 966 } catch (XmlPullParserException | IOException xppe) { 967 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); 968 } 969 } 970 971 if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) { 972 userState.mInstalledServices.clear(); 973 userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList); 974 mTempAccessibilityServiceInfoList.clear(); 975 return true; 976 } 977 978 mTempAccessibilityServiceInfoList.clear(); 979 return false; 980 } 981 readEnabledAccessibilityServicesLocked(UserState userState)982 private boolean readEnabledAccessibilityServicesLocked(UserState userState) { 983 mTempComponentNameSet.clear(); 984 readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 985 userState.mUserId, mTempComponentNameSet); 986 if (!mTempComponentNameSet.equals(userState.mEnabledServices)) { 987 userState.mEnabledServices.clear(); 988 userState.mEnabledServices.addAll(mTempComponentNameSet); 989 mTempComponentNameSet.clear(); 990 return true; 991 } 992 mTempComponentNameSet.clear(); 993 return false; 994 } 995 readTouchExplorationGrantedAccessibilityServicesLocked( UserState userState)996 private boolean readTouchExplorationGrantedAccessibilityServicesLocked( 997 UserState userState) { 998 mTempComponentNameSet.clear(); 999 readComponentNamesFromSettingLocked( 1000 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 1001 userState.mUserId, mTempComponentNameSet); 1002 if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) { 1003 userState.mTouchExplorationGrantedServices.clear(); 1004 userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet); 1005 mTempComponentNameSet.clear(); 1006 return true; 1007 } 1008 mTempComponentNameSet.clear(); 1009 return false; 1010 } 1011 1012 /** 1013 * Performs {@link AccessibilityService}s delayed notification. The delay is configurable 1014 * and denotes the period after the last event before notifying the service. 1015 * 1016 * @param event The event. 1017 * @param isDefault True to notify default listeners, not default services. 1018 */ notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)1019 private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, 1020 boolean isDefault) { 1021 try { 1022 UserState state = getCurrentUserStateLocked(); 1023 for (int i = 0, count = state.mBoundServices.size(); i < count; i++) { 1024 Service service = state.mBoundServices.get(i); 1025 1026 if (service.mIsDefault == isDefault) { 1027 if (canDispatchEventToServiceLocked(service, event, 1028 state.mHandledFeedbackTypes)) { 1029 state.mHandledFeedbackTypes |= service.mFeedbackType; 1030 service.notifyAccessibilityEvent(event); 1031 } 1032 } 1033 } 1034 } catch (IndexOutOfBoundsException oobe) { 1035 // An out of bounds exception can happen if services are going away 1036 // as the for loop is running. If that happens, just bail because 1037 // there are no more services to notify. 1038 } 1039 } 1040 addServiceLocked(Service service, UserState userState)1041 private void addServiceLocked(Service service, UserState userState) { 1042 try { 1043 service.linkToOwnDeathLocked(); 1044 userState.mBoundServices.add(service); 1045 userState.mComponentNameToServiceMap.put(service.mComponentName, service); 1046 } catch (RemoteException re) { 1047 /* do nothing */ 1048 } 1049 } 1050 1051 /** 1052 * Removes a service. 1053 * 1054 * @param service The service. 1055 */ removeServiceLocked(Service service, UserState userState)1056 private void removeServiceLocked(Service service, UserState userState) { 1057 userState.mBoundServices.remove(service); 1058 userState.mComponentNameToServiceMap.remove(service.mComponentName); 1059 service.unlinkToOwnDeathLocked(); 1060 } 1061 1062 /** 1063 * Determines if given event can be dispatched to a service based on the package of the 1064 * event source and already notified services for that event type. Specifically, a 1065 * service is notified if it is interested in events from the package and no other service 1066 * providing the same feedback type has been notified. Exception are services the 1067 * provide generic feedback (feedback type left as a safety net for unforeseen feedback 1068 * types) which are always notified. 1069 * 1070 * @param service The potential receiver. 1071 * @param event The event. 1072 * @param handledFeedbackTypes The feedback types for which services have been notified. 1073 * @return True if the listener should be notified, false otherwise. 1074 */ canDispatchEventToServiceLocked(Service service, AccessibilityEvent event, int handledFeedbackTypes)1075 private boolean canDispatchEventToServiceLocked(Service service, AccessibilityEvent event, 1076 int handledFeedbackTypes) { 1077 1078 if (!service.canReceiveEventsLocked()) { 1079 return false; 1080 } 1081 1082 if (event.getWindowId() != WINDOW_ID_UNKNOWN && !event.isImportantForAccessibility() 1083 && (service.mFetchFlags 1084 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 1085 return false; 1086 } 1087 1088 int eventType = event.getEventType(); 1089 if ((service.mEventTypes & eventType) != eventType) { 1090 return false; 1091 } 1092 1093 Set<String> packageNames = service.mPackageNames; 1094 String packageName = (event.getPackageName() != null) 1095 ? event.getPackageName().toString() : null; 1096 1097 if (packageNames.isEmpty() || packageNames.contains(packageName)) { 1098 int feedbackType = service.mFeedbackType; 1099 if ((handledFeedbackTypes & feedbackType) != feedbackType 1100 || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) { 1101 return true; 1102 } 1103 } 1104 1105 return false; 1106 } 1107 unbindAllServicesLocked(UserState userState)1108 private void unbindAllServicesLocked(UserState userState) { 1109 List<Service> services = userState.mBoundServices; 1110 for (int i = 0, count = services.size(); i < count; i++) { 1111 Service service = services.get(i); 1112 if (service.unbindLocked()) { 1113 i--; 1114 count--; 1115 } 1116 } 1117 } 1118 1119 /** 1120 * Populates a set with the {@link ComponentName}s stored in a colon 1121 * separated value setting for a given user. 1122 * 1123 * @param settingName The setting to parse. 1124 * @param userId The user id. 1125 * @param outComponentNames The output component names. 1126 */ readComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)1127 private void readComponentNamesFromSettingLocked(String settingName, int userId, 1128 Set<ComponentName> outComponentNames) { 1129 String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 1130 settingName, userId); 1131 outComponentNames.clear(); 1132 if (settingValue != null) { 1133 TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; 1134 splitter.setString(settingValue); 1135 while (splitter.hasNext()) { 1136 String str = splitter.next(); 1137 if (str == null || str.length() <= 0) { 1138 continue; 1139 } 1140 ComponentName enabledService = ComponentName.unflattenFromString(str); 1141 if (enabledService != null) { 1142 outComponentNames.add(enabledService); 1143 } 1144 } 1145 } 1146 } 1147 1148 /** 1149 * Persists the component names in the specified setting in a 1150 * colon separated fashion. 1151 * 1152 * @param settingName The setting name. 1153 * @param componentNames The component names. 1154 */ persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)1155 private void persistComponentNamesToSettingLocked(String settingName, 1156 Set<ComponentName> componentNames, int userId) { 1157 StringBuilder builder = new StringBuilder(); 1158 for (ComponentName componentName : componentNames) { 1159 if (builder.length() > 0) { 1160 builder.append(COMPONENT_NAME_SEPARATOR); 1161 } 1162 builder.append(componentName.flattenToShortString()); 1163 } 1164 Settings.Secure.putStringForUser(mContext.getContentResolver(), 1165 settingName, builder.toString(), userId); 1166 } 1167 manageServicesLocked(UserState userState)1168 private void manageServicesLocked(UserState userState) { 1169 Map<ComponentName, Service> componentNameToServiceMap = 1170 userState.mComponentNameToServiceMap; 1171 boolean isEnabled = userState.mIsAccessibilityEnabled; 1172 1173 for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { 1174 AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); 1175 ComponentName componentName = ComponentName.unflattenFromString( 1176 installedService.getId()); 1177 Service service = componentNameToServiceMap.get(componentName); 1178 1179 if (isEnabled) { 1180 // Wait for the binding if it is in process. 1181 if (userState.mBindingServices.contains(componentName)) { 1182 continue; 1183 } 1184 if (userState.mEnabledServices.contains(componentName)) { 1185 if (service == null) { 1186 service = new Service(userState.mUserId, componentName, installedService); 1187 } else if (userState.mBoundServices.contains(service)) { 1188 continue; 1189 } 1190 service.bindLocked(); 1191 } else { 1192 if (service != null) { 1193 service.unbindLocked(); 1194 } 1195 } 1196 } else { 1197 if (service != null) { 1198 service.unbindLocked(); 1199 } else { 1200 userState.mBindingServices.remove(componentName); 1201 } 1202 } 1203 } 1204 1205 // No enabled installed services => disable accessibility to avoid 1206 // sending accessibility events with no recipient across processes. 1207 if (isEnabled && userState.mBoundServices.isEmpty() 1208 && userState.mBindingServices.isEmpty()) { 1209 userState.mIsAccessibilityEnabled = false; 1210 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1211 Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId); 1212 } 1213 } 1214 scheduleUpdateClientsIfNeededLocked(UserState userState)1215 private void scheduleUpdateClientsIfNeededLocked(UserState userState) { 1216 final int clientState = userState.getClientState(); 1217 if (userState.mLastSentClientState != clientState 1218 && (mGlobalClients.getRegisteredCallbackCount() > 0 1219 || userState.mClients.getRegisteredCallbackCount() > 0)) { 1220 userState.mLastSentClientState = clientState; 1221 mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS, 1222 clientState, userState.mUserId) .sendToTarget(); 1223 } 1224 } 1225 scheduleUpdateInputFilter(UserState userState)1226 private void scheduleUpdateInputFilter(UserState userState) { 1227 mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_INPUT_FILTER, userState).sendToTarget(); 1228 } 1229 updateInputFilter(UserState userState)1230 private void updateInputFilter(UserState userState) { 1231 boolean setInputFilter = false; 1232 AccessibilityInputFilter inputFilter = null; 1233 synchronized (mLock) { 1234 int flags = 0; 1235 if (userState.mIsDisplayMagnificationEnabled) { 1236 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER; 1237 } 1238 // Touch exploration without accessibility makes no sense. 1239 if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) { 1240 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; 1241 } 1242 if (userState.mIsFilterKeyEventsEnabled) { 1243 flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; 1244 } 1245 if (flags != 0) { 1246 if (!mHasInputFilter) { 1247 mHasInputFilter = true; 1248 if (mInputFilter == null) { 1249 mInputFilter = new AccessibilityInputFilter(mContext, 1250 AccessibilityManagerService.this); 1251 } 1252 inputFilter = mInputFilter; 1253 setInputFilter = true; 1254 } 1255 mInputFilter.setEnabledFeatures(flags); 1256 } else { 1257 if (mHasInputFilter) { 1258 mHasInputFilter = false; 1259 mInputFilter.disableFeatures(); 1260 inputFilter = null; 1261 setInputFilter = true; 1262 } 1263 } 1264 } 1265 if (setInputFilter) { 1266 mWindowManagerService.setInputFilter(inputFilter); 1267 } 1268 } 1269 showEnableTouchExplorationDialog(final Service service)1270 private void showEnableTouchExplorationDialog(final Service service) { 1271 synchronized (mLock) { 1272 String label = service.mResolveInfo.loadLabel( 1273 mContext.getPackageManager()).toString(); 1274 1275 final UserState state = getCurrentUserStateLocked(); 1276 if (state.mIsTouchExplorationEnabled) { 1277 return; 1278 } 1279 if (mEnableTouchExplorationDialog != null 1280 && mEnableTouchExplorationDialog.isShowing()) { 1281 return; 1282 } 1283 mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) 1284 .setIconAttribute(android.R.attr.alertDialogIcon) 1285 .setPositiveButton(android.R.string.ok, new OnClickListener() { 1286 @Override 1287 public void onClick(DialogInterface dialog, int which) { 1288 // The user allowed the service to toggle touch exploration. 1289 state.mTouchExplorationGrantedServices.add(service.mComponentName); 1290 persistComponentNamesToSettingLocked( 1291 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 1292 state.mTouchExplorationGrantedServices, state.mUserId); 1293 // Enable touch exploration. 1294 UserState userState = getUserStateLocked(service.mUserId); 1295 userState.mIsTouchExplorationEnabled = true; 1296 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1297 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, 1298 service.mUserId); 1299 onUserStateChangedLocked(userState); 1300 } 1301 }) 1302 .setNegativeButton(android.R.string.cancel, new OnClickListener() { 1303 @Override 1304 public void onClick(DialogInterface dialog, int which) { 1305 dialog.dismiss(); 1306 } 1307 }) 1308 .setTitle(R.string.enable_explore_by_touch_warning_title) 1309 .setMessage(mContext.getString( 1310 R.string.enable_explore_by_touch_warning_message, label)) 1311 .create(); 1312 mEnableTouchExplorationDialog.getWindow().setType( 1313 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1314 mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags 1315 |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 1316 mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); 1317 mEnableTouchExplorationDialog.show(); 1318 } 1319 } 1320 onUserStateChangedLocked(UserState userState)1321 private void onUserStateChangedLocked(UserState userState) { 1322 // TODO: Remove this hack 1323 mInitialized = true; 1324 updateLegacyCapabilitiesLocked(userState); 1325 updateServicesLocked(userState); 1326 updateWindowsForAccessibilityCallbackLocked(userState); 1327 updateAccessibilityFocusBehaviorLocked(userState); 1328 updateFilterKeyEventsLocked(userState); 1329 updateTouchExplorationLocked(userState); 1330 updateEnhancedWebAccessibilityLocked(userState); 1331 updateDisplayColorAdjustmentSettingsLocked(userState); 1332 scheduleUpdateInputFilter(userState); 1333 scheduleUpdateClientsIfNeededLocked(userState); 1334 } 1335 updateAccessibilityFocusBehaviorLocked(UserState userState)1336 private void updateAccessibilityFocusBehaviorLocked(UserState userState) { 1337 // If there is no service that can operate with interactive windows 1338 // then we keep the old behavior where a window loses accessibility 1339 // focus if it is no longer active. This still changes the behavior 1340 // for services that do not operate with interactive windows and run 1341 // at the same time as the one(s) which does. In practice however, 1342 // there is only one service that uses accessibility focus and it 1343 // is typically the one that operates with interactive windows, So, 1344 // this is fine. Note that to allow a service to work across windows 1345 // we have to allow accessibility focus stay in any of them. Sigh... 1346 List<Service> boundServices = userState.mBoundServices; 1347 final int boundServiceCount = boundServices.size(); 1348 for (int i = 0; i < boundServiceCount; i++) { 1349 Service boundService = boundServices.get(i); 1350 if (boundService.canRetrieveInteractiveWindowsLocked()) { 1351 userState.mAccessibilityFocusOnlyInActiveWindow = false; 1352 return; 1353 } 1354 } 1355 userState.mAccessibilityFocusOnlyInActiveWindow = true; 1356 } 1357 updateWindowsForAccessibilityCallbackLocked(UserState userState)1358 private void updateWindowsForAccessibilityCallbackLocked(UserState userState) { 1359 if (userState.mIsAccessibilityEnabled) { 1360 // We observe windows for accessibility only if there is at least 1361 // one bound service that can retrieve window content that specified 1362 // it is interested in accessing such windows. For services that are 1363 // binding we do an update pass after each bind event, so we run this 1364 // code and register the callback if needed. 1365 boolean boundServiceCanRetrieveInteractiveWindows = false; 1366 1367 List<Service> boundServices = userState.mBoundServices; 1368 final int boundServiceCount = boundServices.size(); 1369 for (int i = 0; i < boundServiceCount; i++) { 1370 Service boundService = boundServices.get(i); 1371 if (boundService.canRetrieveInteractiveWindowsLocked()) { 1372 boundServiceCanRetrieveInteractiveWindows = true; 1373 break; 1374 } 1375 } 1376 1377 if (boundServiceCanRetrieveInteractiveWindows) { 1378 if (mWindowsForAccessibilityCallback == null) { 1379 mWindowsForAccessibilityCallback = new WindowsForAccessibilityCallback(); 1380 mWindowManagerService.setWindowsForAccessibilityCallback( 1381 mWindowsForAccessibilityCallback); 1382 } 1383 return; 1384 } 1385 } 1386 1387 if (mWindowsForAccessibilityCallback != null) { 1388 mWindowsForAccessibilityCallback = null; 1389 mWindowManagerService.setWindowsForAccessibilityCallback(null); 1390 // Drop all windows we know about. 1391 mSecurityPolicy.clearWindowsLocked(); 1392 } 1393 } 1394 updateLegacyCapabilitiesLocked(UserState userState)1395 private void updateLegacyCapabilitiesLocked(UserState userState) { 1396 // Up to JB-MR1 we had a white list with services that can enable touch 1397 // exploration. When a service is first started we show a dialog to the 1398 // use to get a permission to white list the service. 1399 final int installedServiceCount = userState.mInstalledServices.size(); 1400 for (int i = 0; i < installedServiceCount; i++) { 1401 AccessibilityServiceInfo serviceInfo = userState.mInstalledServices.get(i); 1402 ResolveInfo resolveInfo = serviceInfo.getResolveInfo(); 1403 if ((serviceInfo.getCapabilities() 1404 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) == 0 1405 && resolveInfo.serviceInfo.applicationInfo.targetSdkVersion 1406 <= Build.VERSION_CODES.JELLY_BEAN_MR1) { 1407 ComponentName componentName = new ComponentName( 1408 resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); 1409 if (userState.mTouchExplorationGrantedServices.contains(componentName)) { 1410 serviceInfo.setCapabilities(serviceInfo.getCapabilities() 1411 | AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION); 1412 } 1413 } 1414 } 1415 } 1416 updateFilterKeyEventsLocked(UserState userState)1417 private void updateFilterKeyEventsLocked(UserState userState) { 1418 final int serviceCount = userState.mBoundServices.size(); 1419 for (int i = 0; i < serviceCount; i++) { 1420 Service service = userState.mBoundServices.get(i); 1421 if (service.mRequestFilterKeyEvents 1422 && (service.mAccessibilityServiceInfo.getCapabilities() 1423 & AccessibilityServiceInfo 1424 .CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) != 0) { 1425 userState.mIsFilterKeyEventsEnabled = true; 1426 return; 1427 } 1428 } 1429 userState.mIsFilterKeyEventsEnabled = false; 1430 } 1431 updateServicesLocked(UserState userState)1432 private void updateServicesLocked(UserState userState) { 1433 if (userState.mIsAccessibilityEnabled) { 1434 manageServicesLocked(userState); 1435 } else { 1436 unbindAllServicesLocked(userState); 1437 } 1438 } 1439 readConfigurationForUserStateLocked(UserState userState)1440 private boolean readConfigurationForUserStateLocked(UserState userState) { 1441 boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState); 1442 somthingChanged |= readInstalledAccessibilityServiceLocked(userState); 1443 somthingChanged |= readEnabledAccessibilityServicesLocked(userState); 1444 somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState); 1445 somthingChanged |= readTouchExplorationEnabledSettingLocked(userState); 1446 somthingChanged |= readHighTextContrastEnabledSettingLocked(userState); 1447 somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState); 1448 somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState); 1449 somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState); 1450 return somthingChanged; 1451 } 1452 readAccessibilityEnabledSettingLocked(UserState userState)1453 private boolean readAccessibilityEnabledSettingLocked(UserState userState) { 1454 final boolean accessibilityEnabled = Settings.Secure.getIntForUser( 1455 mContext.getContentResolver(), 1456 Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1; 1457 if (accessibilityEnabled != userState.mIsAccessibilityEnabled) { 1458 userState.mIsAccessibilityEnabled = accessibilityEnabled; 1459 return true; 1460 } 1461 return false; 1462 } 1463 readTouchExplorationEnabledSettingLocked(UserState userState)1464 private boolean readTouchExplorationEnabledSettingLocked(UserState userState) { 1465 final boolean touchExplorationEnabled = Settings.Secure.getIntForUser( 1466 mContext.getContentResolver(), 1467 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; 1468 if (touchExplorationEnabled != userState.mIsTouchExplorationEnabled) { 1469 userState.mIsTouchExplorationEnabled = touchExplorationEnabled; 1470 return true; 1471 } 1472 return false; 1473 } 1474 readDisplayMagnificationEnabledSettingLocked(UserState userState)1475 private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) { 1476 final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser( 1477 mContext.getContentResolver(), 1478 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 1479 0, userState.mUserId) == 1; 1480 if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) { 1481 userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled; 1482 return true; 1483 } 1484 return false; 1485 } 1486 readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState)1487 private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) { 1488 final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser( 1489 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1490 0, userState.mUserId) == 1; 1491 if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) { 1492 userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled; 1493 return true; 1494 } 1495 return false; 1496 } 1497 readDisplayColorAdjustmentSettingsLocked(UserState userState)1498 private boolean readDisplayColorAdjustmentSettingsLocked(UserState userState) { 1499 final boolean displayAdjustmentsEnabled = DisplayAdjustmentUtils.hasAdjustments(mContext, 1500 userState.mUserId); 1501 if (displayAdjustmentsEnabled != userState.mHasDisplayColorAdjustment) { 1502 userState.mHasDisplayColorAdjustment = displayAdjustmentsEnabled; 1503 return true; 1504 } 1505 // If display adjustment is enabled, always assume there was a change in 1506 // the adjustment settings. 1507 return displayAdjustmentsEnabled; 1508 } 1509 readHighTextContrastEnabledSettingLocked(UserState userState)1510 private boolean readHighTextContrastEnabledSettingLocked(UserState userState) { 1511 final boolean highTextContrastEnabled = Settings.Secure.getIntForUser( 1512 mContext.getContentResolver(), 1513 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, 0, 1514 userState.mUserId) == 1; 1515 if (highTextContrastEnabled != userState.mIsTextHighContrastEnabled) { 1516 userState.mIsTextHighContrastEnabled = highTextContrastEnabled; 1517 return true; 1518 } 1519 return false; 1520 } 1521 updateTouchExplorationLocked(UserState userState)1522 private void updateTouchExplorationLocked(UserState userState) { 1523 boolean enabled = false; 1524 final int serviceCount = userState.mBoundServices.size(); 1525 for (int i = 0; i < serviceCount; i++) { 1526 Service service = userState.mBoundServices.get(i); 1527 if (canRequestAndRequestsTouchExplorationLocked(service)) { 1528 enabled = true; 1529 break; 1530 } 1531 } 1532 if (enabled != userState.mIsTouchExplorationEnabled) { 1533 userState.mIsTouchExplorationEnabled = enabled; 1534 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1535 Settings.Secure.TOUCH_EXPLORATION_ENABLED, enabled ? 1 : 0, 1536 userState.mUserId); 1537 } 1538 } 1539 canRequestAndRequestsTouchExplorationLocked(Service service)1540 private boolean canRequestAndRequestsTouchExplorationLocked(Service service) { 1541 // Service not ready or cannot request the feature - well nothing to do. 1542 if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) { 1543 return false; 1544 } 1545 // UI test automation service can always enable it. 1546 if (service.mIsAutomation) { 1547 return true; 1548 } 1549 if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion 1550 <= Build.VERSION_CODES.JELLY_BEAN_MR1) { 1551 // Up to JB-MR1 we had a white list with services that can enable touch 1552 // exploration. When a service is first started we show a dialog to the 1553 // use to get a permission to white list the service. 1554 UserState userState = getUserStateLocked(service.mUserId); 1555 if (userState.mTouchExplorationGrantedServices.contains(service.mComponentName)) { 1556 return true; 1557 } else if (mEnableTouchExplorationDialog == null 1558 || !mEnableTouchExplorationDialog.isShowing()) { 1559 mMainHandler.obtainMessage( 1560 MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG, 1561 service).sendToTarget(); 1562 } 1563 } else { 1564 // Starting in JB-MR2 we request an accessibility service to declare 1565 // certain capabilities in its meta-data to allow it to enable the 1566 // corresponding features. 1567 if ((service.mAccessibilityServiceInfo.getCapabilities() 1568 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION) != 0) { 1569 return true; 1570 } 1571 } 1572 return false; 1573 } 1574 updateEnhancedWebAccessibilityLocked(UserState userState)1575 private void updateEnhancedWebAccessibilityLocked(UserState userState) { 1576 boolean enabled = false; 1577 final int serviceCount = userState.mBoundServices.size(); 1578 for (int i = 0; i < serviceCount; i++) { 1579 Service service = userState.mBoundServices.get(i); 1580 if (canRequestAndRequestsEnhancedWebAccessibilityLocked(service)) { 1581 enabled = true; 1582 break; 1583 } 1584 } 1585 if (enabled != userState.mIsEnhancedWebAccessibilityEnabled) { 1586 userState.mIsEnhancedWebAccessibilityEnabled = enabled; 1587 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1588 Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0, 1589 userState.mUserId); 1590 } 1591 } 1592 canRequestAndRequestsEnhancedWebAccessibilityLocked(Service service)1593 private boolean canRequestAndRequestsEnhancedWebAccessibilityLocked(Service service) { 1594 if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) { 1595 return false; 1596 } 1597 if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities() 1598 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) { 1599 return true; 1600 } 1601 return false; 1602 } 1603 updateDisplayColorAdjustmentSettingsLocked(UserState userState)1604 private void updateDisplayColorAdjustmentSettingsLocked(UserState userState) { 1605 DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId); 1606 } 1607 hasRunningServicesLocked(UserState userState)1608 private boolean hasRunningServicesLocked(UserState userState) { 1609 return !userState.mBoundServices.isEmpty() || !userState.mBindingServices.isEmpty(); 1610 } 1611 getCompatibleMagnificationSpecLocked(int windowId)1612 private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) { 1613 IBinder windowToken = mGlobalWindowTokens.get(windowId); 1614 if (windowToken == null) { 1615 windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId); 1616 } 1617 if (windowToken != null) { 1618 return mWindowManagerService.getCompatibleMagnificationSpecForWindow( 1619 windowToken); 1620 } 1621 return null; 1622 } 1623 1624 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)1625 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 1626 mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP); 1627 synchronized (mLock) { 1628 pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)"); 1629 pw.println(); 1630 final int userCount = mUserStates.size(); 1631 for (int i = 0; i < userCount; i++) { 1632 UserState userState = mUserStates.valueAt(i); 1633 pw.append("User state[attributes:{id=" + userState.mUserId); 1634 pw.append(", currentUser=" + (userState.mUserId == mCurrentUserId)); 1635 pw.append(", accessibilityEnabled=" + userState.mIsAccessibilityEnabled); 1636 pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled); 1637 pw.append(", displayMagnificationEnabled=" 1638 + userState.mIsDisplayMagnificationEnabled); 1639 if (userState.mUiAutomationService != null) { 1640 pw.append(", "); 1641 userState.mUiAutomationService.dump(fd, pw, args); 1642 pw.println(); 1643 } 1644 pw.append("}"); 1645 pw.println(); 1646 pw.append(" services:{"); 1647 final int serviceCount = userState.mBoundServices.size(); 1648 for (int j = 0; j < serviceCount; j++) { 1649 if (j > 0) { 1650 pw.append(", "); 1651 pw.println(); 1652 pw.append(" "); 1653 } 1654 Service service = userState.mBoundServices.get(j); 1655 service.dump(fd, pw, args); 1656 } 1657 pw.println("}]"); 1658 pw.println(); 1659 } 1660 if (mSecurityPolicy.mWindows != null) { 1661 final int windowCount = mSecurityPolicy.mWindows.size(); 1662 for (int j = 0; j < windowCount; j++) { 1663 if (j > 0) { 1664 pw.append(','); 1665 pw.println(); 1666 } 1667 pw.append("Window["); 1668 AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(j); 1669 pw.append(window.toString()); 1670 pw.append(']'); 1671 } 1672 } 1673 } 1674 } 1675 1676 private class AccessibilityConnectionWrapper implements DeathRecipient { 1677 private final int mWindowId; 1678 private final int mUserId; 1679 private final IAccessibilityInteractionConnection mConnection; 1680 AccessibilityConnectionWrapper(int windowId, IAccessibilityInteractionConnection connection, int userId)1681 public AccessibilityConnectionWrapper(int windowId, 1682 IAccessibilityInteractionConnection connection, int userId) { 1683 mWindowId = windowId; 1684 mUserId = userId; 1685 mConnection = connection; 1686 } 1687 linkToDeath()1688 public void linkToDeath() throws RemoteException { 1689 mConnection.asBinder().linkToDeath(this, 0); 1690 } 1691 unlinkToDeath()1692 public void unlinkToDeath() { 1693 mConnection.asBinder().unlinkToDeath(this, 0); 1694 } 1695 1696 @Override binderDied()1697 public void binderDied() { 1698 unlinkToDeath(); 1699 synchronized (mLock) { 1700 removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId); 1701 } 1702 } 1703 } 1704 1705 private final class MainHandler extends Handler { 1706 public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1; 1707 public static final int MSG_SEND_STATE_TO_CLIENTS = 2; 1708 public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3; 1709 public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5; 1710 public static final int MSG_UPDATE_INPUT_FILTER = 6; 1711 public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7; 1712 public static final int MSG_SEND_KEY_EVENT_TO_INPUT_FILTER = 8; 1713 public static final int MSG_CLEAR_ACCESSIBILITY_FOCUS = 9; 1714 MainHandler(Looper looper)1715 public MainHandler(Looper looper) { 1716 super(looper); 1717 } 1718 1719 @Override handleMessage(Message msg)1720 public void handleMessage(Message msg) { 1721 final int type = msg.what; 1722 switch (type) { 1723 case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: { 1724 AccessibilityEvent event = (AccessibilityEvent) msg.obj; 1725 synchronized (mLock) { 1726 if (mHasInputFilter && mInputFilter != null) { 1727 mInputFilter.notifyAccessibilityEvent(event); 1728 } 1729 } 1730 event.recycle(); 1731 } break; 1732 1733 case MSG_SEND_KEY_EVENT_TO_INPUT_FILTER: { 1734 KeyEvent event = (KeyEvent) msg.obj; 1735 final int policyFlags = msg.arg1; 1736 synchronized (mLock) { 1737 if (mHasInputFilter && mInputFilter != null) { 1738 mInputFilter.sendInputEvent(event, policyFlags); 1739 } 1740 } 1741 event.recycle(); 1742 } break; 1743 1744 case MSG_SEND_STATE_TO_CLIENTS: { 1745 final int clientState = msg.arg1; 1746 final int userId = msg.arg2; 1747 sendStateToClients(clientState, mGlobalClients); 1748 sendStateToClientsForUser(clientState, userId); 1749 } break; 1750 1751 case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: { 1752 final int userId = msg.arg1; 1753 sendStateToClientsForUser(0, userId); 1754 } break; 1755 1756 case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: { 1757 announceNewUserIfNeeded(); 1758 } break; 1759 1760 case MSG_UPDATE_INPUT_FILTER: { 1761 UserState userState = (UserState) msg.obj; 1762 updateInputFilter(userState); 1763 } break; 1764 1765 case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: { 1766 Service service = (Service) msg.obj; 1767 showEnableTouchExplorationDialog(service); 1768 } break; 1769 1770 case MSG_CLEAR_ACCESSIBILITY_FOCUS: { 1771 final int windowId = msg.arg1; 1772 InteractionBridge bridge; 1773 synchronized (mLock) { 1774 bridge = getInteractionBridgeLocked(); 1775 } 1776 bridge.clearAccessibilityFocusNotLocked(windowId); 1777 } break; 1778 } 1779 } 1780 announceNewUserIfNeeded()1781 private void announceNewUserIfNeeded() { 1782 synchronized (mLock) { 1783 UserState userState = getCurrentUserStateLocked(); 1784 if (userState.mIsAccessibilityEnabled) { 1785 UserManager userManager = (UserManager) mContext.getSystemService( 1786 Context.USER_SERVICE); 1787 String message = mContext.getString(R.string.user_switched, 1788 userManager.getUserInfo(mCurrentUserId).name); 1789 AccessibilityEvent event = AccessibilityEvent.obtain( 1790 AccessibilityEvent.TYPE_ANNOUNCEMENT); 1791 event.getText().add(message); 1792 sendAccessibilityEvent(event, mCurrentUserId); 1793 } 1794 } 1795 } 1796 sendStateToClientsForUser(int clientState, int userId)1797 private void sendStateToClientsForUser(int clientState, int userId) { 1798 final UserState userState; 1799 synchronized (mLock) { 1800 userState = getUserStateLocked(userId); 1801 } 1802 sendStateToClients(clientState, userState.mClients); 1803 } 1804 sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)1805 private void sendStateToClients(int clientState, 1806 RemoteCallbackList<IAccessibilityManagerClient> clients) { 1807 try { 1808 final int userClientCount = clients.beginBroadcast(); 1809 for (int i = 0; i < userClientCount; i++) { 1810 IAccessibilityManagerClient client = clients.getBroadcastItem(i); 1811 try { 1812 client.setState(clientState); 1813 } catch (RemoteException re) { 1814 /* ignore */ 1815 } 1816 } 1817 } finally { 1818 clients.finishBroadcast(); 1819 } 1820 } 1821 } 1822 obtainPendingEventLocked(KeyEvent event, int policyFlags, int sequence)1823 private PendingEvent obtainPendingEventLocked(KeyEvent event, int policyFlags, int sequence) { 1824 PendingEvent pendingEvent = mPendingEventPool.acquire(); 1825 if (pendingEvent == null) { 1826 pendingEvent = new PendingEvent(); 1827 } 1828 pendingEvent.event = event; 1829 pendingEvent.policyFlags = policyFlags; 1830 pendingEvent.sequence = sequence; 1831 return pendingEvent; 1832 } 1833 recyclePendingEventLocked(PendingEvent pendingEvent)1834 private void recyclePendingEventLocked(PendingEvent pendingEvent) { 1835 pendingEvent.clear(); 1836 mPendingEventPool.release(pendingEvent); 1837 } 1838 findWindowIdLocked(IBinder token)1839 private int findWindowIdLocked(IBinder token) { 1840 final int globalIndex = mGlobalWindowTokens.indexOfValue(token); 1841 if (globalIndex >= 0) { 1842 return mGlobalWindowTokens.keyAt(globalIndex); 1843 } 1844 UserState userState = getCurrentUserStateLocked(); 1845 final int userIndex = userState.mWindowTokens.indexOfValue(token); 1846 if (userIndex >= 0) { 1847 return userState.mWindowTokens.keyAt(userIndex); 1848 } 1849 return -1; 1850 } 1851 ensureWindowsAvailableTimed()1852 private void ensureWindowsAvailableTimed() { 1853 synchronized (mLock) { 1854 if (mSecurityPolicy.mWindows != null) { 1855 return; 1856 } 1857 // If we have no registered callback, update the state we 1858 // we may have to register one but it didn't happen yet. 1859 if (mWindowsForAccessibilityCallback == null) { 1860 UserState userState = getCurrentUserStateLocked(); 1861 onUserStateChangedLocked(userState); 1862 } 1863 // We have no windows but do not care about them, done. 1864 if (mWindowsForAccessibilityCallback == null) { 1865 return; 1866 } 1867 1868 // Wait for the windows with a timeout. 1869 final long startMillis = SystemClock.uptimeMillis(); 1870 while (mSecurityPolicy.mWindows == null) { 1871 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; 1872 final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis; 1873 if (remainMillis <= 0) { 1874 return; 1875 } 1876 try { 1877 mLock.wait(remainMillis); 1878 } catch (InterruptedException ie) { 1879 /* ignore */ 1880 } 1881 } 1882 } 1883 } 1884 1885 /** 1886 * This class represents an accessibility service. It stores all per service 1887 * data required for the service management, provides API for starting/stopping the 1888 * service and is responsible for adding/removing the service in the data structures 1889 * for service management. The class also exposes configuration interface that is 1890 * passed to the service it represents as soon it is bound. It also serves as the 1891 * connection for the service. 1892 */ 1893 class Service extends IAccessibilityServiceConnection.Stub 1894 implements ServiceConnection, DeathRecipient {; 1895 1896 final int mUserId; 1897 1898 int mId = 0; 1899 1900 AccessibilityServiceInfo mAccessibilityServiceInfo; 1901 1902 IBinder mService; 1903 1904 IAccessibilityServiceClient mServiceInterface; 1905 1906 int mEventTypes; 1907 1908 int mFeedbackType; 1909 1910 Set<String> mPackageNames = new HashSet<>(); 1911 1912 boolean mIsDefault; 1913 1914 boolean mRequestTouchExplorationMode; 1915 1916 boolean mRequestEnhancedWebAccessibility; 1917 1918 boolean mRequestFilterKeyEvents; 1919 1920 boolean mRetrieveInteractiveWindows; 1921 1922 int mFetchFlags; 1923 1924 long mNotificationTimeout; 1925 1926 ComponentName mComponentName; 1927 1928 Intent mIntent; 1929 1930 boolean mIsAutomation; 1931 1932 final ResolveInfo mResolveInfo; 1933 1934 // the events pending events to be dispatched to this service 1935 final SparseArray<AccessibilityEvent> mPendingEvents = 1936 new SparseArray<>(); 1937 1938 final KeyEventDispatcher mKeyEventDispatcher = new KeyEventDispatcher(); 1939 1940 boolean mWasConnectedAndDied; 1941 1942 // Handler only for dispatching accessibility events since we use event 1943 // types as message types allowing us to remove messages per event type. 1944 public Handler mEventDispatchHandler = new Handler(mMainHandler.getLooper()) { 1945 @Override 1946 public void handleMessage(Message message) { 1947 final int eventType = message.what; 1948 notifyAccessibilityEventInternal(eventType); 1949 } 1950 }; 1951 1952 // Handler for scheduling method invocations on the main thread. 1953 public InvocationHandler mInvocationHandler = new InvocationHandler( 1954 mMainHandler.getLooper()); 1955 Service(int userId, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo)1956 public Service(int userId, ComponentName componentName, 1957 AccessibilityServiceInfo accessibilityServiceInfo) { 1958 mUserId = userId; 1959 mResolveInfo = accessibilityServiceInfo.getResolveInfo(); 1960 mId = sIdCounter++; 1961 mComponentName = componentName; 1962 mAccessibilityServiceInfo = accessibilityServiceInfo; 1963 mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName)); 1964 if (!mIsAutomation) { 1965 mIntent = new Intent().setComponent(mComponentName); 1966 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, 1967 com.android.internal.R.string.accessibility_binding_label); 1968 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( 1969 mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0)); 1970 } 1971 setDynamicallyConfigurableProperties(accessibilityServiceInfo); 1972 } 1973 setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)1974 public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { 1975 mEventTypes = info.eventTypes; 1976 mFeedbackType = info.feedbackType; 1977 String[] packageNames = info.packageNames; 1978 if (packageNames != null) { 1979 mPackageNames.addAll(Arrays.asList(packageNames)); 1980 } 1981 mNotificationTimeout = info.notificationTimeout; 1982 mIsDefault = (info.flags & DEFAULT) != 0; 1983 1984 if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 1985 >= Build.VERSION_CODES.JELLY_BEAN) { 1986 if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) { 1987 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 1988 } else { 1989 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 1990 } 1991 } 1992 1993 if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) { 1994 mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 1995 } else { 1996 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 1997 } 1998 1999 mRequestTouchExplorationMode = (info.flags 2000 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; 2001 mRequestEnhancedWebAccessibility = (info.flags 2002 & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0; 2003 mRequestFilterKeyEvents = (info.flags 2004 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; 2005 mRetrieveInteractiveWindows = (info.flags 2006 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; 2007 } 2008 2009 /** 2010 * Binds to the accessibility service. 2011 * 2012 * @return True if binding is successful. 2013 */ bindLocked()2014 public boolean bindLocked() { 2015 UserState userState = getUserStateLocked(mUserId); 2016 if (!mIsAutomation) { 2017 if (mService == null && mContext.bindServiceAsUser( 2018 mIntent, this, Context.BIND_AUTO_CREATE, new UserHandle(mUserId))) { 2019 userState.mBindingServices.add(mComponentName); 2020 } 2021 } else { 2022 userState.mBindingServices.add(mComponentName); 2023 mService = userState.mUiAutomationServiceClient.asBinder(); 2024 mMainHandler.post(new Runnable() { 2025 @Override 2026 public void run() { 2027 // Simulate asynchronous connection since in onServiceConnected 2028 // we may modify the state data in case of an error but bind is 2029 // called while iterating over the data and bad things can happen. 2030 onServiceConnected(mComponentName, mService); 2031 } 2032 }); 2033 userState.mUiAutomationService = this; 2034 } 2035 return false; 2036 } 2037 2038 /** 2039 * Unbinds form the accessibility service and removes it from the data 2040 * structures for service management. 2041 * 2042 * @return True if unbinding is successful. 2043 */ unbindLocked()2044 public boolean unbindLocked() { 2045 if (mService == null) { 2046 return false; 2047 } 2048 UserState userState = getUserStateLocked(mUserId); 2049 mKeyEventDispatcher.flush(); 2050 if (!mIsAutomation) { 2051 mContext.unbindService(this); 2052 } else { 2053 userState.destroyUiAutomationService(); 2054 } 2055 removeServiceLocked(this, userState); 2056 resetLocked(); 2057 return true; 2058 } 2059 canReceiveEventsLocked()2060 public boolean canReceiveEventsLocked() { 2061 return (mEventTypes != 0 && mFeedbackType != 0 && mService != null); 2062 } 2063 2064 @Override setOnKeyEventResult(boolean handled, int sequence)2065 public void setOnKeyEventResult(boolean handled, int sequence) { 2066 mKeyEventDispatcher.setOnKeyEventResult(handled, sequence); 2067 } 2068 2069 @Override getServiceInfo()2070 public AccessibilityServiceInfo getServiceInfo() { 2071 synchronized (mLock) { 2072 return mAccessibilityServiceInfo; 2073 } 2074 } 2075 canRetrieveInteractiveWindowsLocked()2076 public boolean canRetrieveInteractiveWindowsLocked() { 2077 return mSecurityPolicy.canRetrieveWindowContentLocked(this) 2078 && mRetrieveInteractiveWindows; 2079 } 2080 2081 @Override setServiceInfo(AccessibilityServiceInfo info)2082 public void setServiceInfo(AccessibilityServiceInfo info) { 2083 final long identity = Binder.clearCallingIdentity(); 2084 try { 2085 synchronized (mLock) { 2086 // If the XML manifest had data to configure the service its info 2087 // should be already set. In such a case update only the dynamically 2088 // configurable properties. 2089 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; 2090 if (oldInfo != null) { 2091 oldInfo.updateDynamicallyConfigurableProperties(info); 2092 setDynamicallyConfigurableProperties(oldInfo); 2093 } else { 2094 setDynamicallyConfigurableProperties(info); 2095 } 2096 UserState userState = getUserStateLocked(mUserId); 2097 onUserStateChangedLocked(userState); 2098 } 2099 } finally { 2100 Binder.restoreCallingIdentity(identity); 2101 } 2102 } 2103 2104 @Override onServiceConnected(ComponentName componentName, IBinder service)2105 public void onServiceConnected(ComponentName componentName, IBinder service) { 2106 synchronized (mLock) { 2107 mService = service; 2108 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); 2109 UserState userState = getUserStateLocked(mUserId); 2110 addServiceLocked(this, userState); 2111 if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) { 2112 userState.mBindingServices.remove(mComponentName); 2113 mWasConnectedAndDied = false; 2114 try { 2115 mServiceInterface.setConnection(this, mId); 2116 onUserStateChangedLocked(userState); 2117 } catch (RemoteException re) { 2118 Slog.w(LOG_TAG, "Error while setting connection for service: " 2119 + service, re); 2120 binderDied(); 2121 } 2122 } else { 2123 binderDied(); 2124 } 2125 } 2126 } 2127 2128 @Override getWindows()2129 public List<AccessibilityWindowInfo> getWindows() { 2130 ensureWindowsAvailableTimed(); 2131 synchronized (mLock) { 2132 // We treat calls from a profile as if made by its perent as profiles 2133 // share the accessibility state of the parent. The call below 2134 // performs the current profile parent resolution. 2135 final int resolvedUserId = mSecurityPolicy 2136 .resolveCallingUserIdEnforcingPermissionsLocked( 2137 UserHandle.USER_CURRENT); 2138 if (resolvedUserId != mCurrentUserId) { 2139 return null; 2140 } 2141 final boolean permissionGranted = 2142 mSecurityPolicy.canRetrieveWindowsLocked(this); 2143 if (!permissionGranted) { 2144 return null; 2145 } 2146 List<AccessibilityWindowInfo> windows = new ArrayList<>(); 2147 final int windowCount = mSecurityPolicy.mWindows.size(); 2148 for (int i = 0; i < windowCount; i++) { 2149 AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i); 2150 AccessibilityWindowInfo windowClone = 2151 AccessibilityWindowInfo.obtain(window); 2152 windowClone.setConnectionId(mId); 2153 windows.add(windowClone); 2154 } 2155 return windows; 2156 } 2157 } 2158 2159 @Override getWindow(int windowId)2160 public AccessibilityWindowInfo getWindow(int windowId) { 2161 ensureWindowsAvailableTimed(); 2162 synchronized (mLock) { 2163 // We treat calls from a profile as if made by its parent as profiles 2164 // share the accessibility state of the parent. The call below 2165 // performs the current profile parent resolution. 2166 final int resolvedUserId = mSecurityPolicy 2167 .resolveCallingUserIdEnforcingPermissionsLocked( 2168 UserHandle.USER_CURRENT); 2169 if (resolvedUserId != mCurrentUserId) { 2170 return null; 2171 } 2172 final boolean permissionGranted = 2173 mSecurityPolicy.canRetrieveWindowsLocked(this); 2174 if (!permissionGranted) { 2175 return null; 2176 } 2177 AccessibilityWindowInfo window = mSecurityPolicy.findWindowById(windowId); 2178 if (window != null) { 2179 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); 2180 windowClone.setConnectionId(mId); 2181 return windowClone; 2182 } 2183 return null; 2184 } 2185 } 2186 2187 @Override findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewIdResName, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2188 public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId, 2189 long accessibilityNodeId, String viewIdResName, int interactionId, 2190 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2191 throws RemoteException { 2192 final int resolvedWindowId; 2193 IAccessibilityInteractionConnection connection = null; 2194 Region partialInteractiveRegion = mTempRegion; 2195 synchronized (mLock) { 2196 // We treat calls from a profile as if made by its parent as profiles 2197 // share the accessibility state of the parent. The call below 2198 // performs the current profile parent resolution. 2199 final int resolvedUserId = mSecurityPolicy 2200 .resolveCallingUserIdEnforcingPermissionsLocked( 2201 UserHandle.USER_CURRENT); 2202 if (resolvedUserId != mCurrentUserId) { 2203 return false; 2204 } 2205 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2206 final boolean permissionGranted = 2207 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2208 if (!permissionGranted) { 2209 return false; 2210 } else { 2211 connection = getConnectionLocked(resolvedWindowId); 2212 if (connection == null) { 2213 return false; 2214 } 2215 } 2216 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2217 resolvedWindowId, partialInteractiveRegion)) { 2218 partialInteractiveRegion = null; 2219 } 2220 } 2221 final int interrogatingPid = Binder.getCallingPid(); 2222 final long identityToken = Binder.clearCallingIdentity(); 2223 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2224 try { 2225 connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName, 2226 partialInteractiveRegion, interactionId, callback, mFetchFlags, 2227 interrogatingPid, interrogatingTid, spec); 2228 return true; 2229 } catch (RemoteException re) { 2230 if (DEBUG) { 2231 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId()."); 2232 } 2233 } finally { 2234 Binder.restoreCallingIdentity(identityToken); 2235 } 2236 return false; 2237 } 2238 2239 @Override findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2240 public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, 2241 long accessibilityNodeId, String text, int interactionId, 2242 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2243 throws RemoteException { 2244 final int resolvedWindowId; 2245 IAccessibilityInteractionConnection connection = null; 2246 Region partialInteractiveRegion = mTempRegion; 2247 synchronized (mLock) { 2248 // We treat calls from a profile as if made by its parent as profiles 2249 // share the accessibility state of the parent. The call below 2250 // performs the current profile parent resolution. 2251 final int resolvedUserId = mSecurityPolicy 2252 .resolveCallingUserIdEnforcingPermissionsLocked( 2253 UserHandle.USER_CURRENT); 2254 if (resolvedUserId != mCurrentUserId) { 2255 return false; 2256 } 2257 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2258 final boolean permissionGranted = 2259 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2260 if (!permissionGranted) { 2261 return false; 2262 } else { 2263 connection = getConnectionLocked(resolvedWindowId); 2264 if (connection == null) { 2265 return false; 2266 } 2267 } 2268 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2269 resolvedWindowId, partialInteractiveRegion)) { 2270 partialInteractiveRegion = null; 2271 } 2272 } 2273 final int interrogatingPid = Binder.getCallingPid(); 2274 final long identityToken = Binder.clearCallingIdentity(); 2275 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2276 try { 2277 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text, 2278 partialInteractiveRegion, interactionId, callback, mFetchFlags, 2279 interrogatingPid, interrogatingTid, spec); 2280 return true; 2281 } catch (RemoteException re) { 2282 if (DEBUG) { 2283 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()"); 2284 } 2285 } finally { 2286 Binder.restoreCallingIdentity(identityToken); 2287 } 2288 return false; 2289 } 2290 2291 @Override findAccessibilityNodeInfoByAccessibilityId( int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid)2292 public boolean findAccessibilityNodeInfoByAccessibilityId( 2293 int accessibilityWindowId, long accessibilityNodeId, int interactionId, 2294 IAccessibilityInteractionConnectionCallback callback, int flags, 2295 long interrogatingTid) throws RemoteException { 2296 final int resolvedWindowId; 2297 IAccessibilityInteractionConnection connection = null; 2298 Region partialInteractiveRegion = mTempRegion; 2299 synchronized (mLock) { 2300 // We treat calls from a profile as if made by its parent as profiles 2301 // share the accessibility state of the parent. The call below 2302 // performs the current profile parent resolution. 2303 final int resolvedUserId = mSecurityPolicy 2304 .resolveCallingUserIdEnforcingPermissionsLocked( 2305 UserHandle.USER_CURRENT); 2306 if (resolvedUserId != mCurrentUserId) { 2307 return false; 2308 } 2309 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2310 final boolean permissionGranted = 2311 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2312 if (!permissionGranted) { 2313 return false; 2314 } else { 2315 connection = getConnectionLocked(resolvedWindowId); 2316 if (connection == null) { 2317 return false; 2318 } 2319 } 2320 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2321 resolvedWindowId, partialInteractiveRegion)) { 2322 partialInteractiveRegion = null; 2323 } 2324 } 2325 final int interrogatingPid = Binder.getCallingPid(); 2326 final long identityToken = Binder.clearCallingIdentity(); 2327 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2328 try { 2329 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId, 2330 partialInteractiveRegion, interactionId, callback, mFetchFlags | flags, 2331 interrogatingPid, interrogatingTid, spec); 2332 return true; 2333 } catch (RemoteException re) { 2334 if (DEBUG) { 2335 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); 2336 } 2337 } finally { 2338 Binder.restoreCallingIdentity(identityToken); 2339 } 2340 return false; 2341 } 2342 2343 @Override findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2344 public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, 2345 int focusType, int interactionId, 2346 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2347 throws RemoteException { 2348 final int resolvedWindowId; 2349 IAccessibilityInteractionConnection connection = null; 2350 Region partialInteractiveRegion = mTempRegion; 2351 synchronized (mLock) { 2352 // We treat calls from a profile as if made by its parent as profiles 2353 // share the accessibility state of the parent. The call below 2354 // performs the current profile parent resolution. 2355 final int resolvedUserId = mSecurityPolicy 2356 .resolveCallingUserIdEnforcingPermissionsLocked( 2357 UserHandle.USER_CURRENT); 2358 if (resolvedUserId != mCurrentUserId) { 2359 return false; 2360 } 2361 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked( 2362 accessibilityWindowId, focusType); 2363 final boolean permissionGranted = 2364 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2365 if (!permissionGranted) { 2366 return false; 2367 } else { 2368 connection = getConnectionLocked(resolvedWindowId); 2369 if (connection == null) { 2370 return false; 2371 } 2372 } 2373 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2374 resolvedWindowId, partialInteractiveRegion)) { 2375 partialInteractiveRegion = null; 2376 } 2377 } 2378 final int interrogatingPid = Binder.getCallingPid(); 2379 final long identityToken = Binder.clearCallingIdentity(); 2380 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2381 try { 2382 connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion, 2383 interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid, 2384 spec); 2385 return true; 2386 } catch (RemoteException re) { 2387 if (DEBUG) { 2388 Slog.e(LOG_TAG, "Error calling findFocus()"); 2389 } 2390 } finally { 2391 Binder.restoreCallingIdentity(identityToken); 2392 } 2393 return false; 2394 } 2395 2396 @Override focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2397 public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, 2398 int direction, int interactionId, 2399 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2400 throws RemoteException { 2401 final int resolvedWindowId; 2402 IAccessibilityInteractionConnection connection = null; 2403 Region partialInteractiveRegion = mTempRegion; 2404 synchronized (mLock) { 2405 // We treat calls from a profile as if made by its parent as profiles 2406 // share the accessibility state of the parent. The call below 2407 // performs the current profile parent resolution. 2408 final int resolvedUserId = mSecurityPolicy 2409 .resolveCallingUserIdEnforcingPermissionsLocked( 2410 UserHandle.USER_CURRENT); 2411 if (resolvedUserId != mCurrentUserId) { 2412 return false; 2413 } 2414 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2415 final boolean permissionGranted = 2416 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2417 if (!permissionGranted) { 2418 return false; 2419 } else { 2420 connection = getConnectionLocked(resolvedWindowId); 2421 if (connection == null) { 2422 return false; 2423 } 2424 } 2425 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2426 resolvedWindowId, partialInteractiveRegion)) { 2427 partialInteractiveRegion = null; 2428 } 2429 } 2430 final int interrogatingPid = Binder.getCallingPid(); 2431 final long identityToken = Binder.clearCallingIdentity(); 2432 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2433 try { 2434 connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion, 2435 interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid, 2436 spec); 2437 return true; 2438 } catch (RemoteException re) { 2439 if (DEBUG) { 2440 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()"); 2441 } 2442 } finally { 2443 Binder.restoreCallingIdentity(identityToken); 2444 } 2445 return false; 2446 } 2447 2448 @Override performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2449 public boolean performAccessibilityAction(int accessibilityWindowId, 2450 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 2451 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2452 throws RemoteException { 2453 final int resolvedWindowId; 2454 IAccessibilityInteractionConnection connection = null; 2455 synchronized (mLock) { 2456 // We treat calls from a profile as if made by its parent as profiles 2457 // share the accessibility state of the parent. The call below 2458 // performs the current profile parent resolution. 2459 final int resolvedUserId = mSecurityPolicy 2460 .resolveCallingUserIdEnforcingPermissionsLocked( 2461 UserHandle.USER_CURRENT); 2462 if (resolvedUserId != mCurrentUserId) { 2463 return false; 2464 } 2465 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2466 final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 2467 this, resolvedWindowId); 2468 if (!permissionGranted) { 2469 return false; 2470 } else { 2471 connection = getConnectionLocked(resolvedWindowId); 2472 if (connection == null) { 2473 return false; 2474 } 2475 } 2476 } 2477 final int interrogatingPid = Binder.getCallingPid(); 2478 final long identityToken = Binder.clearCallingIdentity(); 2479 try { 2480 connection.performAccessibilityAction(accessibilityNodeId, action, arguments, 2481 interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid); 2482 } catch (RemoteException re) { 2483 if (DEBUG) { 2484 Slog.e(LOG_TAG, "Error calling performAccessibilityAction()"); 2485 } 2486 } finally { 2487 Binder.restoreCallingIdentity(identityToken); 2488 } 2489 return true; 2490 } 2491 2492 @Override performGlobalAction(int action)2493 public boolean performGlobalAction(int action) { 2494 synchronized (mLock) { 2495 // We treat calls from a profile as if made by its parent as profiles 2496 // share the accessibility state of the parent. The call below 2497 // performs the current profile parent resolution. 2498 final int resolvedUserId = mSecurityPolicy 2499 .resolveCallingUserIdEnforcingPermissionsLocked( 2500 UserHandle.USER_CURRENT); 2501 if (resolvedUserId != mCurrentUserId) { 2502 return false; 2503 } 2504 } 2505 final long identity = Binder.clearCallingIdentity(); 2506 try { 2507 switch (action) { 2508 case AccessibilityService.GLOBAL_ACTION_BACK: { 2509 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); 2510 } return true; 2511 case AccessibilityService.GLOBAL_ACTION_HOME: { 2512 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); 2513 } return true; 2514 case AccessibilityService.GLOBAL_ACTION_RECENTS: { 2515 openRecents(); 2516 } return true; 2517 case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { 2518 expandNotifications(); 2519 } return true; 2520 case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: { 2521 expandQuickSettings(); 2522 } return true; 2523 case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: { 2524 showGlobalActions(); 2525 } return true; 2526 } 2527 return false; 2528 } finally { 2529 Binder.restoreCallingIdentity(identity); 2530 } 2531 } 2532 2533 @Override computeClickPointInScreen(int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)2534 public boolean computeClickPointInScreen(int accessibilityWindowId, 2535 long accessibilityNodeId, int interactionId, 2536 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2537 throws RemoteException { 2538 final int resolvedWindowId; 2539 IAccessibilityInteractionConnection connection = null; 2540 Region partialInteractiveRegion = mTempRegion; 2541 synchronized (mLock) { 2542 // We treat calls from a profile as if made by its parent as profiles 2543 // share the accessibility state of the parent. The call below 2544 // performs the current profile parent resolution. 2545 final int resolvedUserId = mSecurityPolicy 2546 .resolveCallingUserIdEnforcingPermissionsLocked( 2547 UserHandle.USER_CURRENT); 2548 if (resolvedUserId != mCurrentUserId) { 2549 return false; 2550 } 2551 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2552 final boolean permissionGranted = 2553 mSecurityPolicy.canRetrieveWindowContentLocked(this); 2554 if (!permissionGranted) { 2555 return false; 2556 } else { 2557 connection = getConnectionLocked(resolvedWindowId); 2558 if (connection == null) { 2559 return false; 2560 } 2561 } 2562 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2563 resolvedWindowId, partialInteractiveRegion)) { 2564 partialInteractiveRegion = null; 2565 } 2566 } 2567 final int interrogatingPid = Binder.getCallingPid(); 2568 final long identityToken = Binder.clearCallingIdentity(); 2569 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2570 try { 2571 connection.computeClickPointInScreen(accessibilityNodeId, partialInteractiveRegion, 2572 interactionId, callback, interrogatingPid, interrogatingTid, spec); 2573 return true; 2574 } catch (RemoteException re) { 2575 if (DEBUG) { 2576 Slog.e(LOG_TAG, "Error computeClickPointInScreen()."); 2577 } 2578 } finally { 2579 Binder.restoreCallingIdentity(identityToken); 2580 } 2581 return false; 2582 } 2583 2584 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)2585 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 2586 mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP); 2587 synchronized (mLock) { 2588 pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo() 2589 .loadLabel(mContext.getPackageManager())); 2590 pw.append(", feedbackType" 2591 + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType)); 2592 pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities()); 2593 pw.append(", eventTypes=" 2594 + AccessibilityEvent.eventTypeToString(mEventTypes)); 2595 pw.append(", notificationTimeout=" + mNotificationTimeout); 2596 pw.append("]"); 2597 } 2598 } 2599 2600 @Override onServiceDisconnected(ComponentName componentName)2601 public void onServiceDisconnected(ComponentName componentName) { 2602 /* do nothing - #binderDied takes care */ 2603 } 2604 linkToOwnDeathLocked()2605 public void linkToOwnDeathLocked() throws RemoteException { 2606 mService.linkToDeath(this, 0); 2607 } 2608 unlinkToOwnDeathLocked()2609 public void unlinkToOwnDeathLocked() { 2610 mService.unlinkToDeath(this, 0); 2611 } 2612 resetLocked()2613 public void resetLocked() { 2614 try { 2615 // Clear the proxy in the other process so this 2616 // IAccessibilityServiceConnection can be garbage collected. 2617 mServiceInterface.setConnection(null, mId); 2618 } catch (RemoteException re) { 2619 /* ignore */ 2620 } 2621 mService = null; 2622 mServiceInterface = null; 2623 } 2624 isConnectedLocked()2625 public boolean isConnectedLocked() { 2626 return (mService != null); 2627 } 2628 binderDied()2629 public void binderDied() { 2630 synchronized (mLock) { 2631 // It is possible that this service's package was force stopped during 2632 // whose handling the death recipient is unlinked and still get a call 2633 // on binderDied since the call was made before we unlink but was 2634 // waiting on the lock we held during the force stop handling. 2635 if (!isConnectedLocked()) { 2636 return; 2637 } 2638 mWasConnectedAndDied = true; 2639 mKeyEventDispatcher.flush(); 2640 UserState userState = getUserStateLocked(mUserId); 2641 // The death recipient is unregistered in removeServiceLocked 2642 removeServiceLocked(this, userState); 2643 resetLocked(); 2644 if (mIsAutomation) { 2645 // We no longer have an automation service, so restore 2646 // the state based on values in the settings database. 2647 userState.mInstalledServices.remove(mAccessibilityServiceInfo); 2648 userState.mEnabledServices.remove(mComponentName); 2649 userState.destroyUiAutomationService(); 2650 if (readConfigurationForUserStateLocked(userState)) { 2651 onUserStateChangedLocked(userState); 2652 } 2653 } 2654 } 2655 } 2656 2657 /** 2658 * Performs a notification for an {@link AccessibilityEvent}. 2659 * 2660 * @param event The event. 2661 */ notifyAccessibilityEvent(AccessibilityEvent event)2662 public void notifyAccessibilityEvent(AccessibilityEvent event) { 2663 synchronized (mLock) { 2664 final int eventType = event.getEventType(); 2665 // Make a copy since during dispatch it is possible the event to 2666 // be modified to remove its source if the receiving service does 2667 // not have permission to access the window content. 2668 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event); 2669 AccessibilityEvent oldEvent = mPendingEvents.get(eventType); 2670 mPendingEvents.put(eventType, newEvent); 2671 2672 final int what = eventType; 2673 if (oldEvent != null) { 2674 mEventDispatchHandler.removeMessages(what); 2675 oldEvent.recycle(); 2676 } 2677 2678 Message message = mEventDispatchHandler.obtainMessage(what); 2679 mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout); 2680 } 2681 } 2682 2683 /** 2684 * Notifies an accessibility service client for a scheduled event given the event type. 2685 * 2686 * @param eventType The type of the event to dispatch. 2687 */ notifyAccessibilityEventInternal(int eventType)2688 private void notifyAccessibilityEventInternal(int eventType) { 2689 IAccessibilityServiceClient listener; 2690 AccessibilityEvent event; 2691 2692 synchronized (mLock) { 2693 listener = mServiceInterface; 2694 2695 // If the service died/was disabled while the message for dispatching 2696 // the accessibility event was propagating the listener may be null. 2697 if (listener == null) { 2698 return; 2699 } 2700 2701 event = mPendingEvents.get(eventType); 2702 2703 // Check for null here because there is a concurrent scenario in which this 2704 // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked 2705 // which posts a message for dispatching an event. 2) The message is pulled 2706 // from the queue by the handler on the service thread and the latter is 2707 // just about to acquire the lock and call this method. 3) Now another binder 2708 // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked 2709 // so the service thread waits for the lock; 4) The binder thread replaces 2710 // the event with a more recent one (assume the same event type) and posts a 2711 // dispatch request releasing the lock. 5) Now the main thread is unblocked and 2712 // dispatches the event which is removed from the pending ones. 6) And ... now 2713 // the service thread handles the last message posted by the last binder call 2714 // but the event is already dispatched and hence looking it up in the pending 2715 // ones yields null. This check is much simpler that keeping count for each 2716 // event type of each service to catch such a scenario since only one message 2717 // is processed at a time. 2718 if (event == null) { 2719 return; 2720 } 2721 2722 mPendingEvents.remove(eventType); 2723 if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) { 2724 event.setConnectionId(mId); 2725 } else { 2726 event.setSource(null); 2727 } 2728 event.setSealed(true); 2729 } 2730 2731 try { 2732 listener.onAccessibilityEvent(event); 2733 if (DEBUG) { 2734 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); 2735 } 2736 } catch (RemoteException re) { 2737 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re); 2738 } finally { 2739 event.recycle(); 2740 } 2741 } 2742 notifyGesture(int gestureId)2743 public void notifyGesture(int gestureId) { 2744 mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE, 2745 gestureId, 0).sendToTarget(); 2746 } 2747 notifyKeyEvent(KeyEvent event, int policyFlags)2748 public void notifyKeyEvent(KeyEvent event, int policyFlags) { 2749 mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_KEY_EVENT, 2750 policyFlags, 0, event).sendToTarget(); 2751 } 2752 notifyClearAccessibilityNodeInfoCache()2753 public void notifyClearAccessibilityNodeInfoCache() { 2754 mInvocationHandler.sendEmptyMessage( 2755 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE); 2756 } 2757 notifyGestureInternal(int gestureId)2758 private void notifyGestureInternal(int gestureId) { 2759 final IAccessibilityServiceClient listener; 2760 synchronized (mLock) { 2761 listener = mServiceInterface; 2762 } 2763 if (listener != null) { 2764 try { 2765 listener.onGesture(gestureId); 2766 } catch (RemoteException re) { 2767 Slog.e(LOG_TAG, "Error during sending gesture " + gestureId 2768 + " to " + mService, re); 2769 } 2770 } 2771 } 2772 notifyKeyEventInternal(KeyEvent event, int policyFlags)2773 private void notifyKeyEventInternal(KeyEvent event, int policyFlags) { 2774 mKeyEventDispatcher.notifyKeyEvent(event, policyFlags); 2775 } 2776 notifyClearAccessibilityCacheInternal()2777 private void notifyClearAccessibilityCacheInternal() { 2778 final IAccessibilityServiceClient listener; 2779 synchronized (mLock) { 2780 listener = mServiceInterface; 2781 } 2782 if (listener != null) { 2783 try { 2784 listener.clearAccessibilityCache(); 2785 } catch (RemoteException re) { 2786 Slog.e(LOG_TAG, "Error during requesting accessibility info cache" 2787 + " to be cleared.", re); 2788 } 2789 } 2790 } 2791 sendDownAndUpKeyEvents(int keyCode)2792 private void sendDownAndUpKeyEvents(int keyCode) { 2793 final long token = Binder.clearCallingIdentity(); 2794 2795 // Inject down. 2796 final long downTime = SystemClock.uptimeMillis(); 2797 KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, 2798 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 2799 InputDevice.SOURCE_KEYBOARD, null); 2800 InputManager.getInstance().injectInputEvent(down, 2801 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 2802 down.recycle(); 2803 2804 // Inject up. 2805 final long upTime = SystemClock.uptimeMillis(); 2806 KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0, 2807 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 2808 InputDevice.SOURCE_KEYBOARD, null); 2809 InputManager.getInstance().injectInputEvent(up, 2810 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 2811 up.recycle(); 2812 2813 Binder.restoreCallingIdentity(token); 2814 } 2815 expandNotifications()2816 private void expandNotifications() { 2817 final long token = Binder.clearCallingIdentity(); 2818 2819 StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( 2820 android.app.Service.STATUS_BAR_SERVICE); 2821 statusBarManager.expandNotificationsPanel(); 2822 2823 Binder.restoreCallingIdentity(token); 2824 } 2825 expandQuickSettings()2826 private void expandQuickSettings() { 2827 final long token = Binder.clearCallingIdentity(); 2828 2829 StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( 2830 android.app.Service.STATUS_BAR_SERVICE); 2831 statusBarManager.expandSettingsPanel(); 2832 2833 Binder.restoreCallingIdentity(token); 2834 } 2835 openRecents()2836 private void openRecents() { 2837 final long token = Binder.clearCallingIdentity(); 2838 2839 IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( 2840 ServiceManager.getService("statusbar")); 2841 try { 2842 statusBarService.toggleRecentApps(); 2843 } catch (RemoteException e) { 2844 Slog.e(LOG_TAG, "Error toggling recent apps."); 2845 } 2846 2847 Binder.restoreCallingIdentity(token); 2848 } 2849 showGlobalActions()2850 private void showGlobalActions() { 2851 mWindowManagerService.showGlobalActions(); 2852 } 2853 getConnectionLocked(int windowId)2854 private IAccessibilityInteractionConnection getConnectionLocked(int windowId) { 2855 if (DEBUG) { 2856 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); 2857 } 2858 AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId); 2859 if (wrapper == null) { 2860 wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId); 2861 } 2862 if (wrapper != null && wrapper.mConnection != null) { 2863 return wrapper.mConnection; 2864 } 2865 if (DEBUG) { 2866 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId); 2867 } 2868 return null; 2869 } 2870 resolveAccessibilityWindowIdLocked(int accessibilityWindowId)2871 private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) { 2872 if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) { 2873 return mSecurityPolicy.getActiveWindowId(); 2874 } 2875 return accessibilityWindowId; 2876 } 2877 resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)2878 private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { 2879 if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) { 2880 return mSecurityPolicy.mActiveWindowId; 2881 } 2882 if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) { 2883 if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { 2884 return mSecurityPolicy.mFocusedWindowId; 2885 } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { 2886 return mSecurityPolicy.mAccessibilityFocusedWindowId; 2887 } 2888 } 2889 return windowId; 2890 } 2891 2892 private final class InvocationHandler extends Handler { 2893 public static final int MSG_ON_GESTURE = 1; 2894 public static final int MSG_ON_KEY_EVENT = 2; 2895 public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 3; 2896 public static final int MSG_ON_KEY_EVENT_TIMEOUT = 4; 2897 InvocationHandler(Looper looper)2898 public InvocationHandler(Looper looper) { 2899 super(looper, null, true); 2900 } 2901 2902 @Override handleMessage(Message message)2903 public void handleMessage(Message message) { 2904 final int type = message.what; 2905 switch (type) { 2906 case MSG_ON_GESTURE: { 2907 final int gestureId = message.arg1; 2908 notifyGestureInternal(gestureId); 2909 } break; 2910 2911 case MSG_ON_KEY_EVENT: { 2912 KeyEvent event = (KeyEvent) message.obj; 2913 final int policyFlags = message.arg1; 2914 notifyKeyEventInternal(event, policyFlags); 2915 } break; 2916 2917 case MSG_CLEAR_ACCESSIBILITY_CACHE: { 2918 notifyClearAccessibilityCacheInternal(); 2919 } break; 2920 2921 case MSG_ON_KEY_EVENT_TIMEOUT: { 2922 PendingEvent eventState = (PendingEvent) message.obj; 2923 setOnKeyEventResult(false, eventState.sequence); 2924 } break; 2925 2926 default: { 2927 throw new IllegalArgumentException("Unknown message: " + type); 2928 } 2929 } 2930 } 2931 } 2932 2933 private final class KeyEventDispatcher { 2934 2935 private static final long ON_KEY_EVENT_TIMEOUT_MILLIS = 500; 2936 2937 private PendingEvent mPendingEvents; 2938 2939 private final InputEventConsistencyVerifier mSentEventsVerifier = 2940 InputEventConsistencyVerifier.isInstrumentationEnabled() 2941 ? new InputEventConsistencyVerifier( 2942 this, 0, KeyEventDispatcher.class.getSimpleName()) : null; 2943 notifyKeyEvent(KeyEvent event, int policyFlags)2944 public void notifyKeyEvent(KeyEvent event, int policyFlags) { 2945 final PendingEvent pendingEvent; 2946 2947 synchronized (mLock) { 2948 pendingEvent = addPendingEventLocked(event, policyFlags); 2949 } 2950 2951 Message message = mInvocationHandler.obtainMessage( 2952 InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT, pendingEvent); 2953 mInvocationHandler.sendMessageDelayed(message, ON_KEY_EVENT_TIMEOUT_MILLIS); 2954 2955 try { 2956 // Accessibility services are exclusively not in the system 2957 // process, therefore no need to clone the motion event to 2958 // prevent tampering. It will be cloned in the IPC call. 2959 mServiceInterface.onKeyEvent(pendingEvent.event, pendingEvent.sequence); 2960 } catch (RemoteException re) { 2961 setOnKeyEventResult(false, pendingEvent.sequence); 2962 } 2963 } 2964 setOnKeyEventResult(boolean handled, int sequence)2965 public void setOnKeyEventResult(boolean handled, int sequence) { 2966 synchronized (mLock) { 2967 PendingEvent pendingEvent = removePendingEventLocked(sequence); 2968 if (pendingEvent != null) { 2969 mInvocationHandler.removeMessages( 2970 InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT, 2971 pendingEvent); 2972 pendingEvent.handled = handled; 2973 finishPendingEventLocked(pendingEvent); 2974 } 2975 } 2976 } 2977 flush()2978 public void flush() { 2979 synchronized (mLock) { 2980 cancelAllPendingEventsLocked(); 2981 if (mSentEventsVerifier != null) { 2982 mSentEventsVerifier.reset(); 2983 } 2984 } 2985 } 2986 addPendingEventLocked(KeyEvent event, int policyFlags)2987 private PendingEvent addPendingEventLocked(KeyEvent event, int policyFlags) { 2988 final int sequence = event.getSequenceNumber(); 2989 PendingEvent pendingEvent = obtainPendingEventLocked(event, policyFlags, sequence); 2990 pendingEvent.next = mPendingEvents; 2991 mPendingEvents = pendingEvent; 2992 return pendingEvent; 2993 } 2994 removePendingEventLocked(int sequence)2995 private PendingEvent removePendingEventLocked(int sequence) { 2996 PendingEvent previous = null; 2997 PendingEvent current = mPendingEvents; 2998 2999 while (current != null) { 3000 if (current.sequence == sequence) { 3001 if (previous != null) { 3002 previous.next = current.next; 3003 } else { 3004 mPendingEvents = current.next; 3005 } 3006 current.next = null; 3007 return current; 3008 } 3009 previous = current; 3010 current = current.next; 3011 } 3012 return null; 3013 } 3014 finishPendingEventLocked(PendingEvent pendingEvent)3015 private void finishPendingEventLocked(PendingEvent pendingEvent) { 3016 if (!pendingEvent.handled) { 3017 sendKeyEventToInputFilter(pendingEvent.event, pendingEvent.policyFlags); 3018 } 3019 // Nullify the event since we do not want it to be 3020 // recycled yet. It will be sent to the input filter. 3021 pendingEvent.event = null; 3022 recyclePendingEventLocked(pendingEvent); 3023 } 3024 sendKeyEventToInputFilter(KeyEvent event, int policyFlags)3025 private void sendKeyEventToInputFilter(KeyEvent event, int policyFlags) { 3026 if (DEBUG) { 3027 Slog.i(LOG_TAG, "Injecting event: " + event); 3028 } 3029 if (mSentEventsVerifier != null) { 3030 mSentEventsVerifier.onKeyEvent(event, 0); 3031 } 3032 policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER; 3033 mMainHandler.obtainMessage(MainHandler.MSG_SEND_KEY_EVENT_TO_INPUT_FILTER, 3034 policyFlags, 0, event).sendToTarget(); 3035 } 3036 cancelAllPendingEventsLocked()3037 private void cancelAllPendingEventsLocked() { 3038 while (mPendingEvents != null) { 3039 PendingEvent pendingEvent = removePendingEventLocked(mPendingEvents.sequence); 3040 pendingEvent.handled = false; 3041 mInvocationHandler.removeMessages(InvocationHandler.MSG_ON_KEY_EVENT_TIMEOUT, 3042 pendingEvent); 3043 finishPendingEventLocked(pendingEvent); 3044 } 3045 } 3046 } 3047 } 3048 3049 private static final class PendingEvent { 3050 PendingEvent next; 3051 3052 KeyEvent event; 3053 int policyFlags; 3054 int sequence; 3055 boolean handled; 3056 clear()3057 public void clear() { 3058 if (event != null) { 3059 event.recycle(); 3060 event = null; 3061 } 3062 next = null; 3063 policyFlags = 0; 3064 sequence = 0; 3065 handled = false; 3066 } 3067 } 3068 3069 final class WindowsForAccessibilityCallback implements 3070 WindowManagerInternal.WindowsForAccessibilityCallback { 3071 3072 @Override onWindowsForAccessibilityChanged(List<WindowInfo> windows)3073 public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) { 3074 synchronized (mLock) { 3075 // Populate the windows to report. 3076 List<AccessibilityWindowInfo> reportedWindows = new ArrayList<>(); 3077 final int receivedWindowCount = windows.size(); 3078 for (int i = 0; i < receivedWindowCount; i++) { 3079 WindowInfo receivedWindow = windows.get(i); 3080 AccessibilityWindowInfo reportedWindow = populateReportedWindow( 3081 receivedWindow); 3082 if (reportedWindow != null) { 3083 reportedWindows.add(reportedWindow); 3084 } 3085 } 3086 3087 if (DEBUG) { 3088 Slog.i(LOG_TAG, "Windows changed: " + reportedWindows); 3089 } 3090 3091 // Let the policy update the focused and active windows. 3092 mSecurityPolicy.updateWindowsLocked(reportedWindows); 3093 3094 // Someone may be waiting for the windows - advertise it. 3095 mLock.notifyAll(); 3096 } 3097 } 3098 populateReportedWindow(WindowInfo window)3099 private AccessibilityWindowInfo populateReportedWindow(WindowInfo window) { 3100 final int windowId = findWindowIdLocked(window.token); 3101 if (windowId < 0) { 3102 return null; 3103 } 3104 3105 AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); 3106 3107 reportedWindow.setId(windowId); 3108 reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); 3109 reportedWindow.setLayer(window.layer); 3110 reportedWindow.setFocused(window.focused); 3111 reportedWindow.setBoundsInScreen(window.boundsInScreen); 3112 3113 final int parentId = findWindowIdLocked(window.parentToken); 3114 if (parentId >= 0) { 3115 reportedWindow.setParentId(parentId); 3116 } 3117 3118 if (window.childTokens != null) { 3119 final int childCount = window.childTokens.size(); 3120 for (int i = 0; i < childCount; i++) { 3121 IBinder childToken = window.childTokens.get(i); 3122 final int childId = findWindowIdLocked(childToken); 3123 if (childId >= 0) { 3124 reportedWindow.addChild(childId); 3125 } 3126 } 3127 } 3128 3129 return reportedWindow; 3130 } 3131 getTypeForWindowManagerWindowType(int windowType)3132 private int getTypeForWindowManagerWindowType(int windowType) { 3133 switch (windowType) { 3134 case WindowManager.LayoutParams.TYPE_APPLICATION: 3135 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: 3136 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: 3137 case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: 3138 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: 3139 case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: 3140 case WindowManager.LayoutParams.TYPE_PHONE: 3141 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: 3142 case WindowManager.LayoutParams.TYPE_TOAST: 3143 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: { 3144 return AccessibilityWindowInfo.TYPE_APPLICATION; 3145 } 3146 3147 case WindowManager.LayoutParams.TYPE_INPUT_METHOD: 3148 case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { 3149 return AccessibilityWindowInfo.TYPE_INPUT_METHOD; 3150 } 3151 3152 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: 3153 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: 3154 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: 3155 case WindowManager.LayoutParams.TYPE_SEARCH_BAR: 3156 case WindowManager.LayoutParams.TYPE_STATUS_BAR: 3157 case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: 3158 case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: 3159 case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: 3160 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: 3161 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: 3162 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: 3163 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: 3164 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: { 3165 return AccessibilityWindowInfo.TYPE_SYSTEM; 3166 } 3167 3168 default: { 3169 return -1; 3170 } 3171 } 3172 } 3173 } 3174 3175 private final class InteractionBridge { 3176 private final Display mDefaultDisplay; 3177 private final int mConnectionId; 3178 private final AccessibilityInteractionClient mClient; 3179 InteractionBridge()3180 public InteractionBridge() { 3181 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 3182 info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); 3183 info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 3184 info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 3185 Service service = new Service(UserHandle.USER_NULL, 3186 sFakeAccessibilityServiceComponentName, info); 3187 3188 mConnectionId = service.mId; 3189 3190 mClient = AccessibilityInteractionClient.getInstance(); 3191 mClient.addConnection(mConnectionId, service); 3192 3193 //TODO: (multi-display) We need to support multiple displays. 3194 DisplayManager displayManager = (DisplayManager) 3195 mContext.getSystemService(Context.DISPLAY_SERVICE); 3196 mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 3197 } 3198 clearAccessibilityFocusNotLocked(int windowId)3199 public void clearAccessibilityFocusNotLocked(int windowId) { 3200 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId); 3201 if (focus != null) { 3202 focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 3203 } 3204 } 3205 getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint)3206 public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { 3207 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); 3208 if (focus == null) { 3209 return false; 3210 } 3211 3212 synchronized (mLock) { 3213 Point point = mClient.computeClickPointInScreen(mConnectionId, 3214 focus.getWindowId(), focus.getSourceNodeId()); 3215 3216 if (point == null) { 3217 return false; 3218 } 3219 3220 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId()); 3221 if (spec != null && !spec.isNop()) { 3222 point.offset((int) -spec.offsetX, (int) -spec.offsetY); 3223 point.x = (int) (point.x * (1 / spec.scale)); 3224 point.y = (int) (point.y * (1 / spec.scale)); 3225 } 3226 3227 // Make sure the point is within the window. 3228 Rect windowBounds = mTempRect; 3229 getActiveWindowBounds(windowBounds); 3230 if (!windowBounds.contains(point.x, point.y)) { 3231 return false; 3232 } 3233 3234 // Make sure the point is within the screen. 3235 Point screenSize = mTempPoint; 3236 mDefaultDisplay.getRealSize(screenSize); 3237 if (point.x < 0 || point.x > screenSize.x 3238 || point.y < 0 || point.y > screenSize.y) { 3239 return false; 3240 } 3241 3242 outPoint.set(point.x, point.y); 3243 return true; 3244 } 3245 } 3246 getAccessibilityFocusNotLocked()3247 private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { 3248 final int focusedWindowId; 3249 synchronized (mLock) { 3250 focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId; 3251 if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) { 3252 return null; 3253 } 3254 } 3255 return getAccessibilityFocusNotLocked(focusedWindowId); 3256 } 3257 getAccessibilityFocusNotLocked(int windowId)3258 private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) { 3259 return mClient.findFocus(mConnectionId, 3260 windowId, AccessibilityNodeInfo.ROOT_NODE_ID, 3261 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 3262 } 3263 } 3264 3265 final class SecurityPolicy { 3266 public static final int INVALID_WINDOW_ID = -1; 3267 3268 private static final int RETRIEVAL_ALLOWING_EVENT_TYPES = 3269 AccessibilityEvent.TYPE_VIEW_CLICKED 3270 | AccessibilityEvent.TYPE_VIEW_FOCUSED 3271 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 3272 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 3273 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 3274 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 3275 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 3276 | AccessibilityEvent.TYPE_VIEW_SELECTED 3277 | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 3278 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 3279 | AccessibilityEvent.TYPE_VIEW_SCROLLED 3280 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 3281 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 3282 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 3283 3284 public List<AccessibilityWindowInfo> mWindows; 3285 3286 public int mActiveWindowId = INVALID_WINDOW_ID; 3287 public int mFocusedWindowId = INVALID_WINDOW_ID; 3288 public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID; 3289 public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 3290 3291 public AccessibilityEvent mShowingFocusedWindowEvent; 3292 3293 private boolean mTouchInteractionInProgress; 3294 canDispatchAccessibilityEventLocked(AccessibilityEvent event)3295 private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) { 3296 final int eventType = event.getEventType(); 3297 switch (eventType) { 3298 // All events that are for changes in a global window 3299 // state should *always* be dispatched. 3300 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: 3301 if (mWindowsForAccessibilityCallback != null) { 3302 // OK, this is fun. Sometimes the focused window is notified 3303 // it has focus before being shown. Historically this event 3304 // means that the window is focused and can be introspected. 3305 // But we still have not gotten the window state from the 3306 // window manager, so delay the notification until then. 3307 AccessibilityWindowInfo window = findWindowById(event.getWindowId()); 3308 if (window == null) { 3309 mShowingFocusedWindowEvent = AccessibilityEvent.obtain(event); 3310 return false; 3311 } 3312 } 3313 // $fall-through$ 3314 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: 3315 case AccessibilityEvent.TYPE_ANNOUNCEMENT: 3316 // All events generated by the user touching the 3317 // screen should *always* be dispatched. 3318 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: 3319 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: 3320 case AccessibilityEvent.TYPE_GESTURE_DETECTION_START: 3321 case AccessibilityEvent.TYPE_GESTURE_DETECTION_END: 3322 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START: 3323 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: 3324 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: 3325 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: 3326 // Also windows changing should always be anounced. 3327 case AccessibilityEvent.TYPE_WINDOWS_CHANGED: { 3328 return true; 3329 } 3330 // All events for changes in window content should be 3331 // dispatched *only* if this window is one of the windows 3332 // the accessibility layer reports which are windows 3333 // that a sighted user can touch. 3334 default: { 3335 return isRetrievalAllowingWindow(event.getWindowId()); 3336 } 3337 } 3338 } 3339 clearWindowsLocked()3340 public void clearWindowsLocked() { 3341 List<AccessibilityWindowInfo> windows = Collections.emptyList(); 3342 final int activeWindowId = mActiveWindowId; 3343 updateWindowsLocked(windows); 3344 mActiveWindowId = activeWindowId; 3345 mWindows = null; 3346 } 3347 updateWindowsLocked(List<AccessibilityWindowInfo> windows)3348 public void updateWindowsLocked(List<AccessibilityWindowInfo> windows) { 3349 if (mWindows == null) { 3350 mWindows = new ArrayList<>(); 3351 } 3352 3353 final int oldWindowCount = mWindows.size(); 3354 for (int i = oldWindowCount - 1; i >= 0; i--) { 3355 mWindows.remove(i).recycle(); 3356 } 3357 3358 mFocusedWindowId = INVALID_WINDOW_ID; 3359 if (!mTouchInteractionInProgress) { 3360 mActiveWindowId = INVALID_WINDOW_ID; 3361 } 3362 3363 // If the active window goes away while the user is touch exploring we 3364 // reset the active window id and wait for the next hover event from 3365 // under the user's finger to determine which one is the new one. It 3366 // is possible that the finger is not moving and the input system 3367 // filters out such events. 3368 boolean activeWindowGone = true; 3369 3370 final int windowCount = windows.size(); 3371 if (windowCount > 0) { 3372 for (int i = 0; i < windowCount; i++) { 3373 AccessibilityWindowInfo window = windows.get(i); 3374 final int windowId = window.getId(); 3375 if (window.isFocused()) { 3376 mFocusedWindowId = windowId; 3377 if (!mTouchInteractionInProgress) { 3378 mActiveWindowId = windowId; 3379 window.setActive(true); 3380 } else if (windowId == mActiveWindowId) { 3381 activeWindowGone = false; 3382 } 3383 } 3384 mWindows.add(window); 3385 } 3386 3387 if (mTouchInteractionInProgress && activeWindowGone) { 3388 mActiveWindowId = mFocusedWindowId; 3389 } 3390 3391 // Focused window may change the active one, so set the 3392 // active window once we decided which it is. 3393 for (int i = 0; i < windowCount; i++) { 3394 AccessibilityWindowInfo window = mWindows.get(i); 3395 if (window.getId() == mActiveWindowId) { 3396 window.setActive(true); 3397 } 3398 if (window.getId() == mAccessibilityFocusedWindowId) { 3399 window.setAccessibilityFocused(true); 3400 } 3401 } 3402 } 3403 3404 notifyWindowsChanged(); 3405 3406 // If we are delaying a window state change event as the window 3407 // source was showing when it was fired, now is the time to send. 3408 if (mShowingFocusedWindowEvent != null) { 3409 final int windowId = mShowingFocusedWindowEvent.getWindowId(); 3410 AccessibilityWindowInfo window = findWindowById(windowId); 3411 if (window != null) { 3412 // Sending does the recycle. 3413 sendAccessibilityEvent(mShowingFocusedWindowEvent, mCurrentUserId); 3414 } 3415 mShowingFocusedWindowEvent = null; 3416 } 3417 } 3418 computePartialInteractiveRegionForWindowLocked(int windowId, Region outRegion)3419 public boolean computePartialInteractiveRegionForWindowLocked(int windowId, 3420 Region outRegion) { 3421 if (mWindows == null) { 3422 return false; 3423 } 3424 3425 // Windows are ordered in z order so start from the botton and find 3426 // the window of interest. After that all windows that cover it should 3427 // be subtracted from the resulting region. Note that for accessibility 3428 // we are returning only interactive windows. 3429 Region windowInteractiveRegion = null; 3430 boolean windowInteractiveRegionChanged = false; 3431 3432 final int windowCount = mWindows.size(); 3433 for (int i = windowCount - 1; i >= 0; i--) { 3434 AccessibilityWindowInfo currentWindow = mWindows.get(i); 3435 if (windowInteractiveRegion == null) { 3436 if (currentWindow.getId() == windowId) { 3437 Rect currentWindowBounds = mTempRect; 3438 currentWindow.getBoundsInScreen(currentWindowBounds); 3439 outRegion.set(currentWindowBounds); 3440 windowInteractiveRegion = outRegion; 3441 continue; 3442 } 3443 } else { 3444 Rect currentWindowBounds = mTempRect; 3445 currentWindow.getBoundsInScreen(currentWindowBounds); 3446 if (windowInteractiveRegion.op(currentWindowBounds, Region.Op.DIFFERENCE)) { 3447 windowInteractiveRegionChanged = true; 3448 } 3449 } 3450 } 3451 3452 return windowInteractiveRegionChanged; 3453 } 3454 updateEventSourceLocked(AccessibilityEvent event)3455 public void updateEventSourceLocked(AccessibilityEvent event) { 3456 if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) { 3457 event.setSource(null); 3458 } 3459 } 3460 updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId, int eventType)3461 public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId, 3462 int eventType) { 3463 // The active window is either the window that has input focus or 3464 // the window that the user is currently touching. If the user is 3465 // touching a window that does not have input focus as soon as the 3466 // the user stops touching that window the focused window becomes 3467 // the active one. Here we detect the touched window and make it 3468 // active. In updateWindowsLocked() we update the focused window 3469 // and if the user is not touching the screen, we make the focused 3470 // window the active one. 3471 switch (eventType) { 3472 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: { 3473 // If no service has the capability to introspect screen, 3474 // we do not register callback in the window manager for 3475 // window changes, so we have to ask the window manager 3476 // what the focused window is to update the active one. 3477 // The active window also determined events from which 3478 // windows are delivered. 3479 synchronized (mLock) { 3480 if (mWindowsForAccessibilityCallback == null) { 3481 mFocusedWindowId = getFocusedWindowId(); 3482 if (windowId == mFocusedWindowId) { 3483 mActiveWindowId = windowId; 3484 } 3485 } 3486 } 3487 } break; 3488 3489 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: { 3490 // Do not allow delayed hover events to confuse us 3491 // which the active window is. 3492 synchronized (mLock) { 3493 if (mTouchInteractionInProgress && mActiveWindowId != windowId) { 3494 setActiveWindowLocked(windowId); 3495 } 3496 } 3497 } break; 3498 3499 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 3500 synchronized (mLock) { 3501 if (mAccessibilityFocusedWindowId != windowId) { 3502 mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS, 3503 mAccessibilityFocusedWindowId, 0).sendToTarget(); 3504 mSecurityPolicy.setAccessibilityFocusedWindowLocked(windowId); 3505 mAccessibilityFocusNodeId = nodeId; 3506 } 3507 } 3508 } break; 3509 3510 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 3511 synchronized (mLock) { 3512 if (mAccessibilityFocusNodeId == nodeId) { 3513 mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 3514 } 3515 if (mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID 3516 && mAccessibilityFocusedWindowId == windowId) { 3517 mAccessibilityFocusedWindowId = INVALID_WINDOW_ID; 3518 } 3519 } 3520 } break; 3521 } 3522 } 3523 onTouchInteractionStart()3524 public void onTouchInteractionStart() { 3525 synchronized (mLock) { 3526 mTouchInteractionInProgress = true; 3527 } 3528 } 3529 onTouchInteractionEnd()3530 public void onTouchInteractionEnd() { 3531 synchronized (mLock) { 3532 mTouchInteractionInProgress = false; 3533 // We want to set the active window to be current immediately 3534 // after the user has stopped touching the screen since if the 3535 // user types with the IME he should get a feedback for the 3536 // letter typed in the text view which is in the input focused 3537 // window. Note that we always deliver hover accessibility events 3538 // (they are a result of user touching the screen) so change of 3539 // the active window before all hover accessibility events from 3540 // the touched window are delivered is fine. 3541 final int oldActiveWindow = mSecurityPolicy.mActiveWindowId; 3542 setActiveWindowLocked(mFocusedWindowId); 3543 3544 // If there is no service that can operate with active windows 3545 // we keep accessibility focus behavior to constrain it only in 3546 // the active window. Look at updateAccessibilityFocusBehaviorLocked 3547 // for details. 3548 if (oldActiveWindow != mSecurityPolicy.mActiveWindowId 3549 && mAccessibilityFocusedWindowId == oldActiveWindow 3550 && getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) { 3551 mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS, 3552 oldActiveWindow, 0).sendToTarget(); 3553 } 3554 } 3555 } 3556 getActiveWindowId()3557 public int getActiveWindowId() { 3558 if (mActiveWindowId == INVALID_WINDOW_ID && !mTouchInteractionInProgress) { 3559 mActiveWindowId = getFocusedWindowId(); 3560 } 3561 return mActiveWindowId; 3562 } 3563 setActiveWindowLocked(int windowId)3564 private void setActiveWindowLocked(int windowId) { 3565 if (mActiveWindowId != windowId) { 3566 mActiveWindowId = windowId; 3567 if (mWindows != null) { 3568 final int windowCount = mWindows.size(); 3569 for (int i = 0; i < windowCount; i++) { 3570 AccessibilityWindowInfo window = mWindows.get(i); 3571 window.setActive(window.getId() == windowId); 3572 } 3573 } 3574 notifyWindowsChanged(); 3575 } 3576 } 3577 setAccessibilityFocusedWindowLocked(int windowId)3578 private void setAccessibilityFocusedWindowLocked(int windowId) { 3579 if (mAccessibilityFocusedWindowId != windowId) { 3580 mAccessibilityFocusedWindowId = windowId; 3581 if (mWindows != null) { 3582 final int windowCount = mWindows.size(); 3583 for (int i = 0; i < windowCount; i++) { 3584 AccessibilityWindowInfo window = mWindows.get(i); 3585 window.setAccessibilityFocused(window.getId() == windowId); 3586 } 3587 } 3588 3589 notifyWindowsChanged(); 3590 } 3591 } 3592 notifyWindowsChanged()3593 private void notifyWindowsChanged() { 3594 if (mWindowsForAccessibilityCallback == null) { 3595 return; 3596 } 3597 final long identity = Binder.clearCallingIdentity(); 3598 try { 3599 // Let the client know the windows changed. 3600 AccessibilityEvent event = AccessibilityEvent.obtain( 3601 AccessibilityEvent.TYPE_WINDOWS_CHANGED); 3602 event.setEventTime(SystemClock.uptimeMillis()); 3603 sendAccessibilityEvent(event, mCurrentUserId); 3604 } finally { 3605 Binder.restoreCallingIdentity(identity); 3606 } 3607 } 3608 canGetAccessibilityNodeInfoLocked(Service service, int windowId)3609 public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) { 3610 return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); 3611 } 3612 canRetrieveWindowsLocked(Service service)3613 public boolean canRetrieveWindowsLocked(Service service) { 3614 return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows; 3615 } 3616 canRetrieveWindowContentLocked(Service service)3617 public boolean canRetrieveWindowContentLocked(Service service) { 3618 return (service.mAccessibilityServiceInfo.getCapabilities() 3619 & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 3620 } 3621 resolveProfileParentLocked(int userId)3622 private int resolveProfileParentLocked(int userId) { 3623 if (userId != mCurrentUserId) { 3624 final long identity = Binder.clearCallingIdentity(); 3625 try { 3626 UserInfo parent = mUserManager.getProfileParent(userId); 3627 if (parent != null) { 3628 return parent.getUserHandle().getIdentifier(); 3629 } 3630 } finally { 3631 Binder.restoreCallingIdentity(identity); 3632 } 3633 } 3634 return userId; 3635 } 3636 resolveCallingUserIdEnforcingPermissionsLocked(int userId)3637 public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) { 3638 final int callingUid = Binder.getCallingUid(); 3639 if (callingUid == 0 3640 || callingUid == Process.SYSTEM_UID 3641 || callingUid == Process.SHELL_UID) { 3642 if (userId == UserHandle.USER_CURRENT 3643 || userId == UserHandle.USER_CURRENT_OR_SELF) { 3644 return mCurrentUserId; 3645 } 3646 return resolveProfileParentLocked(userId); 3647 } 3648 final int callingUserId = UserHandle.getUserId(callingUid); 3649 if (callingUserId == userId) { 3650 return resolveProfileParentLocked(userId); 3651 } 3652 final int callingUserParentId = resolveProfileParentLocked(callingUserId); 3653 if (callingUserParentId == mCurrentUserId && 3654 (userId == UserHandle.USER_CURRENT 3655 || userId == UserHandle.USER_CURRENT_OR_SELF)) { 3656 return mCurrentUserId; 3657 } 3658 if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) 3659 && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { 3660 throw new SecurityException("Call from user " + callingUserId + " as user " 3661 + userId + " without permission INTERACT_ACROSS_USERS or " 3662 + "INTERACT_ACROSS_USERS_FULL not allowed."); 3663 } 3664 if (userId == UserHandle.USER_CURRENT 3665 || userId == UserHandle.USER_CURRENT_OR_SELF) { 3666 return mCurrentUserId; 3667 } 3668 throw new IllegalArgumentException("Calling user can be changed to only " 3669 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); 3670 } 3671 isCallerInteractingAcrossUsers(int userId)3672 public boolean isCallerInteractingAcrossUsers(int userId) { 3673 final int callingUid = Binder.getCallingUid(); 3674 return (Binder.getCallingPid() == android.os.Process.myPid() 3675 || callingUid == Process.SHELL_UID 3676 || userId == UserHandle.USER_CURRENT 3677 || userId == UserHandle.USER_CURRENT_OR_SELF); 3678 } 3679 isRetrievalAllowingWindow(int windowId)3680 private boolean isRetrievalAllowingWindow(int windowId) { 3681 // The system gets to interact with any window it wants. 3682 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 3683 return true; 3684 } 3685 if (windowId == mActiveWindowId) { 3686 return true; 3687 } 3688 return findWindowById(windowId) != null; 3689 } 3690 findWindowById(int windowId)3691 private AccessibilityWindowInfo findWindowById(int windowId) { 3692 if (mWindows != null) { 3693 final int windowCount = mWindows.size(); 3694 for (int i = 0; i < windowCount; i++) { 3695 AccessibilityWindowInfo window = mWindows.get(i); 3696 if (window.getId() == windowId) { 3697 return window; 3698 } 3699 } 3700 } 3701 return null; 3702 } 3703 enforceCallingPermission(String permission, String function)3704 private void enforceCallingPermission(String permission, String function) { 3705 if (OWN_PROCESS_ID == Binder.getCallingPid()) { 3706 return; 3707 } 3708 if (!hasPermission(permission)) { 3709 throw new SecurityException("You do not have " + permission 3710 + " required to call " + function + " from pid=" 3711 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 3712 } 3713 } 3714 hasPermission(String permission)3715 private boolean hasPermission(String permission) { 3716 return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; 3717 } 3718 getFocusedWindowId()3719 private int getFocusedWindowId() { 3720 IBinder token = mWindowManagerService.getFocusedWindowToken(); 3721 synchronized (mLock) { 3722 return findWindowIdLocked(token); 3723 } 3724 } 3725 } 3726 3727 private class UserState { 3728 public final int mUserId; 3729 3730 // Non-transient state. 3731 3732 public final RemoteCallbackList<IAccessibilityManagerClient> mClients = 3733 new RemoteCallbackList<>(); 3734 3735 public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections = 3736 new SparseArray<>(); 3737 3738 public final SparseArray<IBinder> mWindowTokens = new SparseArray<>(); 3739 3740 // Transient state. 3741 3742 public final CopyOnWriteArrayList<Service> mBoundServices = 3743 new CopyOnWriteArrayList<>(); 3744 3745 public final Map<ComponentName, Service> mComponentNameToServiceMap = 3746 new HashMap<>(); 3747 3748 public final List<AccessibilityServiceInfo> mInstalledServices = 3749 new ArrayList<>(); 3750 3751 public final Set<ComponentName> mBindingServices = new HashSet<>(); 3752 3753 public final Set<ComponentName> mEnabledServices = new HashSet<>(); 3754 3755 public final Set<ComponentName> mTouchExplorationGrantedServices = 3756 new HashSet<>(); 3757 3758 public int mHandledFeedbackTypes = 0; 3759 3760 public int mLastSentClientState = -1; 3761 3762 public boolean mIsAccessibilityEnabled; 3763 public boolean mIsTouchExplorationEnabled; 3764 public boolean mIsTextHighContrastEnabled; 3765 public boolean mIsEnhancedWebAccessibilityEnabled; 3766 public boolean mIsDisplayMagnificationEnabled; 3767 public boolean mIsFilterKeyEventsEnabled; 3768 public boolean mHasDisplayColorAdjustment; 3769 public boolean mAccessibilityFocusOnlyInActiveWindow; 3770 3771 private Service mUiAutomationService; 3772 private IAccessibilityServiceClient mUiAutomationServiceClient; 3773 3774 private IBinder mUiAutomationServiceOwner; 3775 private final DeathRecipient mUiAutomationSerivceOnwerDeathRecipient = 3776 new DeathRecipient() { 3777 @Override 3778 public void binderDied() { 3779 mUiAutomationServiceOwner.unlinkToDeath( 3780 mUiAutomationSerivceOnwerDeathRecipient, 0); 3781 mUiAutomationServiceOwner = null; 3782 if (mUiAutomationService != null) { 3783 mUiAutomationService.binderDied(); 3784 } 3785 } 3786 }; 3787 UserState(int userId)3788 public UserState(int userId) { 3789 mUserId = userId; 3790 } 3791 getClientState()3792 public int getClientState() { 3793 int clientState = 0; 3794 if (mIsAccessibilityEnabled) { 3795 clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; 3796 } 3797 // Touch exploration relies on enabled accessibility. 3798 if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { 3799 clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; 3800 } 3801 if (mIsTextHighContrastEnabled) { 3802 clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED; 3803 } 3804 return clientState; 3805 } 3806 onSwitchToAnotherUser()3807 public void onSwitchToAnotherUser() { 3808 // Clear UI test automation state. 3809 if (mUiAutomationService != null) { 3810 mUiAutomationService.binderDied(); 3811 } 3812 3813 // Unbind all services. 3814 unbindAllServicesLocked(this); 3815 3816 // Clear service management state. 3817 mBoundServices.clear(); 3818 mBindingServices.clear(); 3819 3820 // Clear event management state. 3821 mHandledFeedbackTypes = 0; 3822 mLastSentClientState = -1; 3823 3824 // Clear state persisted in settings. 3825 mEnabledServices.clear(); 3826 mTouchExplorationGrantedServices.clear(); 3827 mIsAccessibilityEnabled = false; 3828 mIsTouchExplorationEnabled = false; 3829 mIsEnhancedWebAccessibilityEnabled = false; 3830 mIsDisplayMagnificationEnabled = false; 3831 } 3832 destroyUiAutomationService()3833 public void destroyUiAutomationService() { 3834 mUiAutomationService = null; 3835 mUiAutomationServiceClient = null; 3836 if (mUiAutomationServiceOwner != null) { 3837 mUiAutomationServiceOwner.unlinkToDeath( 3838 mUiAutomationSerivceOnwerDeathRecipient, 0); 3839 mUiAutomationServiceOwner = null; 3840 } 3841 } 3842 } 3843 3844 private final class AccessibilityContentObserver extends ContentObserver { 3845 3846 private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor( 3847 Settings.Secure.ACCESSIBILITY_ENABLED); 3848 3849 private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor( 3850 Settings.Secure.TOUCH_EXPLORATION_ENABLED); 3851 3852 private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor( 3853 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 3854 3855 private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor( 3856 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 3857 3858 private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure 3859 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); 3860 3861 private final Uri mEnhancedWebAccessibilityUri = Settings.Secure 3862 .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION); 3863 3864 private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor( 3865 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); 3866 3867 private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor( 3868 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED); 3869 3870 private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor( 3871 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER); 3872 3873 private final Uri mHighTextContrastUri = Settings.Secure.getUriFor( 3874 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED); 3875 AccessibilityContentObserver(Handler handler)3876 public AccessibilityContentObserver(Handler handler) { 3877 super(handler); 3878 } 3879 register(ContentResolver contentResolver)3880 public void register(ContentResolver contentResolver) { 3881 contentResolver.registerContentObserver(mAccessibilityEnabledUri, 3882 false, this, UserHandle.USER_ALL); 3883 contentResolver.registerContentObserver(mTouchExplorationEnabledUri, 3884 false, this, UserHandle.USER_ALL); 3885 contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri, 3886 false, this, UserHandle.USER_ALL); 3887 contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri, 3888 false, this, UserHandle.USER_ALL); 3889 contentResolver.registerContentObserver( 3890 mTouchExplorationGrantedAccessibilityServicesUri, 3891 false, this, UserHandle.USER_ALL); 3892 contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri, 3893 false, this, UserHandle.USER_ALL); 3894 contentResolver.registerContentObserver( 3895 mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL); 3896 contentResolver.registerContentObserver( 3897 mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL); 3898 contentResolver.registerContentObserver( 3899 mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL); 3900 contentResolver.registerContentObserver( 3901 mHighTextContrastUri, false, this, UserHandle.USER_ALL); 3902 } 3903 3904 @Override onChange(boolean selfChange, Uri uri)3905 public void onChange(boolean selfChange, Uri uri) { 3906 synchronized (mLock) { 3907 // Profiles share the accessibility state of the parent. Therefore, 3908 // we are checking for changes only the parent settings. 3909 UserState userState = getCurrentUserStateLocked(); 3910 3911 // We will update when the automation service dies. 3912 if (userState.mUiAutomationService != null) { 3913 return; 3914 } 3915 3916 if (mAccessibilityEnabledUri.equals(uri)) { 3917 if (readAccessibilityEnabledSettingLocked(userState)) { 3918 onUserStateChangedLocked(userState); 3919 } 3920 } else if (mTouchExplorationEnabledUri.equals(uri)) { 3921 if (readTouchExplorationEnabledSettingLocked(userState)) { 3922 onUserStateChangedLocked(userState); 3923 } 3924 } else if (mDisplayMagnificationEnabledUri.equals(uri)) { 3925 if (readDisplayMagnificationEnabledSettingLocked(userState)) { 3926 onUserStateChangedLocked(userState); 3927 } 3928 } else if (mEnabledAccessibilityServicesUri.equals(uri)) { 3929 if (readEnabledAccessibilityServicesLocked(userState)) { 3930 onUserStateChangedLocked(userState); 3931 } 3932 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { 3933 if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) { 3934 onUserStateChangedLocked(userState); 3935 } 3936 } else if (mEnhancedWebAccessibilityUri.equals(uri)) { 3937 if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) { 3938 onUserStateChangedLocked(userState); 3939 } 3940 } else if (mDisplayInversionEnabledUri.equals(uri) 3941 || mDisplayDaltonizerEnabledUri.equals(uri) 3942 || mDisplayDaltonizerUri.equals(uri)) { 3943 if (readDisplayColorAdjustmentSettingsLocked(userState)) { 3944 updateDisplayColorAdjustmentSettingsLocked(userState); 3945 } 3946 } else if (mHighTextContrastUri.equals(uri)) { 3947 if (readHighTextContrastEnabledSettingLocked(userState)) { 3948 onUserStateChangedLocked(userState); 3949 } 3950 } 3951 } 3952 } 3953 } 3954 } 3955