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