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