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