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