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