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