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