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