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