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