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