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 // The service that's bound to this instance. Whenever this value is non-null, this 2212 // object is registered as a death recipient 2213 IBinder mService; 2214 2215 IAccessibilityServiceClient mServiceInterface; 2216 2217 int mEventTypes; 2218 2219 int mFeedbackType; 2220 2221 Set<String> mPackageNames = new HashSet<>(); 2222 2223 boolean mIsDefault; 2224 2225 boolean mRequestTouchExplorationMode; 2226 2227 boolean mRequestEnhancedWebAccessibility; 2228 2229 boolean mRequestFilterKeyEvents; 2230 2231 boolean mRetrieveInteractiveWindows; 2232 2233 int mFetchFlags; 2234 2235 long mNotificationTimeout; 2236 2237 ComponentName mComponentName; 2238 2239 Intent mIntent; 2240 2241 boolean mIsAutomation; 2242 2243 final ResolveInfo mResolveInfo; 2244 2245 final IBinder mOverlayWindowToken = new Binder(); 2246 2247 // the events pending events to be dispatched to this service 2248 final SparseArray<AccessibilityEvent> mPendingEvents = 2249 new SparseArray<>(); 2250 2251 boolean mWasConnectedAndDied; 2252 2253 // Handler only for dispatching accessibility events since we use event 2254 // types as message types allowing us to remove messages per event type. 2255 public Handler mEventDispatchHandler = new Handler(mMainHandler.getLooper()) { 2256 @Override 2257 public void handleMessage(Message message) { 2258 final int eventType = message.what; 2259 AccessibilityEvent event = (AccessibilityEvent) message.obj; 2260 notifyAccessibilityEventInternal(eventType, event); 2261 } 2262 }; 2263 2264 // Handler for scheduling method invocations on the main thread. 2265 public final InvocationHandler mInvocationHandler = new InvocationHandler( 2266 mMainHandler.getLooper()); 2267 2268 public Service(int userId, ComponentName componentName, 2269 AccessibilityServiceInfo accessibilityServiceInfo) { 2270 mUserId = userId; 2271 mResolveInfo = accessibilityServiceInfo.getResolveInfo(); 2272 mId = sIdCounter++; 2273 mComponentName = componentName; 2274 mAccessibilityServiceInfo = accessibilityServiceInfo; 2275 mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName)); 2276 if (!mIsAutomation) { 2277 mIntent = new Intent().setComponent(mComponentName); 2278 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, 2279 com.android.internal.R.string.accessibility_binding_label); 2280 final long idendtity = Binder.clearCallingIdentity(); 2281 try { 2282 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( 2283 mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0)); 2284 } finally { 2285 Binder.restoreCallingIdentity(idendtity); 2286 } 2287 } 2288 setDynamicallyConfigurableProperties(accessibilityServiceInfo); 2289 } 2290 2291 public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { 2292 mEventTypes = info.eventTypes; 2293 mFeedbackType = info.feedbackType; 2294 String[] packageNames = info.packageNames; 2295 if (packageNames != null) { 2296 mPackageNames.addAll(Arrays.asList(packageNames)); 2297 } 2298 mNotificationTimeout = info.notificationTimeout; 2299 mIsDefault = (info.flags & DEFAULT) != 0; 2300 2301 if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 2302 >= Build.VERSION_CODES.JELLY_BEAN) { 2303 if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) { 2304 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 2305 } else { 2306 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 2307 } 2308 } 2309 2310 if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) { 2311 mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 2312 } else { 2313 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 2314 } 2315 2316 mRequestTouchExplorationMode = (info.flags 2317 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; 2318 mRequestEnhancedWebAccessibility = (info.flags 2319 & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0; 2320 mRequestFilterKeyEvents = (info.flags 2321 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; 2322 mRetrieveInteractiveWindows = (info.flags 2323 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; 2324 } 2325 2326 /** 2327 * Binds to the accessibility service. 2328 * 2329 * @return True if binding is successful. 2330 */ 2331 public boolean bindLocked() { 2332 UserState userState = getUserStateLocked(mUserId); 2333 if (!mIsAutomation) { 2334 final long identity = Binder.clearCallingIdentity(); 2335 try { 2336 if (mService == null && mContext.bindServiceAsUser( 2337 mIntent, this, 2338 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, 2339 new UserHandle(mUserId))) { 2340 userState.mBindingServices.add(mComponentName); 2341 } 2342 } finally { 2343 Binder.restoreCallingIdentity(identity); 2344 } 2345 } else { 2346 userState.mBindingServices.add(mComponentName); 2347 mMainHandler.post(new Runnable() { 2348 @Override 2349 public void run() { 2350 // Simulate asynchronous connection since in onServiceConnected 2351 // we may modify the state data in case of an error but bind is 2352 // called while iterating over the data and bad things can happen. 2353 onServiceConnected(mComponentName, 2354 userState.mUiAutomationServiceClient.asBinder()); 2355 } 2356 }); 2357 userState.mUiAutomationService = this; 2358 } 2359 return false; 2360 } 2361 2362 /** 2363 * Unbinds from the accessibility service and removes it from the data 2364 * structures for service management. 2365 * 2366 * @return True if unbinding is successful. 2367 */ 2368 public boolean unbindLocked() { 2369 UserState userState = getUserStateLocked(mUserId); 2370 getKeyEventDispatcher().flush(this); 2371 if (!mIsAutomation) { 2372 mContext.unbindService(this); 2373 } else { 2374 userState.destroyUiAutomationService(); 2375 } 2376 removeServiceLocked(this, userState); 2377 resetLocked(); 2378 return true; 2379 } 2380 2381 @Override 2382 public void disableSelf() { 2383 synchronized(mLock) { 2384 UserState userState = getUserStateLocked(mUserId); 2385 if (userState.mEnabledServices.remove(mComponentName)) { 2386 final long identity = Binder.clearCallingIdentity(); 2387 try { 2388 persistComponentNamesToSettingLocked( 2389 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 2390 userState.mEnabledServices, mUserId); 2391 } finally { 2392 Binder.restoreCallingIdentity(identity); 2393 } 2394 onUserStateChangedLocked(userState); 2395 } 2396 } 2397 } 2398 2399 public boolean canReceiveEventsLocked() { 2400 return (mEventTypes != 0 && mFeedbackType != 0 && mService != null); 2401 } 2402 2403 @Override 2404 public void setOnKeyEventResult(boolean handled, int sequence) { 2405 getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence); 2406 } 2407 2408 @Override 2409 public AccessibilityServiceInfo getServiceInfo() { 2410 synchronized (mLock) { 2411 return mAccessibilityServiceInfo; 2412 } 2413 } 2414 2415 public boolean canRetrieveInteractiveWindowsLocked() { 2416 return mSecurityPolicy.canRetrieveWindowContentLocked(this) 2417 && mRetrieveInteractiveWindows; 2418 } 2419 2420 @Override 2421 public void setServiceInfo(AccessibilityServiceInfo info) { 2422 final long identity = Binder.clearCallingIdentity(); 2423 try { 2424 synchronized (mLock) { 2425 // If the XML manifest had data to configure the service its info 2426 // should be already set. In such a case update only the dynamically 2427 // configurable properties. 2428 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; 2429 if (oldInfo != null) { 2430 oldInfo.updateDynamicallyConfigurableProperties(info); 2431 setDynamicallyConfigurableProperties(oldInfo); 2432 } else { 2433 setDynamicallyConfigurableProperties(info); 2434 } 2435 UserState userState = getUserStateLocked(mUserId); 2436 onUserStateChangedLocked(userState); 2437 } 2438 } finally { 2439 Binder.restoreCallingIdentity(identity); 2440 } 2441 } 2442 2443 @Override 2444 public void onServiceConnected(ComponentName componentName, IBinder service) { 2445 synchronized (mLock) { 2446 if (mService != service) { 2447 if (mService != null) { 2448 mService.unlinkToDeath(this, 0); 2449 } 2450 mService = service; 2451 try { 2452 mService.linkToDeath(this, 0); 2453 } catch (RemoteException re) { 2454 Slog.e(LOG_TAG, "Failed registering death link"); 2455 binderDied(); 2456 return; 2457 } 2458 } 2459 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); 2460 UserState userState = getUserStateLocked(mUserId); 2461 addServiceLocked(this, userState); 2462 if (userState.mBindingServices.contains(mComponentName) || mWasConnectedAndDied) { 2463 userState.mBindingServices.remove(mComponentName); 2464 mWasConnectedAndDied = false; 2465 try { 2466 mServiceInterface.init(this, mId, mOverlayWindowToken); 2467 onUserStateChangedLocked(userState); 2468 } catch (RemoteException re) { 2469 Slog.w(LOG_TAG, "Error while setting connection for service: " 2470 + service, re); 2471 binderDied(); 2472 } 2473 } else { 2474 binderDied(); 2475 } 2476 } 2477 } 2478 2479 private boolean isCalledForCurrentUserLocked() { 2480 // We treat calls from a profile as if made by its parent as profiles 2481 // share the accessibility state of the parent. The call below 2482 // performs the current profile parent resolution. 2483 final int resolvedUserId = mSecurityPolicy 2484 .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT); 2485 return resolvedUserId == mCurrentUserId; 2486 } 2487 2488 @Override 2489 public List<AccessibilityWindowInfo> getWindows() { 2490 ensureWindowsAvailableTimed(); 2491 synchronized (mLock) { 2492 if (!isCalledForCurrentUserLocked()) { 2493 return null; 2494 } 2495 final boolean permissionGranted = 2496 mSecurityPolicy.canRetrieveWindowsLocked(this); 2497 if (!permissionGranted) { 2498 return null; 2499 } 2500 if (mSecurityPolicy.mWindows == null) { 2501 return null; 2502 } 2503 List<AccessibilityWindowInfo> windows = new ArrayList<>(); 2504 final int windowCount = mSecurityPolicy.mWindows.size(); 2505 for (int i = 0; i < windowCount; i++) { 2506 AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i); 2507 AccessibilityWindowInfo windowClone = 2508 AccessibilityWindowInfo.obtain(window); 2509 windowClone.setConnectionId(mId); 2510 windows.add(windowClone); 2511 } 2512 return windows; 2513 } 2514 } 2515 2516 @Override 2517 public AccessibilityWindowInfo getWindow(int windowId) { 2518 ensureWindowsAvailableTimed(); 2519 synchronized (mLock) { 2520 if (!isCalledForCurrentUserLocked()) { 2521 return null; 2522 } 2523 final boolean permissionGranted = 2524 mSecurityPolicy.canRetrieveWindowsLocked(this); 2525 if (!permissionGranted) { 2526 return null; 2527 } 2528 AccessibilityWindowInfo window = mSecurityPolicy.findWindowById(windowId); 2529 if (window != null) { 2530 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); 2531 windowClone.setConnectionId(mId); 2532 return windowClone; 2533 } 2534 return null; 2535 } 2536 } 2537 2538 @Override 2539 public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId, 2540 long accessibilityNodeId, String viewIdResName, int interactionId, 2541 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2542 throws RemoteException { 2543 final int resolvedWindowId; 2544 IAccessibilityInteractionConnection connection = null; 2545 Region partialInteractiveRegion = Region.obtain(); 2546 synchronized (mLock) { 2547 if (!isCalledForCurrentUserLocked()) { 2548 return false; 2549 } 2550 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2551 final boolean permissionGranted = 2552 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2553 if (!permissionGranted) { 2554 return false; 2555 } else { 2556 connection = getConnectionLocked(resolvedWindowId); 2557 if (connection == null) { 2558 return false; 2559 } 2560 } 2561 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2562 resolvedWindowId, partialInteractiveRegion)) { 2563 partialInteractiveRegion.recycle(); 2564 partialInteractiveRegion = null; 2565 } 2566 } 2567 final int interrogatingPid = Binder.getCallingPid(); 2568 final long identityToken = Binder.clearCallingIdentity(); 2569 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2570 try { 2571 connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName, 2572 partialInteractiveRegion, interactionId, callback, mFetchFlags, 2573 interrogatingPid, interrogatingTid, spec); 2574 return true; 2575 } catch (RemoteException re) { 2576 if (DEBUG) { 2577 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId()."); 2578 } 2579 } finally { 2580 Binder.restoreCallingIdentity(identityToken); 2581 // Recycle if passed to another process. 2582 if (partialInteractiveRegion != null && Binder.isProxy(connection)) { 2583 partialInteractiveRegion.recycle(); 2584 } 2585 } 2586 return false; 2587 } 2588 2589 @Override 2590 public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId, 2591 long accessibilityNodeId, String text, int interactionId, 2592 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2593 throws RemoteException { 2594 final int resolvedWindowId; 2595 IAccessibilityInteractionConnection connection = null; 2596 Region partialInteractiveRegion = Region.obtain(); 2597 synchronized (mLock) { 2598 if (!isCalledForCurrentUserLocked()) { 2599 return false; 2600 } 2601 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2602 final boolean permissionGranted = 2603 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2604 if (!permissionGranted) { 2605 return false; 2606 } else { 2607 connection = getConnectionLocked(resolvedWindowId); 2608 if (connection == null) { 2609 return false; 2610 } 2611 } 2612 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2613 resolvedWindowId, partialInteractiveRegion)) { 2614 partialInteractiveRegion.recycle(); 2615 partialInteractiveRegion = null; 2616 } 2617 } 2618 final int interrogatingPid = Binder.getCallingPid(); 2619 final long identityToken = Binder.clearCallingIdentity(); 2620 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2621 try { 2622 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text, 2623 partialInteractiveRegion, interactionId, callback, mFetchFlags, 2624 interrogatingPid, interrogatingTid, spec); 2625 return true; 2626 } catch (RemoteException re) { 2627 if (DEBUG) { 2628 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()"); 2629 } 2630 } finally { 2631 Binder.restoreCallingIdentity(identityToken); 2632 // Recycle if passed to another process. 2633 if (partialInteractiveRegion != null && Binder.isProxy(connection)) { 2634 partialInteractiveRegion.recycle(); 2635 } 2636 } 2637 return false; 2638 } 2639 2640 @Override 2641 public boolean findAccessibilityNodeInfoByAccessibilityId( 2642 int accessibilityWindowId, long accessibilityNodeId, int interactionId, 2643 IAccessibilityInteractionConnectionCallback callback, int flags, 2644 long interrogatingTid) throws RemoteException { 2645 final int resolvedWindowId; 2646 IAccessibilityInteractionConnection connection = null; 2647 Region partialInteractiveRegion = Region.obtain(); 2648 synchronized (mLock) { 2649 if (!isCalledForCurrentUserLocked()) { 2650 return false; 2651 } 2652 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2653 final boolean permissionGranted = 2654 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2655 if (!permissionGranted) { 2656 return false; 2657 } else { 2658 connection = getConnectionLocked(resolvedWindowId); 2659 if (connection == null) { 2660 return false; 2661 } 2662 } 2663 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2664 resolvedWindowId, partialInteractiveRegion)) { 2665 partialInteractiveRegion.recycle(); 2666 partialInteractiveRegion = null; 2667 } 2668 } 2669 final int interrogatingPid = Binder.getCallingPid(); 2670 final long identityToken = Binder.clearCallingIdentity(); 2671 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2672 try { 2673 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId, 2674 partialInteractiveRegion, interactionId, callback, mFetchFlags | flags, 2675 interrogatingPid, interrogatingTid, spec); 2676 return true; 2677 } catch (RemoteException re) { 2678 if (DEBUG) { 2679 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); 2680 } 2681 } finally { 2682 Binder.restoreCallingIdentity(identityToken); 2683 // Recycle if passed to another process. 2684 if (partialInteractiveRegion != null && Binder.isProxy(connection)) { 2685 partialInteractiveRegion.recycle(); 2686 } 2687 } 2688 return false; 2689 } 2690 2691 @Override 2692 public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId, 2693 int focusType, int interactionId, 2694 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2695 throws RemoteException { 2696 final int resolvedWindowId; 2697 IAccessibilityInteractionConnection connection = null; 2698 Region partialInteractiveRegion = Region.obtain(); 2699 synchronized (mLock) { 2700 if (!isCalledForCurrentUserLocked()) { 2701 return false; 2702 } 2703 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked( 2704 accessibilityWindowId, focusType); 2705 final boolean permissionGranted = 2706 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2707 if (!permissionGranted) { 2708 return false; 2709 } else { 2710 connection = getConnectionLocked(resolvedWindowId); 2711 if (connection == null) { 2712 return false; 2713 } 2714 } 2715 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2716 resolvedWindowId, partialInteractiveRegion)) { 2717 partialInteractiveRegion.recycle(); 2718 partialInteractiveRegion = null; 2719 } 2720 } 2721 final int interrogatingPid = Binder.getCallingPid(); 2722 final long identityToken = Binder.clearCallingIdentity(); 2723 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2724 try { 2725 connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion, 2726 interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid, 2727 spec); 2728 return true; 2729 } catch (RemoteException re) { 2730 if (DEBUG) { 2731 Slog.e(LOG_TAG, "Error calling findFocus()"); 2732 } 2733 } finally { 2734 Binder.restoreCallingIdentity(identityToken); 2735 // Recycle if passed to another process. 2736 if (partialInteractiveRegion != null && Binder.isProxy(connection)) { 2737 partialInteractiveRegion.recycle(); 2738 } 2739 } 2740 return false; 2741 } 2742 2743 @Override 2744 public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId, 2745 int direction, int interactionId, 2746 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2747 throws RemoteException { 2748 final int resolvedWindowId; 2749 IAccessibilityInteractionConnection connection = null; 2750 Region partialInteractiveRegion = Region.obtain(); 2751 synchronized (mLock) { 2752 if (!isCalledForCurrentUserLocked()) { 2753 return false; 2754 } 2755 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2756 final boolean permissionGranted = 2757 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 2758 if (!permissionGranted) { 2759 return false; 2760 } else { 2761 connection = getConnectionLocked(resolvedWindowId); 2762 if (connection == null) { 2763 return false; 2764 } 2765 } 2766 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 2767 resolvedWindowId, partialInteractiveRegion)) { 2768 partialInteractiveRegion.recycle(); 2769 partialInteractiveRegion = null; 2770 } 2771 } 2772 final int interrogatingPid = Binder.getCallingPid(); 2773 final long identityToken = Binder.clearCallingIdentity(); 2774 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(resolvedWindowId); 2775 try { 2776 connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion, 2777 interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid, 2778 spec); 2779 return true; 2780 } catch (RemoteException re) { 2781 if (DEBUG) { 2782 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()"); 2783 } 2784 } finally { 2785 Binder.restoreCallingIdentity(identityToken); 2786 // Recycle if passed to another process. 2787 if (partialInteractiveRegion != null && Binder.isProxy(connection)) { 2788 partialInteractiveRegion.recycle(); 2789 } 2790 } 2791 return false; 2792 } 2793 2794 @Override 2795 public void sendGesture(int sequence, ParceledListSlice gestureSteps) { 2796 synchronized (mLock) { 2797 if (mSecurityPolicy.canPerformGestures(this)) { 2798 final long endMillis = 2799 SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS; 2800 while ((mMotionEventInjector == null) 2801 && (SystemClock.uptimeMillis() < endMillis)) { 2802 try { 2803 mLock.wait(endMillis - SystemClock.uptimeMillis()); 2804 } catch (InterruptedException ie) { 2805 /* ignore */ 2806 } 2807 } 2808 if (mMotionEventInjector != null) { 2809 List<GestureDescription.GestureStep> steps = gestureSteps.getList(); 2810 List<MotionEvent> events = GestureDescription.MotionEventGenerator 2811 .getMotionEventsFromGestureSteps(steps); 2812 // Confirm that the motion events end with an UP event. 2813 if (events.get(events.size() - 1).getAction() == MotionEvent.ACTION_UP) { 2814 mMotionEventInjector.injectEvents(events, mServiceInterface, sequence); 2815 return; 2816 } else { 2817 Slog.e(LOG_TAG, "Gesture is not well-formed"); 2818 } 2819 } else { 2820 Slog.e(LOG_TAG, "MotionEventInjector installation timed out"); 2821 } 2822 } 2823 } 2824 try { 2825 mServiceInterface.onPerformGestureResult(sequence, false); 2826 } catch (RemoteException re) { 2827 Slog.e(LOG_TAG, "Error sending motion event injection failure to " 2828 + mServiceInterface, re); 2829 } 2830 } 2831 2832 @Override 2833 public boolean performAccessibilityAction(int accessibilityWindowId, 2834 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 2835 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 2836 throws RemoteException { 2837 final int resolvedWindowId; 2838 IAccessibilityInteractionConnection connection = null; 2839 synchronized (mLock) { 2840 if (!isCalledForCurrentUserLocked()) { 2841 return false; 2842 } 2843 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 2844 final boolean permissionGranted = mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 2845 this, resolvedWindowId); 2846 if (!permissionGranted) { 2847 return false; 2848 } else { 2849 connection = getConnectionLocked(resolvedWindowId); 2850 if (connection == null) { 2851 return false; 2852 } 2853 } 2854 } 2855 final int interrogatingPid = Binder.getCallingPid(); 2856 final long identityToken = Binder.clearCallingIdentity(); 2857 try { 2858 // Regardless of whether or not the action succeeds, it was generated by an 2859 // accessibility service that is driven by user actions, so note user activity. 2860 mPowerManager.userActivity(SystemClock.uptimeMillis(), 2861 PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0); 2862 2863 connection.performAccessibilityAction(accessibilityNodeId, action, arguments, 2864 interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid); 2865 } catch (RemoteException re) { 2866 if (DEBUG) { 2867 Slog.e(LOG_TAG, "Error calling performAccessibilityAction()"); 2868 } 2869 } finally { 2870 Binder.restoreCallingIdentity(identityToken); 2871 } 2872 return true; 2873 } 2874 2875 @Override 2876 public boolean performGlobalAction(int action) { 2877 synchronized (mLock) { 2878 if (!isCalledForCurrentUserLocked()) { 2879 return false; 2880 } 2881 } 2882 final long identity = Binder.clearCallingIdentity(); 2883 try { 2884 mPowerManager.userActivity(SystemClock.uptimeMillis(), 2885 PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0); 2886 switch (action) { 2887 case AccessibilityService.GLOBAL_ACTION_BACK: { 2888 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); 2889 } return true; 2890 case AccessibilityService.GLOBAL_ACTION_HOME: { 2891 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); 2892 } return true; 2893 case AccessibilityService.GLOBAL_ACTION_RECENTS: { 2894 openRecents(); 2895 } return true; 2896 case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { 2897 expandNotifications(); 2898 } return true; 2899 case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: { 2900 expandQuickSettings(); 2901 } return true; 2902 case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: { 2903 showGlobalActions(); 2904 } return true; 2905 case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: { 2906 toggleSplitScreen(); 2907 } return true; 2908 } 2909 return false; 2910 } finally { 2911 Binder.restoreCallingIdentity(identity); 2912 } 2913 } 2914 2915 @Override 2916 public float getMagnificationScale() { 2917 synchronized (mLock) { 2918 if (!isCalledForCurrentUserLocked()) { 2919 return 1.0f; 2920 } 2921 } 2922 final long identity = Binder.clearCallingIdentity(); 2923 try { 2924 return getMagnificationController().getScale(); 2925 } finally { 2926 Binder.restoreCallingIdentity(identity); 2927 } 2928 } 2929 2930 @Override 2931 public Region getMagnificationRegion() { 2932 synchronized (mLock) { 2933 final Region region = Region.obtain(); 2934 if (!isCalledForCurrentUserLocked()) { 2935 return region; 2936 } 2937 MagnificationController magnificationController = getMagnificationController(); 2938 boolean forceRegistration = mSecurityPolicy.canControlMagnification(this); 2939 boolean initiallyRegistered = magnificationController.isRegisteredLocked(); 2940 if (!initiallyRegistered && forceRegistration) { 2941 magnificationController.register(); 2942 } 2943 final long identity = Binder.clearCallingIdentity(); 2944 try { 2945 magnificationController.getMagnificationRegion(region); 2946 return region; 2947 } finally { 2948 Binder.restoreCallingIdentity(identity); 2949 if (!initiallyRegistered && forceRegistration) { 2950 magnificationController.unregister(); 2951 } 2952 } 2953 } 2954 } 2955 2956 @Override 2957 public float getMagnificationCenterX() { 2958 synchronized (mLock) { 2959 if (!isCalledForCurrentUserLocked()) { 2960 return 0.0f; 2961 } 2962 } 2963 final long identity = Binder.clearCallingIdentity(); 2964 try { 2965 return getMagnificationController().getCenterX(); 2966 } finally { 2967 Binder.restoreCallingIdentity(identity); 2968 } 2969 } 2970 2971 @Override 2972 public float getMagnificationCenterY() { 2973 synchronized (mLock) { 2974 if (!isCalledForCurrentUserLocked()) { 2975 return 0.0f; 2976 } 2977 } 2978 final long identity = Binder.clearCallingIdentity(); 2979 try { 2980 return getMagnificationController().getCenterY(); 2981 } finally { 2982 Binder.restoreCallingIdentity(identity); 2983 } 2984 } 2985 2986 @Override 2987 public boolean resetMagnification(boolean animate) { 2988 synchronized (mLock) { 2989 if (!isCalledForCurrentUserLocked()) { 2990 return false; 2991 } 2992 final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this); 2993 if (!permissionGranted) { 2994 return false; 2995 } 2996 } 2997 final long identity = Binder.clearCallingIdentity(); 2998 try { 2999 return getMagnificationController().reset(animate); 3000 } finally { 3001 Binder.restoreCallingIdentity(identity); 3002 } 3003 } 3004 3005 @Override 3006 public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY, 3007 boolean animate) { 3008 synchronized (mLock) { 3009 if (!isCalledForCurrentUserLocked()) { 3010 return false; 3011 } 3012 final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this); 3013 if (!permissionGranted) { 3014 return false; 3015 } 3016 final long identity = Binder.clearCallingIdentity(); 3017 try { 3018 MagnificationController magnificationController = getMagnificationController(); 3019 if (!magnificationController.isRegisteredLocked()) { 3020 magnificationController.register(); 3021 } 3022 return magnificationController 3023 .setScaleAndCenter(scale, centerX, centerY, animate, mId); 3024 } finally { 3025 Binder.restoreCallingIdentity(identity); 3026 } 3027 } 3028 } 3029 3030 @Override 3031 public void setMagnificationCallbackEnabled(boolean enabled) { 3032 mInvocationHandler.setMagnificationCallbackEnabled(enabled); 3033 } 3034 3035 @Override 3036 public boolean setSoftKeyboardShowMode(int showMode) { 3037 final UserState userState; 3038 synchronized (mLock) { 3039 if (!isCalledForCurrentUserLocked()) { 3040 return false; 3041 } 3042 3043 userState = getCurrentUserStateLocked(); 3044 } 3045 3046 final long identity = Binder.clearCallingIdentity(); 3047 try { 3048 // Keep track of the last service to request a non-default show mode. The show mode 3049 // should be restored to default should this service be disabled. 3050 if (showMode == Settings.Secure.SHOW_MODE_AUTO) { 3051 userState.mServiceChangingSoftKeyboardMode = null; 3052 } else { 3053 userState.mServiceChangingSoftKeyboardMode = mComponentName; 3054 } 3055 3056 Settings.Secure.putIntForUser(mContext.getContentResolver(), 3057 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode, 3058 userState.mUserId); 3059 } finally { 3060 Binder.restoreCallingIdentity(identity); 3061 } 3062 return true; 3063 } 3064 3065 @Override 3066 public void setSoftKeyboardCallbackEnabled(boolean enabled) { 3067 mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled); 3068 } 3069 3070 @Override 3071 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 3072 mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP); 3073 synchronized (mLock) { 3074 pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo() 3075 .loadLabel(mContext.getPackageManager())); 3076 pw.append(", feedbackType" 3077 + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType)); 3078 pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities()); 3079 pw.append(", eventTypes=" 3080 + AccessibilityEvent.eventTypeToString(mEventTypes)); 3081 pw.append(", notificationTimeout=" + mNotificationTimeout); 3082 pw.append("]"); 3083 } 3084 } 3085 3086 @Override 3087 public void onServiceDisconnected(ComponentName componentName) { 3088 binderDied(); 3089 } 3090 3091 public void onAdded() throws RemoteException { 3092 final long identity = Binder.clearCallingIdentity(); 3093 try { 3094 mWindowManagerService.addWindowToken(mOverlayWindowToken, 3095 WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY); 3096 } finally { 3097 Binder.restoreCallingIdentity(identity); 3098 } 3099 } 3100 3101 public void onRemoved() { 3102 final long identity = Binder.clearCallingIdentity(); 3103 try { 3104 mWindowManagerService.removeWindowToken(mOverlayWindowToken, true); 3105 } finally { 3106 Binder.restoreCallingIdentity(identity); 3107 } 3108 } 3109 3110 public void resetLocked() { 3111 try { 3112 // Clear the proxy in the other process so this 3113 // IAccessibilityServiceConnection can be garbage collected. 3114 if (mServiceInterface != null) { 3115 mServiceInterface.init(null, mId, null); 3116 } 3117 } catch (RemoteException re) { 3118 /* ignore */ 3119 } 3120 if (mService != null) { 3121 mService.unlinkToDeath(this, 0); 3122 mService = null; 3123 } 3124 mServiceInterface = null; 3125 } 3126 3127 public boolean isConnectedLocked() { 3128 return (mService != null); 3129 } 3130 3131 public void binderDied() { 3132 synchronized (mLock) { 3133 // It is possible that this service's package was force stopped during 3134 // whose handling the death recipient is unlinked and still get a call 3135 // on binderDied since the call was made before we unlink but was 3136 // waiting on the lock we held during the force stop handling. 3137 if (!isConnectedLocked()) { 3138 return; 3139 } 3140 mWasConnectedAndDied = true; 3141 getKeyEventDispatcher().flush(this); 3142 UserState userState = getUserStateLocked(mUserId); 3143 resetLocked(); 3144 if (mIsAutomation) { 3145 // This is typically done when unbinding, but UiAutomation isn't bound. 3146 removeServiceLocked(this, userState); 3147 // We no longer have an automation service, so restore 3148 // the state based on values in the settings database. 3149 userState.mInstalledServices.remove(mAccessibilityServiceInfo); 3150 userState.mEnabledServices.remove(mComponentName); 3151 userState.destroyUiAutomationService(); 3152 readConfigurationForUserStateLocked(userState); 3153 } 3154 if (mId == getMagnificationController().getIdOfLastServiceToMagnify()) { 3155 getMagnificationController().resetIfNeeded(true); 3156 } 3157 onUserStateChangedLocked(userState); 3158 } 3159 } 3160 3161 /** 3162 * Performs a notification for an {@link AccessibilityEvent}. 3163 * 3164 * @param event The event. 3165 */ 3166 public void notifyAccessibilityEvent(AccessibilityEvent event) { 3167 synchronized (mLock) { 3168 final int eventType = event.getEventType(); 3169 // Make a copy since during dispatch it is possible the event to 3170 // be modified to remove its source if the receiving service does 3171 // not have permission to access the window content. 3172 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event); 3173 Message message; 3174 if ((mNotificationTimeout > 0) 3175 && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) { 3176 // Allow at most one pending event 3177 final AccessibilityEvent oldEvent = mPendingEvents.get(eventType); 3178 mPendingEvents.put(eventType, newEvent); 3179 if (oldEvent != null) { 3180 mEventDispatchHandler.removeMessages(eventType); 3181 oldEvent.recycle(); 3182 } 3183 message = mEventDispatchHandler.obtainMessage(eventType); 3184 } else { 3185 // Send all messages, bypassing mPendingEvents 3186 message = mEventDispatchHandler.obtainMessage(eventType, newEvent); 3187 } 3188 3189 mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout); 3190 } 3191 } 3192 3193 /** 3194 * Notifies an accessibility service client for a scheduled event given the event type. 3195 * 3196 * @param eventType The type of the event to dispatch. 3197 */ 3198 private void notifyAccessibilityEventInternal(int eventType, AccessibilityEvent event) { 3199 IAccessibilityServiceClient listener; 3200 3201 synchronized (mLock) { 3202 listener = mServiceInterface; 3203 3204 // If the service died/was disabled while the message for dispatching 3205 // the accessibility event was propagating the listener may be null. 3206 if (listener == null) { 3207 return; 3208 } 3209 3210 // There are two ways we notify for events, throttled and non-throttled. If we 3211 // are not throttling, then messages come with events, which we handle with 3212 // minimal fuss. 3213 if (event == null) { 3214 // We are throttling events, so we'll send the event for this type in 3215 // mPendingEvents as long as it it's null. It can only null due to a race 3216 // condition: 3217 // 3218 // 1) A binder thread calls notifyAccessibilityServiceDelayedLocked 3219 // which posts a message for dispatching an event and stores the event 3220 // in mPendingEvents. 3221 // 2) The message is pulled from the queue by the handler on the service 3222 // thread and this method is just about to acquire the lock. 3223 // 3) Another binder thread acquires the lock in notifyAccessibilityEvent 3224 // 4) notifyAccessibilityEvent recycles the event that this method was about 3225 // to process, replaces it with a new one, and posts a second message 3226 // 5) This method grabs the new event, processes it, and removes it from 3227 // mPendingEvents 3228 // 6) The second message dispatched in (4) arrives, but the event has been 3229 // remvoved in (5). 3230 event = mPendingEvents.get(eventType); 3231 if (event == null) { 3232 return; 3233 } 3234 mPendingEvents.remove(eventType); 3235 } 3236 if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) { 3237 event.setConnectionId(mId); 3238 } else { 3239 event.setSource(null); 3240 } 3241 event.setSealed(true); 3242 } 3243 3244 try { 3245 listener.onAccessibilityEvent(event); 3246 if (DEBUG) { 3247 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); 3248 } 3249 } catch (RemoteException re) { 3250 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re); 3251 } finally { 3252 event.recycle(); 3253 } 3254 } 3255 3256 public void notifyGesture(int gestureId) { 3257 mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE, 3258 gestureId, 0).sendToTarget(); 3259 } 3260 3261 public void notifyClearAccessibilityNodeInfoCache() { 3262 mInvocationHandler.sendEmptyMessage( 3263 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE); 3264 } 3265 3266 public void notifyMagnificationChangedLocked(@NonNull Region region, 3267 float scale, float centerX, float centerY) { 3268 mInvocationHandler 3269 .notifyMagnificationChangedLocked(region, scale, centerX, centerY); 3270 } 3271 3272 public void notifySoftKeyboardShowModeChangedLocked(int showState) { 3273 mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState); 3274 } 3275 3276 /** 3277 * Called by the invocation handler to notify the service that the 3278 * state of magnification has changed. 3279 */ 3280 private void notifyMagnificationChangedInternal(@NonNull Region region, 3281 float scale, float centerX, float centerY) { 3282 final IAccessibilityServiceClient listener; 3283 synchronized (mLock) { 3284 listener = mServiceInterface; 3285 } 3286 if (listener != null) { 3287 try { 3288 listener.onMagnificationChanged(region, scale, centerX, centerY); 3289 } catch (RemoteException re) { 3290 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re); 3291 } 3292 } 3293 } 3294 3295 /** 3296 * Called by the invocation handler to notify the service that the state of the soft 3297 * keyboard show mode has changed. 3298 */ 3299 private void notifySoftKeyboardShowModeChangedInternal(int showState) { 3300 final IAccessibilityServiceClient listener; 3301 synchronized (mLock) { 3302 listener = mServiceInterface; 3303 } 3304 if (listener != null) { 3305 try { 3306 listener.onSoftKeyboardShowModeChanged(showState); 3307 } catch (RemoteException re) { 3308 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService, 3309 re); 3310 } 3311 } 3312 } 3313 3314 private void notifyGestureInternal(int gestureId) { 3315 final IAccessibilityServiceClient listener; 3316 synchronized (mLock) { 3317 listener = mServiceInterface; 3318 } 3319 if (listener != null) { 3320 try { 3321 listener.onGesture(gestureId); 3322 } catch (RemoteException re) { 3323 Slog.e(LOG_TAG, "Error during sending gesture " + gestureId 3324 + " to " + mService, re); 3325 } 3326 } 3327 } 3328 3329 private void notifyClearAccessibilityCacheInternal() { 3330 final IAccessibilityServiceClient listener; 3331 synchronized (mLock) { 3332 listener = mServiceInterface; 3333 } 3334 if (listener != null) { 3335 try { 3336 listener.clearAccessibilityCache(); 3337 } catch (RemoteException re) { 3338 Slog.e(LOG_TAG, "Error during requesting accessibility info cache" 3339 + " to be cleared.", re); 3340 } 3341 } 3342 } 3343 3344 private void sendDownAndUpKeyEvents(int keyCode) { 3345 final long token = Binder.clearCallingIdentity(); 3346 3347 // Inject down. 3348 final long downTime = SystemClock.uptimeMillis(); 3349 KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, 3350 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 3351 InputDevice.SOURCE_KEYBOARD, null); 3352 InputManager.getInstance().injectInputEvent(down, 3353 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 3354 down.recycle(); 3355 3356 // Inject up. 3357 final long upTime = SystemClock.uptimeMillis(); 3358 KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0, 3359 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 3360 InputDevice.SOURCE_KEYBOARD, null); 3361 InputManager.getInstance().injectInputEvent(up, 3362 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 3363 up.recycle(); 3364 3365 Binder.restoreCallingIdentity(token); 3366 } 3367 3368 private void expandNotifications() { 3369 final long token = Binder.clearCallingIdentity(); 3370 3371 StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( 3372 android.app.Service.STATUS_BAR_SERVICE); 3373 statusBarManager.expandNotificationsPanel(); 3374 3375 Binder.restoreCallingIdentity(token); 3376 } 3377 3378 private void expandQuickSettings() { 3379 final long token = Binder.clearCallingIdentity(); 3380 3381 StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( 3382 android.app.Service.STATUS_BAR_SERVICE); 3383 statusBarManager.expandSettingsPanel(); 3384 3385 Binder.restoreCallingIdentity(token); 3386 } 3387 3388 private void openRecents() { 3389 final long token = Binder.clearCallingIdentity(); 3390 3391 StatusBarManagerInternal statusBarService = LocalServices.getService( 3392 StatusBarManagerInternal.class); 3393 statusBarService.toggleRecentApps(); 3394 3395 Binder.restoreCallingIdentity(token); 3396 } 3397 3398 private void showGlobalActions() { 3399 mWindowManagerService.showGlobalActions(); 3400 } 3401 3402 private void toggleSplitScreen() { 3403 LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen(); 3404 } 3405 3406 private IAccessibilityInteractionConnection getConnectionLocked(int windowId) { 3407 if (DEBUG) { 3408 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); 3409 } 3410 AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId); 3411 if (wrapper == null) { 3412 wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId); 3413 } 3414 if (wrapper != null && wrapper.mConnection != null) { 3415 return wrapper.mConnection; 3416 } 3417 if (DEBUG) { 3418 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId); 3419 } 3420 return null; 3421 } 3422 3423 private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) { 3424 if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) { 3425 return mSecurityPolicy.getActiveWindowId(); 3426 } 3427 return accessibilityWindowId; 3428 } 3429 3430 private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { 3431 if (windowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) { 3432 return mSecurityPolicy.mActiveWindowId; 3433 } 3434 if (windowId == AccessibilityNodeInfo.ANY_WINDOW_ID) { 3435 if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { 3436 return mSecurityPolicy.mFocusedWindowId; 3437 } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { 3438 return mSecurityPolicy.mAccessibilityFocusedWindowId; 3439 } 3440 } 3441 return windowId; 3442 } 3443 3444 private final class InvocationHandler extends Handler { 3445 public static final int MSG_ON_GESTURE = 1; 3446 public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2; 3447 3448 private static final int MSG_ON_MAGNIFICATION_CHANGED = 5; 3449 private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6; 3450 3451 private boolean mIsMagnificationCallbackEnabled = false; 3452 private boolean mIsSoftKeyboardCallbackEnabled = false; 3453 3454 public InvocationHandler(Looper looper) { 3455 super(looper, null, true); 3456 } 3457 3458 @Override 3459 public void handleMessage(Message message) { 3460 final int type = message.what; 3461 switch (type) { 3462 case MSG_ON_GESTURE: { 3463 final int gestureId = message.arg1; 3464 notifyGestureInternal(gestureId); 3465 } break; 3466 3467 case MSG_CLEAR_ACCESSIBILITY_CACHE: { 3468 notifyClearAccessibilityCacheInternal(); 3469 } break; 3470 3471 case MSG_ON_MAGNIFICATION_CHANGED: { 3472 final SomeArgs args = (SomeArgs) message.obj; 3473 final Region region = (Region) args.arg1; 3474 final float scale = (float) args.arg2; 3475 final float centerX = (float) args.arg3; 3476 final float centerY = (float) args.arg4; 3477 notifyMagnificationChangedInternal(region, scale, centerX, centerY); 3478 } break; 3479 3480 case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: { 3481 final int showState = (int) message.arg1; 3482 notifySoftKeyboardShowModeChangedInternal(showState); 3483 } break; 3484 3485 default: { 3486 throw new IllegalArgumentException("Unknown message: " + type); 3487 } 3488 } 3489 } 3490 3491 public void notifyMagnificationChangedLocked(@NonNull Region region, float scale, 3492 float centerX, float centerY) { 3493 if (!mIsMagnificationCallbackEnabled) { 3494 // Callback is disabled, don't bother packing args. 3495 return; 3496 } 3497 3498 final SomeArgs args = SomeArgs.obtain(); 3499 args.arg1 = region; 3500 args.arg2 = scale; 3501 args.arg3 = centerX; 3502 args.arg4 = centerY; 3503 3504 final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args); 3505 msg.sendToTarget(); 3506 } 3507 3508 public void setMagnificationCallbackEnabled(boolean enabled) { 3509 mIsMagnificationCallbackEnabled = enabled; 3510 } 3511 3512 public void notifySoftKeyboardShowModeChangedLocked(int showState) { 3513 if (!mIsSoftKeyboardCallbackEnabled) { 3514 return; 3515 } 3516 3517 final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0); 3518 msg.sendToTarget(); 3519 } 3520 3521 public void setSoftKeyboardCallbackEnabled(boolean enabled) { 3522 mIsSoftKeyboardCallbackEnabled = enabled; 3523 } 3524 } 3525 } 3526 3527 final class WindowsForAccessibilityCallback implements 3528 WindowManagerInternal.WindowsForAccessibilityCallback { 3529 3530 @Override 3531 public void onWindowsForAccessibilityChanged(List<WindowInfo> windows) { 3532 synchronized (mLock) { 3533 // Populate the windows to report. 3534 List<AccessibilityWindowInfo> reportedWindows = new ArrayList<>(); 3535 final int receivedWindowCount = windows.size(); 3536 for (int i = 0; i < receivedWindowCount; i++) { 3537 WindowInfo receivedWindow = windows.get(i); 3538 AccessibilityWindowInfo reportedWindow = populateReportedWindow( 3539 receivedWindow); 3540 if (reportedWindow != null) { 3541 reportedWindows.add(reportedWindow); 3542 } 3543 } 3544 3545 if (DEBUG) { 3546 Slog.i(LOG_TAG, "Windows changed: " + reportedWindows); 3547 } 3548 3549 // Let the policy update the focused and active windows. 3550 mSecurityPolicy.updateWindowsLocked(reportedWindows); 3551 3552 // Someone may be waiting for the windows - advertise it. 3553 mLock.notifyAll(); 3554 } 3555 } 3556 3557 private AccessibilityWindowInfo populateReportedWindow(WindowInfo window) { 3558 final int windowId = findWindowIdLocked(window.token); 3559 if (windowId < 0) { 3560 return null; 3561 } 3562 3563 AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); 3564 3565 reportedWindow.setId(windowId); 3566 reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); 3567 reportedWindow.setLayer(window.layer); 3568 reportedWindow.setFocused(window.focused); 3569 reportedWindow.setBoundsInScreen(window.boundsInScreen); 3570 reportedWindow.setTitle(window.title); 3571 reportedWindow.setAnchorId(window.accessibilityIdOfAnchor); 3572 3573 final int parentId = findWindowIdLocked(window.parentToken); 3574 if (parentId >= 0) { 3575 reportedWindow.setParentId(parentId); 3576 } 3577 3578 if (window.childTokens != null) { 3579 final int childCount = window.childTokens.size(); 3580 for (int i = 0; i < childCount; i++) { 3581 IBinder childToken = window.childTokens.get(i); 3582 final int childId = findWindowIdLocked(childToken); 3583 if (childId >= 0) { 3584 reportedWindow.addChild(childId); 3585 } 3586 } 3587 } 3588 3589 return reportedWindow; 3590 } 3591 3592 private int getTypeForWindowManagerWindowType(int windowType) { 3593 switch (windowType) { 3594 case WindowManager.LayoutParams.TYPE_APPLICATION: 3595 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: 3596 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: 3597 case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: 3598 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: 3599 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: 3600 case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: 3601 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: 3602 case WindowManager.LayoutParams.TYPE_PHONE: 3603 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: 3604 case WindowManager.LayoutParams.TYPE_TOAST: 3605 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: { 3606 return AccessibilityWindowInfo.TYPE_APPLICATION; 3607 } 3608 3609 case WindowManager.LayoutParams.TYPE_INPUT_METHOD: 3610 case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { 3611 return AccessibilityWindowInfo.TYPE_INPUT_METHOD; 3612 } 3613 3614 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: 3615 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: 3616 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: 3617 case WindowManager.LayoutParams.TYPE_SEARCH_BAR: 3618 case WindowManager.LayoutParams.TYPE_STATUS_BAR: 3619 case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: 3620 case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: 3621 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: 3622 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: 3623 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: 3624 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: 3625 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: 3626 case WindowManager.LayoutParams.TYPE_SCREENSHOT: { 3627 return AccessibilityWindowInfo.TYPE_SYSTEM; 3628 } 3629 3630 case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { 3631 return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; 3632 } 3633 3634 case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: { 3635 return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; 3636 } 3637 3638 default: { 3639 return -1; 3640 } 3641 } 3642 } 3643 } 3644 3645 private final class InteractionBridge { 3646 private final Display mDefaultDisplay; 3647 private final int mConnectionId; 3648 private final AccessibilityInteractionClient mClient; 3649 3650 public InteractionBridge() { 3651 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 3652 info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT); 3653 info.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS; 3654 info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 3655 Service service = new Service(UserHandle.USER_NULL, 3656 sFakeAccessibilityServiceComponentName, info); 3657 3658 mConnectionId = service.mId; 3659 3660 mClient = AccessibilityInteractionClient.getInstance(); 3661 mClient.addConnection(mConnectionId, service); 3662 3663 //TODO: (multi-display) We need to support multiple displays. 3664 DisplayManager displayManager = (DisplayManager) 3665 mContext.getSystemService(Context.DISPLAY_SERVICE); 3666 mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 3667 } 3668 3669 public void clearAccessibilityFocusNotLocked(int windowId) { 3670 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(windowId); 3671 if (focus != null) { 3672 focus.performAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 3673 } 3674 } 3675 3676 public boolean getAccessibilityFocusClickPointInScreenNotLocked(Point outPoint) { 3677 AccessibilityNodeInfo focus = getAccessibilityFocusNotLocked(); 3678 if (focus == null) { 3679 return false; 3680 } 3681 3682 synchronized (mLock) { 3683 Rect boundsInScreen = mTempRect; 3684 focus.getBoundsInScreen(boundsInScreen); 3685 3686 // Apply magnification if needed. 3687 MagnificationSpec spec = getCompatibleMagnificationSpecLocked(focus.getWindowId()); 3688 if (spec != null && !spec.isNop()) { 3689 boundsInScreen.offset((int) -spec.offsetX, (int) -spec.offsetY); 3690 boundsInScreen.scale(1 / spec.scale); 3691 } 3692 3693 // Clip to the window bounds. 3694 Rect windowBounds = mTempRect1; 3695 getWindowBounds(focus.getWindowId(), windowBounds); 3696 if (!boundsInScreen.intersect(windowBounds)) { 3697 return false; 3698 } 3699 3700 // Clip to the screen bounds. 3701 Point screenSize = mTempPoint; 3702 mDefaultDisplay.getRealSize(screenSize); 3703 if (!boundsInScreen.intersect(0, 0, screenSize.x, screenSize.y)) { 3704 return false; 3705 } 3706 3707 outPoint.set(boundsInScreen.centerX(), boundsInScreen.centerY()); 3708 } 3709 3710 return true; 3711 } 3712 3713 private AccessibilityNodeInfo getAccessibilityFocusNotLocked() { 3714 final int focusedWindowId; 3715 synchronized (mLock) { 3716 focusedWindowId = mSecurityPolicy.mAccessibilityFocusedWindowId; 3717 if (focusedWindowId == SecurityPolicy.INVALID_WINDOW_ID) { 3718 return null; 3719 } 3720 } 3721 return getAccessibilityFocusNotLocked(focusedWindowId); 3722 } 3723 3724 private AccessibilityNodeInfo getAccessibilityFocusNotLocked(int windowId) { 3725 return mClient.findFocus(mConnectionId, 3726 windowId, AccessibilityNodeInfo.ROOT_NODE_ID, 3727 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 3728 } 3729 } 3730 3731 final class SecurityPolicy { 3732 public static final int INVALID_WINDOW_ID = -1; 3733 3734 private static final int RETRIEVAL_ALLOWING_EVENT_TYPES = 3735 AccessibilityEvent.TYPE_VIEW_CLICKED 3736 | AccessibilityEvent.TYPE_VIEW_FOCUSED 3737 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 3738 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 3739 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 3740 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 3741 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 3742 | AccessibilityEvent.TYPE_VIEW_SELECTED 3743 | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 3744 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 3745 | AccessibilityEvent.TYPE_VIEW_SCROLLED 3746 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 3747 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED 3748 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 3749 3750 public List<AccessibilityWindowInfo> mWindows; 3751 3752 public int mActiveWindowId = INVALID_WINDOW_ID; 3753 public int mFocusedWindowId = INVALID_WINDOW_ID; 3754 public int mAccessibilityFocusedWindowId = INVALID_WINDOW_ID; 3755 public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 3756 3757 private boolean mTouchInteractionInProgress; 3758 3759 private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) { 3760 final int eventType = event.getEventType(); 3761 switch (eventType) { 3762 // All events that are for changes in a global window 3763 // state should *always* be dispatched. 3764 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: 3765 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: 3766 case AccessibilityEvent.TYPE_ANNOUNCEMENT: 3767 // All events generated by the user touching the 3768 // screen should *always* be dispatched. 3769 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: 3770 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: 3771 case AccessibilityEvent.TYPE_GESTURE_DETECTION_START: 3772 case AccessibilityEvent.TYPE_GESTURE_DETECTION_END: 3773 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START: 3774 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: 3775 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: 3776 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: 3777 // Also always dispatch the event that assist is reading context. 3778 case AccessibilityEvent.TYPE_ASSIST_READING_CONTEXT: 3779 // Also windows changing should always be anounced. 3780 case AccessibilityEvent.TYPE_WINDOWS_CHANGED: { 3781 return true; 3782 } 3783 // All events for changes in window content should be 3784 // dispatched *only* if this window is one of the windows 3785 // the accessibility layer reports which are windows 3786 // that a sighted user can touch. 3787 default: { 3788 return isRetrievalAllowingWindow(event.getWindowId()); 3789 } 3790 } 3791 } 3792 3793 public void clearWindowsLocked() { 3794 List<AccessibilityWindowInfo> windows = Collections.emptyList(); 3795 final int activeWindowId = mActiveWindowId; 3796 updateWindowsLocked(windows); 3797 mActiveWindowId = activeWindowId; 3798 mWindows = null; 3799 } 3800 3801 public void updateWindowsLocked(List<AccessibilityWindowInfo> windows) { 3802 if (mWindows == null) { 3803 mWindows = new ArrayList<>(); 3804 } 3805 3806 final int oldWindowCount = mWindows.size(); 3807 for (int i = oldWindowCount - 1; i >= 0; i--) { 3808 mWindows.remove(i).recycle(); 3809 } 3810 3811 mFocusedWindowId = INVALID_WINDOW_ID; 3812 if (!mTouchInteractionInProgress) { 3813 mActiveWindowId = INVALID_WINDOW_ID; 3814 } 3815 3816 // If the active window goes away while the user is touch exploring we 3817 // reset the active window id and wait for the next hover event from 3818 // under the user's finger to determine which one is the new one. It 3819 // is possible that the finger is not moving and the input system 3820 // filters out such events. 3821 boolean activeWindowGone = true; 3822 3823 final int windowCount = windows.size(); 3824 if (windowCount > 0) { 3825 for (int i = 0; i < windowCount; i++) { 3826 AccessibilityWindowInfo window = windows.get(i); 3827 final int windowId = window.getId(); 3828 if (window.isFocused()) { 3829 mFocusedWindowId = windowId; 3830 if (!mTouchInteractionInProgress) { 3831 mActiveWindowId = windowId; 3832 window.setActive(true); 3833 } else if (windowId == mActiveWindowId) { 3834 activeWindowGone = false; 3835 } 3836 } 3837 mWindows.add(window); 3838 } 3839 3840 if (mTouchInteractionInProgress && activeWindowGone) { 3841 mActiveWindowId = mFocusedWindowId; 3842 } 3843 3844 // Focused window may change the active one, so set the 3845 // active window once we decided which it is. 3846 for (int i = 0; i < windowCount; i++) { 3847 AccessibilityWindowInfo window = mWindows.get(i); 3848 if (window.getId() == mActiveWindowId) { 3849 window.setActive(true); 3850 } 3851 if (window.getId() == mAccessibilityFocusedWindowId) { 3852 window.setAccessibilityFocused(true); 3853 } 3854 } 3855 } 3856 3857 notifyWindowsChanged(); 3858 } 3859 3860 public boolean computePartialInteractiveRegionForWindowLocked(int windowId, 3861 Region outRegion) { 3862 if (mWindows == null) { 3863 return false; 3864 } 3865 3866 // Windows are ordered in z order so start from the bottom and find 3867 // the window of interest. After that all windows that cover it should 3868 // be subtracted from the resulting region. Note that for accessibility 3869 // we are returning only interactive windows. 3870 Region windowInteractiveRegion = null; 3871 boolean windowInteractiveRegionChanged = false; 3872 3873 final int windowCount = mWindows.size(); 3874 for (int i = windowCount - 1; i >= 0; i--) { 3875 AccessibilityWindowInfo currentWindow = mWindows.get(i); 3876 if (windowInteractiveRegion == null) { 3877 if (currentWindow.getId() == windowId) { 3878 Rect currentWindowBounds = mTempRect; 3879 currentWindow.getBoundsInScreen(currentWindowBounds); 3880 outRegion.set(currentWindowBounds); 3881 windowInteractiveRegion = outRegion; 3882 continue; 3883 } 3884 } else if (currentWindow.getType() 3885 != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { 3886 Rect currentWindowBounds = mTempRect; 3887 currentWindow.getBoundsInScreen(currentWindowBounds); 3888 if (windowInteractiveRegion.op(currentWindowBounds, Region.Op.DIFFERENCE)) { 3889 windowInteractiveRegionChanged = true; 3890 } 3891 } 3892 } 3893 3894 return windowInteractiveRegionChanged; 3895 } 3896 3897 public void updateEventSourceLocked(AccessibilityEvent event) { 3898 if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) { 3899 event.setSource(null); 3900 } 3901 } 3902 3903 public void updateActiveAndAccessibilityFocusedWindowLocked(int windowId, long nodeId, 3904 int eventType, int eventAction) { 3905 // The active window is either the window that has input focus or 3906 // the window that the user is currently touching. If the user is 3907 // touching a window that does not have input focus as soon as the 3908 // the user stops touching that window the focused window becomes 3909 // the active one. Here we detect the touched window and make it 3910 // active. In updateWindowsLocked() we update the focused window 3911 // and if the user is not touching the screen, we make the focused 3912 // window the active one. 3913 switch (eventType) { 3914 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: { 3915 // If no service has the capability to introspect screen, 3916 // we do not register callback in the window manager for 3917 // window changes, so we have to ask the window manager 3918 // what the focused window is to update the active one. 3919 // The active window also determined events from which 3920 // windows are delivered. 3921 synchronized (mLock) { 3922 if (mWindowsForAccessibilityCallback == null) { 3923 mFocusedWindowId = getFocusedWindowId(); 3924 if (windowId == mFocusedWindowId) { 3925 mActiveWindowId = windowId; 3926 } 3927 } 3928 } 3929 } break; 3930 3931 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: { 3932 // Do not allow delayed hover events to confuse us 3933 // which the active window is. 3934 synchronized (mLock) { 3935 if (mTouchInteractionInProgress && mActiveWindowId != windowId) { 3936 setActiveWindowLocked(windowId); 3937 } 3938 } 3939 } break; 3940 3941 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 3942 synchronized (mLock) { 3943 if (mAccessibilityFocusedWindowId != windowId) { 3944 mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS, 3945 mAccessibilityFocusedWindowId, 0).sendToTarget(); 3946 mSecurityPolicy.setAccessibilityFocusedWindowLocked(windowId); 3947 mAccessibilityFocusNodeId = nodeId; 3948 } 3949 } 3950 } break; 3951 3952 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 3953 synchronized (mLock) { 3954 if (mAccessibilityFocusNodeId == nodeId) { 3955 mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 3956 } 3957 // Clear the window with focus if it no longer has focus and we aren't 3958 // just moving focus from one view to the other in the same window 3959 if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) 3960 && (mAccessibilityFocusedWindowId == windowId) 3961 && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) 3962 ) { 3963 mAccessibilityFocusedWindowId = INVALID_WINDOW_ID; 3964 } 3965 } 3966 } break; 3967 } 3968 } 3969 3970 public void onTouchInteractionStart() { 3971 synchronized (mLock) { 3972 mTouchInteractionInProgress = true; 3973 } 3974 } 3975 3976 public void onTouchInteractionEnd() { 3977 synchronized (mLock) { 3978 mTouchInteractionInProgress = false; 3979 // We want to set the active window to be current immediately 3980 // after the user has stopped touching the screen since if the 3981 // user types with the IME he should get a feedback for the 3982 // letter typed in the text view which is in the input focused 3983 // window. Note that we always deliver hover accessibility events 3984 // (they are a result of user touching the screen) so change of 3985 // the active window before all hover accessibility events from 3986 // the touched window are delivered is fine. 3987 final int oldActiveWindow = mSecurityPolicy.mActiveWindowId; 3988 setActiveWindowLocked(mFocusedWindowId); 3989 3990 // If there is no service that can operate with active windows 3991 // we keep accessibility focus behavior to constrain it only in 3992 // the active window. Look at updateAccessibilityFocusBehaviorLocked 3993 // for details. 3994 if (oldActiveWindow != mSecurityPolicy.mActiveWindowId 3995 && mAccessibilityFocusedWindowId == oldActiveWindow 3996 && getCurrentUserStateLocked().mAccessibilityFocusOnlyInActiveWindow) { 3997 mMainHandler.obtainMessage(MainHandler.MSG_CLEAR_ACCESSIBILITY_FOCUS, 3998 oldActiveWindow, 0).sendToTarget(); 3999 } 4000 } 4001 } 4002 4003 public int getActiveWindowId() { 4004 if (mActiveWindowId == INVALID_WINDOW_ID && !mTouchInteractionInProgress) { 4005 mActiveWindowId = getFocusedWindowId(); 4006 } 4007 return mActiveWindowId; 4008 } 4009 4010 private void setActiveWindowLocked(int windowId) { 4011 if (mActiveWindowId != windowId) { 4012 mActiveWindowId = windowId; 4013 if (mWindows != null) { 4014 final int windowCount = mWindows.size(); 4015 for (int i = 0; i < windowCount; i++) { 4016 AccessibilityWindowInfo window = mWindows.get(i); 4017 window.setActive(window.getId() == windowId); 4018 } 4019 } 4020 notifyWindowsChanged(); 4021 } 4022 } 4023 4024 private void setAccessibilityFocusedWindowLocked(int windowId) { 4025 if (mAccessibilityFocusedWindowId != windowId) { 4026 mAccessibilityFocusedWindowId = windowId; 4027 if (mWindows != null) { 4028 final int windowCount = mWindows.size(); 4029 for (int i = 0; i < windowCount; i++) { 4030 AccessibilityWindowInfo window = mWindows.get(i); 4031 window.setAccessibilityFocused(window.getId() == windowId); 4032 } 4033 } 4034 4035 notifyWindowsChanged(); 4036 } 4037 } 4038 4039 private void notifyWindowsChanged() { 4040 if (mWindowsForAccessibilityCallback == null) { 4041 return; 4042 } 4043 final long identity = Binder.clearCallingIdentity(); 4044 try { 4045 // Let the client know the windows changed. 4046 AccessibilityEvent event = AccessibilityEvent.obtain( 4047 AccessibilityEvent.TYPE_WINDOWS_CHANGED); 4048 event.setEventTime(SystemClock.uptimeMillis()); 4049 sendAccessibilityEvent(event, mCurrentUserId); 4050 } finally { 4051 Binder.restoreCallingIdentity(identity); 4052 } 4053 } 4054 4055 public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) { 4056 return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId); 4057 } 4058 4059 public boolean canRetrieveWindowsLocked(Service service) { 4060 return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows; 4061 } 4062 4063 public boolean canRetrieveWindowContentLocked(Service service) { 4064 return (service.mAccessibilityServiceInfo.getCapabilities() 4065 & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; 4066 } 4067 4068 public boolean canControlMagnification(Service service) { 4069 return (service.mAccessibilityServiceInfo.getCapabilities() 4070 & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0; 4071 } 4072 4073 public boolean canPerformGestures(Service service) { 4074 return (service.mAccessibilityServiceInfo.getCapabilities() 4075 & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0; 4076 } 4077 4078 private int resolveProfileParentLocked(int userId) { 4079 if (userId != mCurrentUserId) { 4080 final long identity = Binder.clearCallingIdentity(); 4081 try { 4082 UserInfo parent = mUserManager.getProfileParent(userId); 4083 if (parent != null) { 4084 return parent.getUserHandle().getIdentifier(); 4085 } 4086 } finally { 4087 Binder.restoreCallingIdentity(identity); 4088 } 4089 } 4090 return userId; 4091 } 4092 4093 public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) { 4094 final int callingUid = Binder.getCallingUid(); 4095 if (callingUid == 0 4096 || callingUid == Process.SYSTEM_UID 4097 || callingUid == Process.SHELL_UID) { 4098 if (userId == UserHandle.USER_CURRENT 4099 || userId == UserHandle.USER_CURRENT_OR_SELF) { 4100 return mCurrentUserId; 4101 } 4102 return resolveProfileParentLocked(userId); 4103 } 4104 final int callingUserId = UserHandle.getUserId(callingUid); 4105 if (callingUserId == userId) { 4106 return resolveProfileParentLocked(userId); 4107 } 4108 final int callingUserParentId = resolveProfileParentLocked(callingUserId); 4109 if (callingUserParentId == mCurrentUserId && 4110 (userId == UserHandle.USER_CURRENT 4111 || userId == UserHandle.USER_CURRENT_OR_SELF)) { 4112 return mCurrentUserId; 4113 } 4114 if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) 4115 && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { 4116 throw new SecurityException("Call from user " + callingUserId + " as user " 4117 + userId + " without permission INTERACT_ACROSS_USERS or " 4118 + "INTERACT_ACROSS_USERS_FULL not allowed."); 4119 } 4120 if (userId == UserHandle.USER_CURRENT 4121 || userId == UserHandle.USER_CURRENT_OR_SELF) { 4122 return mCurrentUserId; 4123 } 4124 throw new IllegalArgumentException("Calling user can be changed to only " 4125 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); 4126 } 4127 4128 public boolean isCallerInteractingAcrossUsers(int userId) { 4129 final int callingUid = Binder.getCallingUid(); 4130 return (Binder.getCallingPid() == android.os.Process.myPid() 4131 || callingUid == Process.SHELL_UID 4132 || userId == UserHandle.USER_CURRENT 4133 || userId == UserHandle.USER_CURRENT_OR_SELF); 4134 } 4135 4136 private boolean isRetrievalAllowingWindow(int windowId) { 4137 // The system gets to interact with any window it wants. 4138 if (Binder.getCallingUid() == Process.SYSTEM_UID) { 4139 return true; 4140 } 4141 if (windowId == mActiveWindowId) { 4142 return true; 4143 } 4144 return findWindowById(windowId) != null; 4145 } 4146 4147 private AccessibilityWindowInfo findWindowById(int windowId) { 4148 if (mWindows != null) { 4149 final int windowCount = mWindows.size(); 4150 for (int i = 0; i < windowCount; i++) { 4151 AccessibilityWindowInfo window = mWindows.get(i); 4152 if (window.getId() == windowId) { 4153 return window; 4154 } 4155 } 4156 } 4157 return null; 4158 } 4159 4160 private void enforceCallingPermission(String permission, String function) { 4161 if (OWN_PROCESS_ID == Binder.getCallingPid()) { 4162 return; 4163 } 4164 if (!hasPermission(permission)) { 4165 throw new SecurityException("You do not have " + permission 4166 + " required to call " + function + " from pid=" 4167 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 4168 } 4169 } 4170 4171 private boolean hasPermission(String permission) { 4172 return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; 4173 } 4174 4175 private int getFocusedWindowId() { 4176 IBinder token = mWindowManagerService.getFocusedWindowToken(); 4177 synchronized (mLock) { 4178 return findWindowIdLocked(token); 4179 } 4180 } 4181 } 4182 4183 private class UserState { 4184 public final int mUserId; 4185 4186 // Non-transient state. 4187 4188 public final RemoteCallbackList<IAccessibilityManagerClient> mClients = 4189 new RemoteCallbackList<>(); 4190 4191 public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections = 4192 new SparseArray<>(); 4193 4194 public final SparseArray<IBinder> mWindowTokens = new SparseArray<>(); 4195 4196 // Transient state. 4197 4198 public final CopyOnWriteArrayList<Service> mBoundServices = 4199 new CopyOnWriteArrayList<>(); 4200 4201 public final Map<ComponentName, Service> mComponentNameToServiceMap = 4202 new HashMap<>(); 4203 4204 public final List<AccessibilityServiceInfo> mInstalledServices = 4205 new ArrayList<>(); 4206 4207 public final Set<ComponentName> mBindingServices = new HashSet<>(); 4208 4209 public final Set<ComponentName> mEnabledServices = new HashSet<>(); 4210 4211 public final Set<ComponentName> mTouchExplorationGrantedServices = 4212 new HashSet<>(); 4213 4214 public ComponentName mServiceChangingSoftKeyboardMode; 4215 4216 public int mLastSentClientState = -1; 4217 4218 public int mSoftKeyboardShowMode = 0; 4219 4220 public boolean mIsTouchExplorationEnabled; 4221 public boolean mIsTextHighContrastEnabled; 4222 public boolean mIsEnhancedWebAccessibilityEnabled; 4223 public boolean mIsDisplayMagnificationEnabled; 4224 public boolean mIsAutoclickEnabled; 4225 public boolean mIsPerformGesturesEnabled; 4226 public boolean mIsFilterKeyEventsEnabled; 4227 public boolean mAccessibilityFocusOnlyInActiveWindow; 4228 4229 private Service mUiAutomationService; 4230 private int mUiAutomationFlags; 4231 private IAccessibilityServiceClient mUiAutomationServiceClient; 4232 4233 private IBinder mUiAutomationServiceOwner; 4234 private final DeathRecipient mUiAutomationSerivceOnwerDeathRecipient = 4235 new DeathRecipient() { 4236 @Override 4237 public void binderDied() { 4238 mUiAutomationServiceOwner.unlinkToDeath( 4239 mUiAutomationSerivceOnwerDeathRecipient, 0); 4240 mUiAutomationServiceOwner = null; 4241 if (mUiAutomationService != null) { 4242 mUiAutomationService.binderDied(); 4243 } 4244 } 4245 }; 4246 4247 public UserState(int userId) { 4248 mUserId = userId; 4249 } 4250 4251 public int getClientState() { 4252 int clientState = 0; 4253 if (isHandlingAccessibilityEvents()) { 4254 clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; 4255 } 4256 // Touch exploration relies on enabled accessibility. 4257 if (isHandlingAccessibilityEvents() && mIsTouchExplorationEnabled) { 4258 clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; 4259 } 4260 if (mIsTextHighContrastEnabled) { 4261 clientState |= AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED; 4262 } 4263 return clientState; 4264 } 4265 4266 public boolean isHandlingAccessibilityEvents() { 4267 return !mBoundServices.isEmpty() || !mBindingServices.isEmpty(); 4268 } 4269 4270 public void onSwitchToAnotherUser() { 4271 // Clear UI test automation state. 4272 if (mUiAutomationService != null) { 4273 mUiAutomationService.binderDied(); 4274 } 4275 4276 // Unbind all services. 4277 unbindAllServicesLocked(this); 4278 4279 // Clear service management state. 4280 mBoundServices.clear(); 4281 mBindingServices.clear(); 4282 4283 // Clear event management state. 4284 mLastSentClientState = -1; 4285 4286 // Clear state persisted in settings. 4287 mEnabledServices.clear(); 4288 mTouchExplorationGrantedServices.clear(); 4289 mIsTouchExplorationEnabled = false; 4290 mIsEnhancedWebAccessibilityEnabled = false; 4291 mIsDisplayMagnificationEnabled = false; 4292 mIsAutoclickEnabled = false; 4293 mSoftKeyboardShowMode = 0; 4294 } 4295 4296 public void destroyUiAutomationService() { 4297 mUiAutomationService = null; 4298 mUiAutomationFlags = 0; 4299 mUiAutomationServiceClient = null; 4300 if (mUiAutomationServiceOwner != null) { 4301 mUiAutomationServiceOwner.unlinkToDeath( 4302 mUiAutomationSerivceOnwerDeathRecipient, 0); 4303 mUiAutomationServiceOwner = null; 4304 } 4305 } 4306 4307 boolean isUiAutomationSuppressingOtherServices() { 4308 return ((mUiAutomationService != null) && (mUiAutomationFlags 4309 & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0); 4310 } 4311 } 4312 4313 private final class AccessibilityContentObserver extends ContentObserver { 4314 4315 private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor( 4316 Settings.Secure.TOUCH_EXPLORATION_ENABLED); 4317 4318 private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor( 4319 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 4320 4321 private final Uri mAutoclickEnabledUri = Settings.Secure.getUriFor( 4322 Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED); 4323 4324 private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor( 4325 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 4326 4327 private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure 4328 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); 4329 4330 private final Uri mEnhancedWebAccessibilityUri = Settings.Secure 4331 .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION); 4332 4333 private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor( 4334 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); 4335 4336 private final Uri mDisplayDaltonizerEnabledUri = Settings.Secure.getUriFor( 4337 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED); 4338 4339 private final Uri mDisplayDaltonizerUri = Settings.Secure.getUriFor( 4340 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER); 4341 4342 private final Uri mHighTextContrastUri = Settings.Secure.getUriFor( 4343 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED); 4344 4345 private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor( 4346 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); 4347 4348 public AccessibilityContentObserver(Handler handler) { 4349 super(handler); 4350 } 4351 4352 public void register(ContentResolver contentResolver) { 4353 contentResolver.registerContentObserver(mTouchExplorationEnabledUri, 4354 false, this, UserHandle.USER_ALL); 4355 contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri, 4356 false, this, UserHandle.USER_ALL); 4357 contentResolver.registerContentObserver(mAutoclickEnabledUri, 4358 false, this, UserHandle.USER_ALL); 4359 contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri, 4360 false, this, UserHandle.USER_ALL); 4361 contentResolver.registerContentObserver( 4362 mTouchExplorationGrantedAccessibilityServicesUri, 4363 false, this, UserHandle.USER_ALL); 4364 contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri, 4365 false, this, UserHandle.USER_ALL); 4366 contentResolver.registerContentObserver( 4367 mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL); 4368 contentResolver.registerContentObserver( 4369 mDisplayDaltonizerEnabledUri, false, this, UserHandle.USER_ALL); 4370 contentResolver.registerContentObserver( 4371 mDisplayDaltonizerUri, false, this, UserHandle.USER_ALL); 4372 contentResolver.registerContentObserver( 4373 mHighTextContrastUri, false, this, UserHandle.USER_ALL); 4374 contentResolver.registerContentObserver( 4375 mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL); 4376 } 4377 4378 @Override 4379 public void onChange(boolean selfChange, Uri uri) { 4380 synchronized (mLock) { 4381 // Profiles share the accessibility state of the parent. Therefore, 4382 // we are checking for changes only the parent settings. 4383 UserState userState = getCurrentUserStateLocked(); 4384 4385 // If the automation service is suppressing, we will update when it dies. 4386 if (userState.isUiAutomationSuppressingOtherServices()) { 4387 return; 4388 } 4389 4390 if (mTouchExplorationEnabledUri.equals(uri)) { 4391 if (readTouchExplorationEnabledSettingLocked(userState)) { 4392 onUserStateChangedLocked(userState); 4393 } 4394 } else if (mDisplayMagnificationEnabledUri.equals(uri)) { 4395 if (readDisplayMagnificationEnabledSettingLocked(userState)) { 4396 onUserStateChangedLocked(userState); 4397 } 4398 } else if (mAutoclickEnabledUri.equals(uri)) { 4399 if (readAutoclickEnabledSettingLocked(userState)) { 4400 onUserStateChangedLocked(userState); 4401 } 4402 } else if (mEnabledAccessibilityServicesUri.equals(uri)) { 4403 if (readEnabledAccessibilityServicesLocked(userState)) { 4404 onUserStateChangedLocked(userState); 4405 } 4406 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { 4407 if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) { 4408 onUserStateChangedLocked(userState); 4409 } 4410 } else if (mEnhancedWebAccessibilityUri.equals(uri)) { 4411 if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) { 4412 onUserStateChangedLocked(userState); 4413 } 4414 } else if (mDisplayDaltonizerEnabledUri.equals(uri) 4415 || mDisplayDaltonizerUri.equals(uri)) { 4416 updateDisplayDaltonizerLocked(userState); 4417 } else if (mDisplayInversionEnabledUri.equals(uri)) { 4418 updateDisplayInversionLocked(userState); 4419 } else if (mHighTextContrastUri.equals(uri)) { 4420 if (readHighTextContrastEnabledSettingLocked(userState)) { 4421 onUserStateChangedLocked(userState); 4422 } 4423 } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) { 4424 if (readSoftKeyboardShowModeChangedLocked(userState)) { 4425 notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode); 4426 onUserStateChangedLocked(userState); 4427 } 4428 } 4429 } 4430 } 4431 } 4432 } 4433