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