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