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