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