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