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