1 /* 2 ** Copyright 2009, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.server.accessibility; 18 19 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT; 20 import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 21 22 import android.Manifest; 23 import android.accessibilityservice.AccessibilityService; 24 import android.accessibilityservice.AccessibilityServiceInfo; 25 import android.accessibilityservice.IAccessibilityServiceClient; 26 import android.accessibilityservice.IAccessibilityServiceConnection; 27 import android.app.AlertDialog; 28 import android.app.PendingIntent; 29 import android.app.StatusBarManager; 30 import android.content.BroadcastReceiver; 31 import android.content.ComponentName; 32 import android.content.ContentResolver; 33 import android.content.Context; 34 import android.content.DialogInterface; 35 import android.content.DialogInterface.OnClickListener; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.content.ServiceConnection; 39 import android.content.pm.PackageManager; 40 import android.content.pm.ResolveInfo; 41 import android.content.pm.ServiceInfo; 42 import android.database.ContentObserver; 43 import android.graphics.Point; 44 import android.graphics.Rect; 45 import android.hardware.display.DisplayManager; 46 import android.hardware.input.InputManager; 47 import android.net.Uri; 48 import android.os.Binder; 49 import android.os.Build; 50 import android.os.Bundle; 51 import android.os.Handler; 52 import android.os.IBinder; 53 import android.os.Looper; 54 import android.os.Message; 55 import android.os.Process; 56 import android.os.RemoteCallbackList; 57 import android.os.RemoteException; 58 import android.os.ServiceManager; 59 import android.os.SystemClock; 60 import android.os.UserHandle; 61 import android.os.UserManager; 62 import android.provider.Settings; 63 import android.text.TextUtils; 64 import android.text.TextUtils.SimpleStringSplitter; 65 import android.util.Slog; 66 import android.util.SparseArray; 67 import android.view.Display; 68 import android.view.IWindow; 69 import android.view.IWindowManager; 70 import android.view.InputDevice; 71 import android.view.KeyCharacterMap; 72 import android.view.KeyEvent; 73 import android.view.WindowInfo; 74 import android.view.WindowManager; 75 import android.view.accessibility.AccessibilityEvent; 76 import android.view.accessibility.AccessibilityInteractionClient; 77 import android.view.accessibility.AccessibilityManager; 78 import android.view.accessibility.AccessibilityNodeInfo; 79 import android.view.accessibility.IAccessibilityInteractionConnection; 80 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 81 import android.view.accessibility.IAccessibilityManager; 82 import android.view.accessibility.IAccessibilityManagerClient; 83 84 import com.android.internal.R; 85 import com.android.internal.content.PackageMonitor; 86 import com.android.internal.statusbar.IStatusBarService; 87 88 import org.xmlpull.v1.XmlPullParserException; 89 90 import java.io.IOException; 91 import java.util.ArrayList; 92 import java.util.Arrays; 93 import java.util.HashMap; 94 import java.util.HashSet; 95 import java.util.Iterator; 96 import java.util.List; 97 import java.util.Map; 98 import java.util.Set; 99 import java.util.concurrent.CopyOnWriteArrayList; 100 101 /** 102 * This class is instantiated by the system as a system level service and can be 103 * accessed only by the system. The task of this service is to be a centralized 104 * event dispatch for {@link AccessibilityEvent}s generated across all processes 105 * on the device. Events are dispatched to {@link AccessibilityService}s. 106 * 107 * @hide 108 */ 109 public class AccessibilityManagerService extends IAccessibilityManager.Stub { 110 111 private static final boolean DEBUG = false; 112 113 private static final String LOG_TAG = "AccessibilityManagerService"; 114 115 // TODO: This is arbitrary. When there is time implement this by watching 116 // when that accessibility services are bound. 117 private static final int WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS = 3000; 118 119 private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE = 120 "registerUiTestAutomationService"; 121 122 private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED = 123 "temporaryEnableAccessibilityStateUntilKeyguardRemoved"; 124 125 private static final char COMPONENT_NAME_SEPARATOR = ':'; 126 127 private static final int OWN_PROCESS_ID = android.os.Process.myPid(); 128 129 private static int sIdCounter = 0; 130 131 private static int sNextWindowId; 132 133 private final Context mContext; 134 135 private final Object mLock = new Object(); 136 137 private final SimpleStringSplitter mStringColonSplitter = 138 new SimpleStringSplitter(COMPONENT_NAME_SEPARATOR); 139 140 private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = 141 new ArrayList<AccessibilityServiceInfo>(); 142 143 private final Rect mTempRect = new Rect(); 144 145 private final Point mTempPoint = new Point(); 146 147 private final Display mDefaultDisplay; 148 149 private final PackageManager mPackageManager; 150 151 private final IWindowManager mWindowManagerService; 152 153 private final SecurityPolicy mSecurityPolicy; 154 155 private final MainHandler mMainHandler; 156 157 private Service mUiAutomationService; 158 159 private Service mQueryBridge; 160 161 private AlertDialog mEnableTouchExplorationDialog; 162 163 private AccessibilityInputFilter mInputFilter; 164 165 private boolean mHasInputFilter; 166 167 private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients = 168 new RemoteCallbackList<IAccessibilityManagerClient>(); 169 170 private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections = 171 new SparseArray<AccessibilityConnectionWrapper>(); 172 173 private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<IBinder>(); 174 175 private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); 176 177 private final TempUserStateChangeMemento mTempStateChangeForCurrentUserMemento = 178 new TempUserStateChangeMemento(); 179 180 private int mCurrentUserId = UserHandle.USER_OWNER; 181 getCurrentUserStateLocked()182 private UserState getCurrentUserStateLocked() { 183 return getUserStateLocked(mCurrentUserId); 184 } 185 getUserStateLocked(int userId)186 private UserState getUserStateLocked(int userId) { 187 UserState state = mUserStates.get(userId); 188 if (state == null) { 189 state = new UserState(userId); 190 mUserStates.put(userId, state); 191 } 192 return state; 193 } 194 195 /** 196 * Creates a new instance. 197 * 198 * @param context A {@link Context} instance. 199 */ AccessibilityManagerService(Context context)200 public AccessibilityManagerService(Context context) { 201 mContext = context; 202 mPackageManager = mContext.getPackageManager(); 203 mWindowManagerService = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE); 204 mSecurityPolicy = new SecurityPolicy(); 205 mMainHandler = new MainHandler(mContext.getMainLooper()); 206 //TODO: (multi-display) We need to support multiple displays. 207 DisplayManager displayManager = (DisplayManager) 208 mContext.getSystemService(Context.DISPLAY_SERVICE); 209 mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 210 registerBroadcastReceivers(); 211 new AccessibilityContentObserver(mMainHandler).register( 212 context.getContentResolver()); 213 } 214 registerBroadcastReceivers()215 private void registerBroadcastReceivers() { 216 PackageMonitor monitor = new PackageMonitor() { 217 @Override 218 public void onSomePackagesChanged() { 219 synchronized (mLock) { 220 if (getChangingUserId() != mCurrentUserId) { 221 return; 222 } 223 // We will update when the automation service dies. 224 if (mUiAutomationService == null) { 225 UserState userState = getCurrentUserStateLocked(); 226 populateInstalledAccessibilityServiceLocked(userState); 227 manageServicesLocked(userState); 228 } 229 } 230 } 231 232 @Override 233 public void onPackageRemoved(String packageName, int uid) { 234 synchronized (mLock) { 235 final int userId = getChangingUserId(); 236 if (userId != mCurrentUserId) { 237 return; 238 } 239 UserState state = getUserStateLocked(userId); 240 Iterator<ComponentName> it = state.mEnabledServices.iterator(); 241 while (it.hasNext()) { 242 ComponentName comp = it.next(); 243 String compPkg = comp.getPackageName(); 244 if (compPkg.equals(packageName)) { 245 it.remove(); 246 // Update the enabled services setting. 247 persistComponentNamesToSettingLocked( 248 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 249 state.mEnabledServices, userId); 250 // Update the touch exploration granted services setting. 251 state.mTouchExplorationGrantedServices.remove(comp); 252 persistComponentNamesToSettingLocked( 253 Settings.Secure. 254 TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 255 state.mEnabledServices, userId); 256 return; 257 } 258 } 259 } 260 } 261 262 @Override 263 public boolean onHandleForceStop(Intent intent, String[] packages, 264 int uid, boolean doit) { 265 synchronized (mLock) { 266 final int userId = getChangingUserId(); 267 if (userId != mCurrentUserId) { 268 return false; 269 } 270 UserState state = getUserStateLocked(userId); 271 Iterator<ComponentName> it = state.mEnabledServices.iterator(); 272 while (it.hasNext()) { 273 ComponentName comp = it.next(); 274 String compPkg = comp.getPackageName(); 275 for (String pkg : packages) { 276 if (compPkg.equals(pkg)) { 277 if (!doit) { 278 return true; 279 } 280 it.remove(); 281 persistComponentNamesToSettingLocked( 282 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 283 state.mEnabledServices, userId); 284 } 285 } 286 } 287 return false; 288 } 289 } 290 }; 291 292 // package changes 293 monitor.register(mContext, null, UserHandle.ALL, true); 294 295 // user change and unlock 296 IntentFilter intentFilter = new IntentFilter(); 297 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 298 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 299 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 300 301 mContext.registerReceiverAsUser(new BroadcastReceiver() { 302 @Override 303 public void onReceive(Context context, Intent intent) { 304 String action = intent.getAction(); 305 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 306 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 307 } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 308 removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); 309 } else if (Intent.ACTION_USER_PRESENT.equals(action)) { 310 restoreStateFromMementoIfNeeded(); 311 } 312 } 313 }, UserHandle.ALL, intentFilter, null, null); 314 } 315 addClient(IAccessibilityManagerClient client, int userId)316 public int addClient(IAccessibilityManagerClient client, int userId) { 317 synchronized (mLock) { 318 final int resolvedUserId = mSecurityPolicy 319 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 320 // If the client is from a process that runs across users such as 321 // the system UI or the system we add it to the global state that 322 // is shared across users. 323 UserState userState = getUserStateLocked(resolvedUserId); 324 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 325 mGlobalClients.register(client); 326 if (DEBUG) { 327 Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid()); 328 } 329 return getClientState(userState); 330 } else { 331 userState.mClients.register(client); 332 // If this client is not for the current user we do not 333 // return a state since it is not for the foreground user. 334 // We will send the state to the client on a user switch. 335 if (DEBUG) { 336 Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid() 337 + " and userId:" + mCurrentUserId); 338 } 339 return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0; 340 } 341 } 342 } 343 sendAccessibilityEvent(AccessibilityEvent event, int userId)344 public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) { 345 synchronized (mLock) { 346 final int resolvedUserId = mSecurityPolicy 347 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 348 // This method does nothing for a background user. 349 if (resolvedUserId != mCurrentUserId) { 350 return true; // yes, recycle the event 351 } 352 if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) { 353 mSecurityPolicy.updateEventSourceLocked(event); 354 mMainHandler.obtainMessage(MainHandler.MSG_UPDATE_ACTIVE_WINDOW, 355 event.getWindowId(), event.getEventType()).sendToTarget(); 356 notifyAccessibilityServicesDelayedLocked(event, false); 357 notifyAccessibilityServicesDelayedLocked(event, true); 358 } 359 if (mHasInputFilter && mInputFilter != null) { 360 mMainHandler.obtainMessage(MainHandler.MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER, 361 AccessibilityEvent.obtain(event)).sendToTarget(); 362 } 363 event.recycle(); 364 getUserStateLocked(resolvedUserId).mHandledFeedbackTypes = 0; 365 } 366 return (OWN_PROCESS_ID != Binder.getCallingPid()); 367 } 368 getInstalledAccessibilityServiceList(int userId)369 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { 370 synchronized (mLock) { 371 final int resolvedUserId = mSecurityPolicy 372 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 373 return getUserStateLocked(resolvedUserId).mInstalledServices; 374 } 375 } 376 getEnabledAccessibilityServiceList(int feedbackType, int userId)377 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, 378 int userId) { 379 List<AccessibilityServiceInfo> result = null; 380 synchronized (mLock) { 381 final int resolvedUserId = mSecurityPolicy 382 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 383 result = mEnabledServicesForFeedbackTempList; 384 result.clear(); 385 List<Service> services = getUserStateLocked(resolvedUserId).mServices; 386 while (feedbackType != 0) { 387 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); 388 feedbackType &= ~feedbackTypeBit; 389 final int serviceCount = services.size(); 390 for (int i = 0; i < serviceCount; i++) { 391 Service service = services.get(i); 392 if ((service.mFeedbackType & feedbackTypeBit) != 0) { 393 result.add(service.mAccessibilityServiceInfo); 394 } 395 } 396 } 397 } 398 return result; 399 } 400 interrupt(int userId)401 public void interrupt(int userId) { 402 CopyOnWriteArrayList<Service> services; 403 synchronized (mLock) { 404 final int resolvedUserId = mSecurityPolicy 405 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 406 // This method does nothing for a background user. 407 if (resolvedUserId != mCurrentUserId) { 408 return; 409 } 410 services = getUserStateLocked(resolvedUserId).mServices; 411 } 412 for (int i = 0, count = services.size(); i < count; i++) { 413 Service service = services.get(i); 414 try { 415 service.mServiceInterface.onInterrupt(); 416 } catch (RemoteException re) { 417 Slog.e(LOG_TAG, "Error during sending interrupt request to " 418 + service.mService, re); 419 } 420 } 421 } 422 addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection, int userId)423 public int addAccessibilityInteractionConnection(IWindow windowToken, 424 IAccessibilityInteractionConnection connection, int userId) throws RemoteException { 425 synchronized (mLock) { 426 final int resolvedUserId = mSecurityPolicy 427 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 428 final int windowId = sNextWindowId++; 429 // If the window is from a process that runs across users such as 430 // the system UI or the system we add it to the global state that 431 // is shared across users. 432 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 433 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( 434 windowId, connection, UserHandle.USER_ALL); 435 wrapper.linkToDeath(); 436 mGlobalInteractionConnections.put(windowId, wrapper); 437 mGlobalWindowTokens.put(windowId, windowToken.asBinder()); 438 if (DEBUG) { 439 Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid() 440 + " with windowId: " + windowId); 441 } 442 } else { 443 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper( 444 windowId, connection, resolvedUserId); 445 wrapper.linkToDeath(); 446 UserState userState = getUserStateLocked(resolvedUserId); 447 userState.mInteractionConnections.put(windowId, wrapper); 448 userState.mWindowTokens.put(windowId, windowToken.asBinder()); 449 if (DEBUG) { 450 Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid() 451 + " with windowId: " + windowId + " and userId:" + mCurrentUserId); 452 } 453 } 454 if (DEBUG) { 455 Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId); 456 } 457 return windowId; 458 } 459 } 460 removeAccessibilityInteractionConnection(IWindow window)461 public void removeAccessibilityInteractionConnection(IWindow window) { 462 synchronized (mLock) { 463 mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( 464 UserHandle.getCallingUserId()); 465 IBinder token = window.asBinder(); 466 final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked( 467 token, mGlobalWindowTokens, mGlobalInteractionConnections); 468 if (removedWindowId >= 0) { 469 if (DEBUG) { 470 Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid() 471 + " with windowId: " + removedWindowId); 472 } 473 return; 474 } 475 final int userCount = mUserStates.size(); 476 for (int i = 0; i < userCount; i++) { 477 UserState userState = mUserStates.valueAt(i); 478 final int removedWindowIdForUser = 479 removeAccessibilityInteractionConnectionInternalLocked( 480 token, userState.mWindowTokens, userState.mInteractionConnections); 481 if (removedWindowIdForUser >= 0) { 482 if (DEBUG) { 483 Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid() 484 + " with windowId: " + removedWindowIdForUser + " and userId:" 485 + mUserStates.keyAt(i)); 486 } 487 return; 488 } 489 } 490 } 491 } 492 removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, SparseArray<IBinder> windowTokens, SparseArray<AccessibilityConnectionWrapper> interactionConnections)493 private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, 494 SparseArray<IBinder> windowTokens, 495 SparseArray<AccessibilityConnectionWrapper> interactionConnections) { 496 final int count = windowTokens.size(); 497 for (int i = 0; i < count; i++) { 498 if (windowTokens.valueAt(i) == windowToken) { 499 final int windowId = windowTokens.keyAt(i); 500 windowTokens.removeAt(i); 501 AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId); 502 wrapper.unlinkToDeath(); 503 interactionConnections.remove(windowId); 504 return windowId; 505 } 506 } 507 return -1; 508 } 509 registerUiTestAutomationService(IAccessibilityServiceClient serviceClient, AccessibilityServiceInfo accessibilityServiceInfo)510 public void registerUiTestAutomationService(IAccessibilityServiceClient serviceClient, 511 AccessibilityServiceInfo accessibilityServiceInfo) { 512 mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, 513 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE); 514 ComponentName componentName = new ComponentName("foo.bar", 515 "AutomationAccessibilityService"); 516 synchronized (mLock) { 517 // If an automation services is connected to the system all services are stopped 518 // so the automation one is the only one running. Settings are not changed so when 519 // the automation service goes away the state is restored from the settings. 520 UserState userState = getCurrentUserStateLocked(); 521 unbindAllServicesLocked(userState); 522 523 // If necessary enable accessibility and announce that. 524 if (!userState.mIsAccessibilityEnabled) { 525 userState.mIsAccessibilityEnabled = true; 526 } 527 // No touch exploration. 528 userState.mIsTouchExplorationEnabled = false; 529 530 // Hook the automation service up. 531 mUiAutomationService = new Service(mCurrentUserId, componentName, 532 accessibilityServiceInfo, true); 533 mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder()); 534 535 updateInputFilterLocked(userState); 536 scheduleSendStateToClientsLocked(userState); 537 } 538 } 539 temporaryEnableAccessibilityStateUntilKeyguardRemoved( ComponentName service, boolean touchExplorationEnabled)540 public void temporaryEnableAccessibilityStateUntilKeyguardRemoved( 541 ComponentName service, boolean touchExplorationEnabled) { 542 mSecurityPolicy.enforceCallingPermission( 543 Manifest.permission.TEMPORARY_ENABLE_ACCESSIBILITY, 544 TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED); 545 try { 546 if (!mWindowManagerService.isKeyguardLocked()) { 547 return; 548 } 549 } catch (RemoteException re) { 550 return; 551 } 552 synchronized (mLock) { 553 UserState userState = getCurrentUserStateLocked(); 554 // Stash the old state so we can restore it when the keyguard is gone. 555 mTempStateChangeForCurrentUserMemento.initialize(mCurrentUserId, getCurrentUserStateLocked()); 556 // Set the temporary state. 557 userState.mIsAccessibilityEnabled = true; 558 userState.mIsTouchExplorationEnabled= touchExplorationEnabled; 559 userState.mIsDisplayMagnificationEnabled = false; 560 userState.mEnabledServices.clear(); 561 userState.mEnabledServices.add(service); 562 userState.mTouchExplorationGrantedServices.clear(); 563 userState.mTouchExplorationGrantedServices.add(service); 564 // Update the internal state. 565 performServiceManagementLocked(userState); 566 updateInputFilterLocked(userState); 567 scheduleSendStateToClientsLocked(userState); 568 } 569 } 570 unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient)571 public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) { 572 synchronized (mLock) { 573 // Automation service is not bound, so pretend it died to perform clean up. 574 if (mUiAutomationService != null && mUiAutomationService.mServiceInterface != null 575 && serviceClient != null && mUiAutomationService.mServiceInterface 576 .asBinder() == serviceClient.asBinder()) { 577 mUiAutomationService.binderDied(); 578 } 579 } 580 } 581 onGesture(int gestureId)582 boolean onGesture(int gestureId) { 583 synchronized (mLock) { 584 boolean handled = notifyGestureLocked(gestureId, false); 585 if (!handled) { 586 handled = notifyGestureLocked(gestureId, true); 587 } 588 return handled; 589 } 590 } 591 592 /** 593 * Gets the bounds of the accessibility focus in the active window. 594 * 595 * @param outBounds The output to which to write the focus bounds. 596 * @return Whether accessibility focus was found and the bounds are populated. 597 */ 598 // TODO: (multi-display) Make sure this works for multiple displays. getAccessibilityFocusBoundsInActiveWindow(Rect outBounds)599 boolean getAccessibilityFocusBoundsInActiveWindow(Rect outBounds) { 600 // Instead of keeping track of accessibility focus events per 601 // window to be able to find the focus in the active window, 602 // we take a stateless approach and look it up. This is fine 603 // since we do this only when the user clicks/long presses. 604 Service service = getQueryBridge(); 605 final int connectionId = service.mId; 606 AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance(); 607 client.addConnection(connectionId, service); 608 try { 609 AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance() 610 .getRootInActiveWindow(connectionId); 611 if (root == null) { 612 return false; 613 } 614 AccessibilityNodeInfo focus = root.findFocus( 615 AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); 616 if (focus == null) { 617 return false; 618 } 619 focus.getBoundsInScreen(outBounds); 620 // Clip to the window rectangle. 621 Rect windowBounds = mTempRect; 622 getActiveWindowBounds(windowBounds); 623 outBounds.intersect(windowBounds); 624 // Clip to the screen rectangle. 625 mDefaultDisplay.getRealSize(mTempPoint); 626 outBounds.intersect(0, 0, mTempPoint.x, mTempPoint.y); 627 return true; 628 } finally { 629 client.removeConnection(connectionId); 630 } 631 } 632 633 /** 634 * Gets the bounds of the active window. 635 * 636 * @param outBounds The output to which to write the bounds. 637 */ getActiveWindowBounds(Rect outBounds)638 boolean getActiveWindowBounds(Rect outBounds) { 639 IBinder token; 640 synchronized (mLock) { 641 final int windowId = mSecurityPolicy.mActiveWindowId; 642 token = mGlobalWindowTokens.get(windowId); 643 if (token == null) { 644 token = getCurrentUserStateLocked().mWindowTokens.get(windowId); 645 } 646 } 647 WindowInfo info = null; 648 try { 649 info = mWindowManagerService.getWindowInfo(token); 650 if (info != null) { 651 outBounds.set(info.frame); 652 return true; 653 } 654 } catch (RemoteException re) { 655 /* ignore */ 656 } finally { 657 if (info != null) { 658 info.recycle(); 659 } 660 } 661 return false; 662 } 663 getActiveWindowId()664 int getActiveWindowId() { 665 return mSecurityPolicy.mActiveWindowId; 666 } 667 onTouchInteractionStart()668 void onTouchInteractionStart() { 669 mSecurityPolicy.onTouchInteractionStart(); 670 } 671 onTouchInteractionEnd()672 void onTouchInteractionEnd() { 673 mSecurityPolicy.onTouchInteractionEnd(); 674 } 675 switchUser(int userId)676 private void switchUser(int userId) { 677 synchronized (mLock) { 678 // The user switched so we do not need to restore the current user 679 // state since we will fully rebuild it when he becomes current again. 680 mTempStateChangeForCurrentUserMemento.clear(); 681 682 // Disconnect from services for the old user. 683 UserState oldUserState = getUserStateLocked(mCurrentUserId); 684 unbindAllServicesLocked(oldUserState); 685 686 // Disable the local managers for the old user. 687 if (oldUserState.mClients.getRegisteredCallbackCount() > 0) { 688 mMainHandler.obtainMessage(MainHandler.MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER, 689 oldUserState.mUserId, 0).sendToTarget(); 690 } 691 692 // Announce user changes only if more that one exist. 693 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 694 final boolean announceNewUser = userManager.getUsers().size() > 1; 695 696 // The user changed. 697 mCurrentUserId = userId; 698 699 // Recreate the internal state for the new user. 700 mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE, 701 mCurrentUserId, 0).sendToTarget(); 702 703 if (announceNewUser) { 704 // Schedule announcement of the current user if needed. 705 mMainHandler.sendEmptyMessageDelayed(MainHandler.MSG_ANNOUNCE_NEW_USER_IF_NEEDED, 706 WAIT_FOR_USER_STATE_FULLY_INITIALIZED_MILLIS); 707 } 708 } 709 } 710 removeUser(int userId)711 private void removeUser(int userId) { 712 synchronized (mLock) { 713 mUserStates.remove(userId); 714 } 715 } 716 restoreStateFromMementoIfNeeded()717 private void restoreStateFromMementoIfNeeded() { 718 synchronized (mLock) { 719 if (mTempStateChangeForCurrentUserMemento.mUserId != UserHandle.USER_NULL) { 720 UserState userState = getCurrentUserStateLocked(); 721 // Restore the state from the memento. 722 mTempStateChangeForCurrentUserMemento.applyTo(userState); 723 mTempStateChangeForCurrentUserMemento.clear(); 724 // Update the internal state. 725 performServiceManagementLocked(userState); 726 updateInputFilterLocked(userState); 727 scheduleSendStateToClientsLocked(userState); 728 } 729 } 730 } 731 getQueryBridge()732 private Service getQueryBridge() { 733 if (mQueryBridge == null) { 734 AccessibilityServiceInfo info = new AccessibilityServiceInfo(); 735 mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true); 736 } 737 return mQueryBridge; 738 } 739 notifyGestureLocked(int gestureId, boolean isDefault)740 private boolean notifyGestureLocked(int gestureId, boolean isDefault) { 741 // TODO: Now we are giving the gestures to the last enabled 742 // service that can handle them which is the last one 743 // in our list since we write the last enabled as the 744 // last record in the enabled services setting. Ideally, 745 // the user should make the call which service handles 746 // gestures. However, only one service should handle 747 // gestures to avoid user frustration when different 748 // behavior is observed from different combinations of 749 // enabled accessibility services. 750 UserState state = getCurrentUserStateLocked(); 751 for (int i = state.mServices.size() - 1; i >= 0; i--) { 752 Service service = state.mServices.get(i); 753 if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) { 754 service.notifyGesture(gestureId); 755 return true; 756 } 757 } 758 return false; 759 } 760 761 /** 762 * Removes an AccessibilityInteractionConnection. 763 * 764 * @param windowId The id of the window to which the connection is targeted. 765 * @param userId The id of the user owning the connection. UserHandle.USER_ALL 766 * if global. 767 */ removeAccessibilityInteractionConnectionLocked(int windowId, int userId)768 private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) { 769 if (userId == UserHandle.USER_ALL) { 770 mGlobalWindowTokens.remove(windowId); 771 mGlobalInteractionConnections.remove(windowId); 772 } else { 773 UserState userState = getCurrentUserStateLocked(); 774 userState.mWindowTokens.remove(windowId); 775 userState.mInteractionConnections.remove(windowId); 776 } 777 if (DEBUG) { 778 Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); 779 } 780 } 781 populateInstalledAccessibilityServiceLocked(UserState userState)782 private void populateInstalledAccessibilityServiceLocked(UserState userState) { 783 userState.mInstalledServices.clear(); 784 785 List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser( 786 new Intent(AccessibilityService.SERVICE_INTERFACE), 787 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 788 mCurrentUserId); 789 790 for (int i = 0, count = installedServices.size(); i < count; i++) { 791 ResolveInfo resolveInfo = installedServices.get(i); 792 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 793 if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals( 794 serviceInfo.permission)) { 795 Slog.w(LOG_TAG, "Skipping accessibilty service " + new ComponentName( 796 serviceInfo.packageName, serviceInfo.name).flattenToShortString() 797 + ": it does not require the permission " 798 + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE); 799 continue; 800 } 801 AccessibilityServiceInfo accessibilityServiceInfo; 802 try { 803 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); 804 userState.mInstalledServices.add(accessibilityServiceInfo); 805 } catch (XmlPullParserException xppe) { 806 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); 807 } catch (IOException ioe) { 808 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe); 809 } 810 } 811 } 812 populateEnabledAccessibilityServicesLocked(UserState userState)813 private void populateEnabledAccessibilityServicesLocked(UserState userState) { 814 populateComponentNamesFromSettingLocked( 815 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 816 userState.mUserId, 817 userState.mEnabledServices); 818 } 819 populateTouchExplorationGrantedAccessibilityServicesLocked( UserState userState)820 private void populateTouchExplorationGrantedAccessibilityServicesLocked( 821 UserState userState) { 822 populateComponentNamesFromSettingLocked( 823 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 824 userState.mUserId, 825 userState.mTouchExplorationGrantedServices); 826 } 827 828 /** 829 * Performs {@link AccessibilityService}s delayed notification. The delay is configurable 830 * and denotes the period after the last event before notifying the service. 831 * 832 * @param event The event. 833 * @param isDefault True to notify default listeners, not default services. 834 */ notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault)835 private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, 836 boolean isDefault) { 837 try { 838 UserState state = getCurrentUserStateLocked(); 839 for (int i = 0, count = state.mServices.size(); i < count; i++) { 840 Service service = state.mServices.get(i); 841 842 if (service.mIsDefault == isDefault) { 843 if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) { 844 state.mHandledFeedbackTypes |= service.mFeedbackType; 845 service.notifyAccessibilityEvent(event); 846 } 847 } 848 } 849 } catch (IndexOutOfBoundsException oobe) { 850 // An out of bounds exception can happen if services are going away 851 // as the for loop is running. If that happens, just bail because 852 // there are no more services to notify. 853 return; 854 } 855 } 856 857 /** 858 * Adds a service for a user. 859 * 860 * @param service The service to add. 861 * @param userId The user id. 862 */ tryAddServiceLocked(Service service, int userId)863 private void tryAddServiceLocked(Service service, int userId) { 864 try { 865 UserState userState = getUserStateLocked(userId); 866 if (userState.mServices.contains(service)) { 867 return; 868 } 869 service.linkToOwnDeath(); 870 userState.mServices.add(service); 871 userState.mComponentNameToServiceMap.put(service.mComponentName, service); 872 updateInputFilterLocked(userState); 873 tryEnableTouchExplorationLocked(service); 874 } catch (RemoteException e) { 875 /* do nothing */ 876 } 877 } 878 879 /** 880 * Removes a service. 881 * 882 * @param service The service. 883 * @return True if the service was removed, false otherwise. 884 */ tryRemoveServiceLocked(Service service)885 private boolean tryRemoveServiceLocked(Service service) { 886 UserState userState = getUserStateLocked(service.mUserId); 887 final boolean removed = userState.mServices.remove(service); 888 if (!removed) { 889 return false; 890 } 891 userState.mComponentNameToServiceMap.remove(service.mComponentName); 892 service.unlinkToOwnDeath(); 893 service.dispose(); 894 updateInputFilterLocked(userState); 895 tryDisableTouchExplorationLocked(service); 896 return removed; 897 } 898 899 /** 900 * Determines if given event can be dispatched to a service based on the package of the 901 * event source and already notified services for that event type. Specifically, a 902 * service is notified if it is interested in events from the package and no other service 903 * providing the same feedback type has been notified. Exception are services the 904 * provide generic feedback (feedback type left as a safety net for unforeseen feedback 905 * types) which are always notified. 906 * 907 * @param service The potential receiver. 908 * @param event The event. 909 * @param handledFeedbackTypes The feedback types for which services have been notified. 910 * @return True if the listener should be notified, false otherwise. 911 */ canDispathEventLocked(Service service, AccessibilityEvent event, int handledFeedbackTypes)912 private boolean canDispathEventLocked(Service service, AccessibilityEvent event, 913 int handledFeedbackTypes) { 914 915 if (!service.canReceiveEvents()) { 916 return false; 917 } 918 919 if (!event.isImportantForAccessibility() 920 && !service.mIncludeNotImportantViews) { 921 return false; 922 } 923 924 int eventType = event.getEventType(); 925 if ((service.mEventTypes & eventType) != eventType) { 926 return false; 927 } 928 929 Set<String> packageNames = service.mPackageNames; 930 CharSequence packageName = event.getPackageName(); 931 932 if (packageNames.isEmpty() || packageNames.contains(packageName)) { 933 int feedbackType = service.mFeedbackType; 934 if ((handledFeedbackTypes & feedbackType) != feedbackType 935 || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) { 936 return true; 937 } 938 } 939 940 return false; 941 } 942 943 /** 944 * Manages services by starting enabled ones and stopping disabled ones. 945 */ manageServicesLocked(UserState userState)946 private void manageServicesLocked(UserState userState) { 947 final int enabledInstalledServicesCount = updateServicesStateLocked(userState); 948 // No enabled installed services => disable accessibility to avoid 949 // sending accessibility events with no recipient across processes. 950 if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { 951 Settings.Secure.putIntForUser(mContext.getContentResolver(), 952 Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId); 953 } 954 } 955 956 /** 957 * Unbinds all bound services for a user. 958 * 959 * @param userState The user state. 960 */ unbindAllServicesLocked(UserState userState)961 private void unbindAllServicesLocked(UserState userState) { 962 List<Service> services = userState.mServices; 963 for (int i = 0, count = services.size(); i < count; i++) { 964 Service service = services.get(i); 965 if (service.unbind()) { 966 i--; 967 count--; 968 } 969 } 970 } 971 972 /** 973 * Populates a set with the {@link ComponentName}s stored in a colon 974 * separated value setting for a given user. 975 * 976 * @param settingName The setting to parse. 977 * @param userId The user id. 978 * @param outComponentNames The output component names. 979 */ populateComponentNamesFromSettingLocked(String settingName, int userId, Set<ComponentName> outComponentNames)980 private void populateComponentNamesFromSettingLocked(String settingName, int userId, 981 Set<ComponentName> outComponentNames) { 982 String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), 983 settingName, userId); 984 outComponentNames.clear(); 985 if (settingValue != null) { 986 TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; 987 splitter.setString(settingValue); 988 while (splitter.hasNext()) { 989 String str = splitter.next(); 990 if (str == null || str.length() <= 0) { 991 continue; 992 } 993 ComponentName enabledService = ComponentName.unflattenFromString(str); 994 if (enabledService != null) { 995 outComponentNames.add(enabledService); 996 } 997 } 998 } 999 } 1000 1001 /** 1002 * Persists the component names in the specified setting in a 1003 * colon separated fashion. 1004 * 1005 * @param settingName The setting name. 1006 * @param componentNames The component names. 1007 */ persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)1008 private void persistComponentNamesToSettingLocked(String settingName, 1009 Set<ComponentName> componentNames, int userId) { 1010 StringBuilder builder = new StringBuilder(); 1011 for (ComponentName componentName : componentNames) { 1012 if (builder.length() > 0) { 1013 builder.append(COMPONENT_NAME_SEPARATOR); 1014 } 1015 builder.append(componentName.flattenToShortString()); 1016 } 1017 Settings.Secure.putStringForUser(mContext.getContentResolver(), 1018 settingName, builder.toString(), userId); 1019 } 1020 1021 /** 1022 * Updates the state of each service by starting (or keeping running) enabled ones and 1023 * stopping the rest. 1024 * 1025 * @param userState The user state for which to do that. 1026 * @return The number of enabled installed services. 1027 */ updateServicesStateLocked(UserState userState)1028 private int updateServicesStateLocked(UserState userState) { 1029 Map<ComponentName, Service> componentNameToServiceMap = 1030 userState.mComponentNameToServiceMap; 1031 boolean isEnabled = userState.mIsAccessibilityEnabled; 1032 1033 int enabledInstalledServices = 0; 1034 for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) { 1035 AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i); 1036 ComponentName componentName = ComponentName.unflattenFromString( 1037 installedService.getId()); 1038 Service service = componentNameToServiceMap.get(componentName); 1039 1040 if (isEnabled) { 1041 if (userState.mEnabledServices.contains(componentName)) { 1042 if (service == null) { 1043 service = new Service(userState.mUserId, componentName, 1044 installedService, false); 1045 } 1046 service.bind(); 1047 enabledInstalledServices++; 1048 } else { 1049 if (service != null) { 1050 service.unbind(); 1051 } 1052 } 1053 } else { 1054 if (service != null) { 1055 service.unbind(); 1056 } 1057 } 1058 } 1059 1060 return enabledInstalledServices; 1061 } 1062 scheduleSendStateToClientsLocked(UserState userState)1063 private void scheduleSendStateToClientsLocked(UserState userState) { 1064 if (mGlobalClients.getRegisteredCallbackCount() > 0 1065 || userState.mClients.getRegisteredCallbackCount() > 0) { 1066 final int clientState = getClientState(userState); 1067 mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS, 1068 clientState, userState.mUserId) .sendToTarget(); 1069 } 1070 } 1071 updateInputFilterLocked(UserState userState)1072 private void updateInputFilterLocked(UserState userState) { 1073 boolean setInputFilter = false; 1074 AccessibilityInputFilter inputFilter = null; 1075 synchronized (mLock) { 1076 if ((userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) 1077 || userState.mIsDisplayMagnificationEnabled) { 1078 if (!mHasInputFilter) { 1079 mHasInputFilter = true; 1080 if (mInputFilter == null) { 1081 mInputFilter = new AccessibilityInputFilter(mContext, 1082 AccessibilityManagerService.this); 1083 } 1084 inputFilter = mInputFilter; 1085 setInputFilter = true; 1086 } 1087 int flags = 0; 1088 if (userState.mIsDisplayMagnificationEnabled) { 1089 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER; 1090 } 1091 if (userState.mIsTouchExplorationEnabled) { 1092 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION; 1093 } 1094 mInputFilter.setEnabledFeatures(flags); 1095 } else { 1096 if (mHasInputFilter) { 1097 mHasInputFilter = false; 1098 mInputFilter.setEnabledFeatures(0); 1099 inputFilter = null; 1100 setInputFilter = true; 1101 } 1102 } 1103 } 1104 if (setInputFilter) { 1105 try { 1106 mWindowManagerService.setInputFilter(inputFilter); 1107 } catch (RemoteException re) { 1108 /* ignore */ 1109 } 1110 } 1111 } 1112 showEnableTouchExplorationDialog(final Service service)1113 private void showEnableTouchExplorationDialog(final Service service) { 1114 String label = service.mResolveInfo.loadLabel( 1115 mContext.getPackageManager()).toString(); 1116 synchronized (mLock) { 1117 final UserState state = getCurrentUserStateLocked(); 1118 if (state.mIsTouchExplorationEnabled) { 1119 return; 1120 } 1121 if (mEnableTouchExplorationDialog != null 1122 && mEnableTouchExplorationDialog.isShowing()) { 1123 return; 1124 } 1125 mEnableTouchExplorationDialog = new AlertDialog.Builder(mContext) 1126 .setIcon(android.R.drawable.ic_dialog_alert) 1127 .setPositiveButton(android.R.string.ok, new OnClickListener() { 1128 @Override 1129 public void onClick(DialogInterface dialog, int which) { 1130 // The user allowed the service to toggle touch exploration. 1131 state.mTouchExplorationGrantedServices.add(service.mComponentName); 1132 persistComponentNamesToSettingLocked( 1133 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, 1134 state.mTouchExplorationGrantedServices, state.mUserId); 1135 // Enable touch exploration. 1136 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1137 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, 1138 service.mUserId); 1139 } 1140 }) 1141 .setNegativeButton(android.R.string.cancel, new OnClickListener() { 1142 @Override 1143 public void onClick(DialogInterface dialog, int which) { 1144 dialog.dismiss(); 1145 } 1146 }) 1147 .setTitle(R.string.enable_explore_by_touch_warning_title) 1148 .setMessage(mContext.getString( 1149 R.string.enable_explore_by_touch_warning_message, label)) 1150 .create(); 1151 mEnableTouchExplorationDialog.getWindow().setType( 1152 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1153 mEnableTouchExplorationDialog.getWindow().getAttributes().privateFlags 1154 |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 1155 mEnableTouchExplorationDialog.setCanceledOnTouchOutside(true); 1156 mEnableTouchExplorationDialog.show(); 1157 } 1158 } 1159 getClientState(UserState userState)1160 private int getClientState(UserState userState) { 1161 int clientState = 0; 1162 if (userState.mIsAccessibilityEnabled) { 1163 clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; 1164 } 1165 // Touch exploration relies on enabled accessibility. 1166 if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) { 1167 clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; 1168 } 1169 return clientState; 1170 } 1171 recreateInternalStateLocked(UserState userState)1172 private void recreateInternalStateLocked(UserState userState) { 1173 populateInstalledAccessibilityServiceLocked(userState); 1174 populateEnabledAccessibilityServicesLocked(userState); 1175 populateTouchExplorationGrantedAccessibilityServicesLocked(userState); 1176 1177 handleTouchExplorationEnabledSettingChangedLocked(userState); 1178 handleDisplayMagnificationEnabledSettingChangedLocked(userState); 1179 handleAccessibilityEnabledSettingChangedLocked(userState); 1180 1181 performServiceManagementLocked(userState); 1182 updateInputFilterLocked(userState); 1183 scheduleSendStateToClientsLocked(userState); 1184 } 1185 handleAccessibilityEnabledSettingChangedLocked(UserState userState)1186 private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) { 1187 userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser( 1188 mContext.getContentResolver(), 1189 Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1; 1190 } 1191 performServiceManagementLocked(UserState userState)1192 private void performServiceManagementLocked(UserState userState) { 1193 if (userState.mIsAccessibilityEnabled ) { 1194 manageServicesLocked(userState); 1195 } else { 1196 unbindAllServicesLocked(userState); 1197 } 1198 } 1199 handleTouchExplorationEnabledSettingChangedLocked(UserState userState)1200 private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) { 1201 userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser( 1202 mContext.getContentResolver(), 1203 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1; 1204 } 1205 handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState)1206 private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) { 1207 userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser( 1208 mContext.getContentResolver(), 1209 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 1210 0, userState.mUserId) == 1; 1211 } 1212 handleTouchExplorationGrantedAccessibilityServicesChangedLocked( UserState userState)1213 private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked( 1214 UserState userState) { 1215 final int serviceCount = userState.mServices.size(); 1216 for (int i = 0; i < serviceCount; i++) { 1217 Service service = userState.mServices.get(i); 1218 if (service.mRequestTouchExplorationMode 1219 && userState.mTouchExplorationGrantedServices.contains( 1220 service.mComponentName)) { 1221 tryEnableTouchExplorationLocked(service); 1222 return; 1223 } 1224 } 1225 if (userState.mIsTouchExplorationEnabled) { 1226 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1227 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId); 1228 } 1229 } 1230 tryEnableTouchExplorationLocked(final Service service)1231 private void tryEnableTouchExplorationLocked(final Service service) { 1232 UserState userState = getUserStateLocked(service.mUserId); 1233 if (!userState.mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode 1234 && service.canReceiveEvents()) { 1235 final boolean canToggleTouchExploration = 1236 userState.mTouchExplorationGrantedServices.contains(service.mComponentName); 1237 if (!service.mIsAutomation && !canToggleTouchExploration) { 1238 showEnableTouchExplorationDialog(service); 1239 } else { 1240 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1241 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, userState.mUserId); 1242 } 1243 } 1244 } 1245 tryDisableTouchExplorationLocked(Service service)1246 private void tryDisableTouchExplorationLocked(Service service) { 1247 UserState userState = getUserStateLocked(service.mUserId); 1248 if (userState.mIsTouchExplorationEnabled) { 1249 final int serviceCount = userState.mServices.size(); 1250 for (int i = 0; i < serviceCount; i++) { 1251 Service other = userState.mServices.get(i); 1252 if (other != service && other.mRequestTouchExplorationMode) { 1253 return; 1254 } 1255 } 1256 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1257 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId); 1258 } 1259 } 1260 1261 private class AccessibilityConnectionWrapper implements DeathRecipient { 1262 private final int mWindowId; 1263 private final int mUserId; 1264 private final IAccessibilityInteractionConnection mConnection; 1265 AccessibilityConnectionWrapper(int windowId, IAccessibilityInteractionConnection connection, int userId)1266 public AccessibilityConnectionWrapper(int windowId, 1267 IAccessibilityInteractionConnection connection, int userId) { 1268 mWindowId = windowId; 1269 mUserId = userId; 1270 mConnection = connection; 1271 } 1272 linkToDeath()1273 public void linkToDeath() throws RemoteException { 1274 mConnection.asBinder().linkToDeath(this, 0); 1275 } 1276 unlinkToDeath()1277 public void unlinkToDeath() { 1278 mConnection.asBinder().unlinkToDeath(this, 0); 1279 } 1280 1281 @Override binderDied()1282 public void binderDied() { 1283 unlinkToDeath(); 1284 synchronized (mLock) { 1285 removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId); 1286 } 1287 } 1288 } 1289 1290 private final class MainHandler extends Handler { 1291 public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1; 1292 public static final int MSG_SEND_STATE_TO_CLIENTS = 2; 1293 public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3; 1294 public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4; 1295 public static final int MSG_UPDATE_ACTIVE_WINDOW = 5; 1296 public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 6; 1297 MainHandler(Looper looper)1298 public MainHandler(Looper looper) { 1299 super(looper); 1300 } 1301 1302 @Override handleMessage(Message msg)1303 public void handleMessage(Message msg) { 1304 final int type = msg.what; 1305 switch (type) { 1306 case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: { 1307 AccessibilityEvent event = (AccessibilityEvent) msg.obj; 1308 synchronized (mLock) { 1309 if (mHasInputFilter && mInputFilter != null) { 1310 mInputFilter.notifyAccessibilityEvent(event); 1311 } 1312 } 1313 event.recycle(); 1314 } break; 1315 case MSG_SEND_STATE_TO_CLIENTS: { 1316 final int clientState = msg.arg1; 1317 final int userId = msg.arg2; 1318 sendStateToClients(clientState, mGlobalClients); 1319 sendStateToClientsForUser(clientState, userId); 1320 } break; 1321 case MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER: { 1322 final int userId = msg.arg1; 1323 sendStateToClientsForUser(0, userId); 1324 } break; 1325 case MSG_SEND_RECREATE_INTERNAL_STATE: { 1326 final int userId = msg.arg1; 1327 synchronized (mLock) { 1328 UserState userState = getUserStateLocked(userId); 1329 recreateInternalStateLocked(userState); 1330 } 1331 } break; 1332 case MSG_UPDATE_ACTIVE_WINDOW: { 1333 final int windowId = msg.arg1; 1334 final int eventType = msg.arg2; 1335 mSecurityPolicy.updateActiveWindow(windowId, eventType); 1336 } break; 1337 case MSG_ANNOUNCE_NEW_USER_IF_NEEDED: { 1338 announceNewUserIfNeeded(); 1339 } break; 1340 } 1341 } 1342 announceNewUserIfNeeded()1343 private void announceNewUserIfNeeded() { 1344 synchronized (mLock) { 1345 UserState userState = getCurrentUserStateLocked(); 1346 if (userState.mIsAccessibilityEnabled) { 1347 UserManager userManager = (UserManager) mContext.getSystemService( 1348 Context.USER_SERVICE); 1349 String message = mContext.getString(R.string.user_switched, 1350 userManager.getUserInfo(mCurrentUserId).name); 1351 AccessibilityEvent event = AccessibilityEvent.obtain( 1352 AccessibilityEvent.TYPE_ANNOUNCEMENT); 1353 event.getText().add(message); 1354 event.setWindowId(mSecurityPolicy.getRetrievalAllowingWindowLocked()); 1355 sendAccessibilityEvent(event, mCurrentUserId); 1356 } 1357 } 1358 } 1359 sendStateToClientsForUser(int clientState, int userId)1360 private void sendStateToClientsForUser(int clientState, int userId) { 1361 final UserState userState; 1362 synchronized (mLock) { 1363 userState = getUserStateLocked(userId); 1364 } 1365 sendStateToClients(clientState, userState.mClients); 1366 } 1367 sendStateToClients(int clientState, RemoteCallbackList<IAccessibilityManagerClient> clients)1368 private void sendStateToClients(int clientState, 1369 RemoteCallbackList<IAccessibilityManagerClient> clients) { 1370 try { 1371 final int userClientCount = clients.beginBroadcast(); 1372 for (int i = 0; i < userClientCount; i++) { 1373 IAccessibilityManagerClient client = clients.getBroadcastItem(i); 1374 try { 1375 client.setState(clientState); 1376 } catch (RemoteException re) { 1377 /* ignore */ 1378 } 1379 } 1380 } finally { 1381 clients.finishBroadcast(); 1382 } 1383 } 1384 } 1385 1386 /** 1387 * This class represents an accessibility service. It stores all per service 1388 * data required for the service management, provides API for starting/stopping the 1389 * service and is responsible for adding/removing the service in the data structures 1390 * for service management. The class also exposes configuration interface that is 1391 * passed to the service it represents as soon it is bound. It also serves as the 1392 * connection for the service. 1393 */ 1394 class Service extends IAccessibilityServiceConnection.Stub 1395 implements ServiceConnection, DeathRecipient { 1396 1397 // We pick the MSB to avoid collision since accessibility event types are 1398 // used as message types allowing us to remove messages per event type. 1399 private static final int MSG_ON_GESTURE = 0x80000000; 1400 1401 final int mUserId; 1402 1403 int mId = 0; 1404 1405 AccessibilityServiceInfo mAccessibilityServiceInfo; 1406 1407 IBinder mService; 1408 1409 IAccessibilityServiceClient mServiceInterface; 1410 1411 int mEventTypes; 1412 1413 int mFeedbackType; 1414 1415 Set<String> mPackageNames = new HashSet<String>(); 1416 1417 boolean mIsDefault; 1418 1419 boolean mRequestTouchExplorationMode; 1420 1421 boolean mIncludeNotImportantViews; 1422 1423 long mNotificationTimeout; 1424 1425 ComponentName mComponentName; 1426 1427 Intent mIntent; 1428 1429 boolean mCanRetrieveScreenContent; 1430 1431 boolean mIsAutomation; 1432 1433 final Rect mTempBounds = new Rect(); 1434 1435 final ResolveInfo mResolveInfo; 1436 1437 // the events pending events to be dispatched to this service 1438 final SparseArray<AccessibilityEvent> mPendingEvents = 1439 new SparseArray<AccessibilityEvent>(); 1440 1441 /** 1442 * Handler for delayed event dispatch. 1443 */ 1444 public Handler mHandler = new Handler(mMainHandler.getLooper()) { 1445 @Override 1446 public void handleMessage(Message message) { 1447 final int type = message.what; 1448 switch (type) { 1449 case MSG_ON_GESTURE: { 1450 final int gestureId = message.arg1; 1451 notifyGestureInternal(gestureId); 1452 } break; 1453 default: { 1454 final int eventType = type; 1455 notifyAccessibilityEventInternal(eventType); 1456 } break; 1457 } 1458 } 1459 }; 1460 Service(int userId, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation)1461 public Service(int userId, ComponentName componentName, 1462 AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) { 1463 mUserId = userId; 1464 mResolveInfo = accessibilityServiceInfo.getResolveInfo(); 1465 mId = sIdCounter++; 1466 mComponentName = componentName; 1467 mAccessibilityServiceInfo = accessibilityServiceInfo; 1468 mIsAutomation = isAutomation; 1469 if (!isAutomation) { 1470 mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent(); 1471 mRequestTouchExplorationMode = 1472 (accessibilityServiceInfo.flags 1473 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; 1474 mIntent = new Intent().setComponent(mComponentName); 1475 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, 1476 com.android.internal.R.string.accessibility_binding_label); 1477 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( 1478 mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0)); 1479 } else { 1480 mCanRetrieveScreenContent = true; 1481 } 1482 setDynamicallyConfigurableProperties(accessibilityServiceInfo); 1483 } 1484 setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)1485 public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { 1486 mEventTypes = info.eventTypes; 1487 mFeedbackType = info.feedbackType; 1488 String[] packageNames = info.packageNames; 1489 if (packageNames != null) { 1490 mPackageNames.addAll(Arrays.asList(packageNames)); 1491 } 1492 mNotificationTimeout = info.notificationTimeout; 1493 mIsDefault = (info.flags & DEFAULT) != 0; 1494 1495 if (mIsAutomation || info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 1496 >= Build.VERSION_CODES.JELLY_BEAN) { 1497 mIncludeNotImportantViews = 1498 (info.flags & FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0; 1499 } 1500 1501 mRequestTouchExplorationMode = (info.flags 1502 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; 1503 1504 // If this service is up and running we may have to enable touch 1505 // exploration, otherwise this will happen when the service connects. 1506 synchronized (mLock) { 1507 if (canReceiveEvents()) { 1508 if (mRequestTouchExplorationMode) { 1509 tryEnableTouchExplorationLocked(this); 1510 } else { 1511 tryDisableTouchExplorationLocked(this); 1512 } 1513 } 1514 } 1515 } 1516 1517 /** 1518 * Binds to the accessibility service. 1519 * 1520 * @return True if binding is successful. 1521 */ bind()1522 public boolean bind() { 1523 if (!mIsAutomation && mService == null) { 1524 return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE, mUserId); 1525 } 1526 return false; 1527 } 1528 1529 /** 1530 * Unbinds form the accessibility service and removes it from the data 1531 * structures for service management. 1532 * 1533 * @return True if unbinding is successful. 1534 */ unbind()1535 public boolean unbind() { 1536 if (mService != null) { 1537 synchronized (mLock) { 1538 tryRemoveServiceLocked(this); 1539 } 1540 if (!mIsAutomation) { 1541 mContext.unbindService(this); 1542 } 1543 return true; 1544 } 1545 return false; 1546 } 1547 canReceiveEvents()1548 public boolean canReceiveEvents() { 1549 return (mEventTypes != 0 && mFeedbackType != 0 && mService != null); 1550 } 1551 1552 @Override getServiceInfo()1553 public AccessibilityServiceInfo getServiceInfo() { 1554 synchronized (mLock) { 1555 return mAccessibilityServiceInfo; 1556 } 1557 } 1558 1559 @Override setServiceInfo(AccessibilityServiceInfo info)1560 public void setServiceInfo(AccessibilityServiceInfo info) { 1561 final long identity = Binder.clearCallingIdentity(); 1562 try { 1563 synchronized (mLock) { 1564 // If the XML manifest had data to configure the service its info 1565 // should be already set. In such a case update only the dynamically 1566 // configurable properties. 1567 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; 1568 if (oldInfo != null) { 1569 oldInfo.updateDynamicallyConfigurableProperties(info); 1570 setDynamicallyConfigurableProperties(oldInfo); 1571 } else { 1572 setDynamicallyConfigurableProperties(info); 1573 } 1574 } 1575 } finally { 1576 Binder.restoreCallingIdentity(identity); 1577 } 1578 } 1579 1580 @Override onServiceConnected(ComponentName componentName, IBinder service)1581 public void onServiceConnected(ComponentName componentName, IBinder service) { 1582 mService = service; 1583 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); 1584 try { 1585 mServiceInterface.setConnection(this, mId); 1586 synchronized (mLock) { 1587 tryAddServiceLocked(this, mUserId); 1588 } 1589 } catch (RemoteException re) { 1590 Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re); 1591 } 1592 } 1593 1594 @Override findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1595 public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, 1596 long accessibilityNodeId, int viewId, int interactionId, 1597 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1598 throws RemoteException { 1599 final int resolvedWindowId; 1600 IAccessibilityInteractionConnection connection = null; 1601 synchronized (mLock) { 1602 final int resolvedUserId = mSecurityPolicy 1603 .resolveCallingUserIdEnforcingPermissionsLocked( 1604 UserHandle.getCallingUserId()); 1605 if (resolvedUserId != mCurrentUserId) { 1606 return -1; 1607 } 1608 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1609 final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this); 1610 if (!permissionGranted) { 1611 return 0; 1612 } else { 1613 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 1614 connection = getConnectionLocked(resolvedWindowId); 1615 if (connection == null) { 1616 return 0; 1617 } 1618 } 1619 } 1620 final int flags = (mIncludeNotImportantViews) ? 1621 AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; 1622 final int interrogatingPid = Binder.getCallingPid(); 1623 final long identityToken = Binder.clearCallingIdentity(); 1624 try { 1625 connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId, 1626 interactionId, callback, flags, interrogatingPid, interrogatingTid); 1627 return getCompatibilityScale(resolvedWindowId); 1628 } catch (RemoteException re) { 1629 if (DEBUG) { 1630 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId()."); 1631 } 1632 } finally { 1633 Binder.restoreCallingIdentity(identityToken); 1634 } 1635 return 0; 1636 } 1637 1638 @Override findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1639 public float findAccessibilityNodeInfosByText(int accessibilityWindowId, 1640 long accessibilityNodeId, String text, int interactionId, 1641 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1642 throws RemoteException { 1643 final int resolvedWindowId; 1644 IAccessibilityInteractionConnection connection = null; 1645 synchronized (mLock) { 1646 final int resolvedUserId = mSecurityPolicy 1647 .resolveCallingUserIdEnforcingPermissionsLocked( 1648 UserHandle.getCallingUserId()); 1649 if (resolvedUserId != mCurrentUserId) { 1650 return -1; 1651 } 1652 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1653 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 1654 final boolean permissionGranted = 1655 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 1656 if (!permissionGranted) { 1657 return 0; 1658 } else { 1659 connection = getConnectionLocked(resolvedWindowId); 1660 if (connection == null) { 1661 return 0; 1662 } 1663 } 1664 } 1665 final int flags = (mIncludeNotImportantViews) ? 1666 AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; 1667 final int interrogatingPid = Binder.getCallingPid(); 1668 final long identityToken = Binder.clearCallingIdentity(); 1669 try { 1670 connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text, 1671 interactionId, callback, flags, interrogatingPid, 1672 interrogatingTid); 1673 return getCompatibilityScale(resolvedWindowId); 1674 } catch (RemoteException re) { 1675 if (DEBUG) { 1676 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()"); 1677 } 1678 } finally { 1679 Binder.restoreCallingIdentity(identityToken); 1680 } 1681 return 0; 1682 } 1683 1684 @Override findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid)1685 public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, 1686 long accessibilityNodeId, int interactionId, 1687 IAccessibilityInteractionConnectionCallback callback, int flags, 1688 long interrogatingTid) throws RemoteException { 1689 final int resolvedWindowId; 1690 IAccessibilityInteractionConnection connection = null; 1691 synchronized (mLock) { 1692 final int resolvedUserId = mSecurityPolicy 1693 .resolveCallingUserIdEnforcingPermissionsLocked( 1694 UserHandle.getCallingUserId()); 1695 if (resolvedUserId != mCurrentUserId) { 1696 return -1; 1697 } 1698 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1699 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 1700 final boolean permissionGranted = 1701 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 1702 if (!permissionGranted) { 1703 return 0; 1704 } else { 1705 connection = getConnectionLocked(resolvedWindowId); 1706 if (connection == null) { 1707 return 0; 1708 } 1709 } 1710 } 1711 final int allFlags = flags | ((mIncludeNotImportantViews) ? 1712 AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0); 1713 final int interrogatingPid = Binder.getCallingPid(); 1714 final long identityToken = Binder.clearCallingIdentity(); 1715 try { 1716 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId, 1717 interactionId, callback, allFlags, interrogatingPid, interrogatingTid); 1718 return getCompatibilityScale(resolvedWindowId); 1719 } catch (RemoteException re) { 1720 if (DEBUG) { 1721 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); 1722 } 1723 } finally { 1724 Binder.restoreCallingIdentity(identityToken); 1725 } 1726 return 0; 1727 } 1728 1729 @Override findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1730 public float findFocus(int accessibilityWindowId, long accessibilityNodeId, 1731 int focusType, int interactionId, 1732 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1733 throws RemoteException { 1734 final int resolvedWindowId; 1735 IAccessibilityInteractionConnection connection = null; 1736 synchronized (mLock) { 1737 final int resolvedUserId = mSecurityPolicy 1738 .resolveCallingUserIdEnforcingPermissionsLocked( 1739 UserHandle.getCallingUserId()); 1740 if (resolvedUserId != mCurrentUserId) { 1741 return -1; 1742 } 1743 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1744 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 1745 final boolean permissionGranted = 1746 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 1747 if (!permissionGranted) { 1748 return 0; 1749 } else { 1750 connection = getConnectionLocked(resolvedWindowId); 1751 if (connection == null) { 1752 return 0; 1753 } 1754 } 1755 } 1756 final int flags = (mIncludeNotImportantViews) ? 1757 AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; 1758 final int interrogatingPid = Binder.getCallingPid(); 1759 final long identityToken = Binder.clearCallingIdentity(); 1760 try { 1761 connection.findFocus(accessibilityNodeId, focusType, interactionId, callback, 1762 flags, interrogatingPid, interrogatingTid); 1763 return getCompatibilityScale(resolvedWindowId); 1764 } catch (RemoteException re) { 1765 if (DEBUG) { 1766 Slog.e(LOG_TAG, "Error calling findAccessibilityFocus()"); 1767 } 1768 } finally { 1769 Binder.restoreCallingIdentity(identityToken); 1770 } 1771 return 0; 1772 } 1773 1774 @Override focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1775 public float focusSearch(int accessibilityWindowId, long accessibilityNodeId, 1776 int direction, int interactionId, 1777 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1778 throws RemoteException { 1779 final int resolvedWindowId; 1780 IAccessibilityInteractionConnection connection = null; 1781 synchronized (mLock) { 1782 final int resolvedUserId = mSecurityPolicy 1783 .resolveCallingUserIdEnforcingPermissionsLocked( 1784 UserHandle.getCallingUserId()); 1785 if (resolvedUserId != mCurrentUserId) { 1786 return -1; 1787 } 1788 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1789 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 1790 final boolean permissionGranted = 1791 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 1792 if (!permissionGranted) { 1793 return 0; 1794 } else { 1795 connection = getConnectionLocked(resolvedWindowId); 1796 if (connection == null) { 1797 return 0; 1798 } 1799 } 1800 } 1801 final int flags = (mIncludeNotImportantViews) ? 1802 AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; 1803 final int interrogatingPid = Binder.getCallingPid(); 1804 final long identityToken = Binder.clearCallingIdentity(); 1805 try { 1806 connection.focusSearch(accessibilityNodeId, direction, interactionId, callback, 1807 flags, interrogatingPid, interrogatingTid); 1808 return getCompatibilityScale(resolvedWindowId); 1809 } catch (RemoteException re) { 1810 if (DEBUG) { 1811 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()"); 1812 } 1813 } finally { 1814 Binder.restoreCallingIdentity(identityToken); 1815 } 1816 return 0; 1817 } 1818 1819 @Override performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)1820 public boolean performAccessibilityAction(int accessibilityWindowId, 1821 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 1822 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1823 throws RemoteException { 1824 final int resolvedWindowId; 1825 IAccessibilityInteractionConnection connection = null; 1826 synchronized (mLock) { 1827 final int resolvedUserId = mSecurityPolicy 1828 .resolveCallingUserIdEnforcingPermissionsLocked( 1829 UserHandle.getCallingUserId()); 1830 if (resolvedUserId != mCurrentUserId) { 1831 return false; 1832 } 1833 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1834 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 1835 final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this, 1836 resolvedWindowId, action, arguments); 1837 if (!permissionGranted) { 1838 return false; 1839 } else { 1840 connection = getConnectionLocked(resolvedWindowId); 1841 if (connection == null) { 1842 return false; 1843 } 1844 } 1845 } 1846 final int flags = (mIncludeNotImportantViews) ? 1847 AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0; 1848 final int interrogatingPid = Binder.getCallingPid(); 1849 final long identityToken = Binder.clearCallingIdentity(); 1850 try { 1851 connection.performAccessibilityAction(accessibilityNodeId, action, arguments, 1852 interactionId, callback, flags, interrogatingPid, interrogatingTid); 1853 } catch (RemoteException re) { 1854 if (DEBUG) { 1855 Slog.e(LOG_TAG, "Error calling performAccessibilityAction()"); 1856 } 1857 } finally { 1858 Binder.restoreCallingIdentity(identityToken); 1859 } 1860 return true; 1861 } 1862 performGlobalAction(int action)1863 public boolean performGlobalAction(int action) { 1864 synchronized (mLock) { 1865 final int resolvedUserId = mSecurityPolicy 1866 .resolveCallingUserIdEnforcingPermissionsLocked( 1867 UserHandle.getCallingUserId()); 1868 if (resolvedUserId != mCurrentUserId) { 1869 return false; 1870 } 1871 } 1872 final long identity = Binder.clearCallingIdentity(); 1873 try { 1874 switch (action) { 1875 case AccessibilityService.GLOBAL_ACTION_BACK: { 1876 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); 1877 } return true; 1878 case AccessibilityService.GLOBAL_ACTION_HOME: { 1879 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); 1880 } return true; 1881 case AccessibilityService.GLOBAL_ACTION_RECENTS: { 1882 openRecents(); 1883 } return true; 1884 case AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS: { 1885 expandNotifications(); 1886 } return true; 1887 case AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS: { 1888 expandQuickSettings(); 1889 } return true; 1890 } 1891 return false; 1892 } finally { 1893 Binder.restoreCallingIdentity(identity); 1894 } 1895 } 1896 onServiceDisconnected(ComponentName componentName)1897 public void onServiceDisconnected(ComponentName componentName) { 1898 /* do nothing - #binderDied takes care */ 1899 } 1900 linkToOwnDeath()1901 public void linkToOwnDeath() throws RemoteException { 1902 mService.linkToDeath(this, 0); 1903 } 1904 unlinkToOwnDeath()1905 public void unlinkToOwnDeath() { 1906 mService.unlinkToDeath(this, 0); 1907 } 1908 dispose()1909 public void dispose() { 1910 try { 1911 // Clear the proxy in the other process so this 1912 // IAccessibilityServiceConnection can be garbage collected. 1913 mServiceInterface.setConnection(null, mId); 1914 } catch (RemoteException re) { 1915 /* ignore */ 1916 } 1917 mService = null; 1918 mServiceInterface = null; 1919 } 1920 binderDied()1921 public void binderDied() { 1922 synchronized (mLock) { 1923 // The death recipient is unregistered in tryRemoveServiceLocked 1924 tryRemoveServiceLocked(this); 1925 // We no longer have an automation service, so restore 1926 // the state based on values in the settings database. 1927 if (mIsAutomation) { 1928 mUiAutomationService = null; 1929 recreateInternalStateLocked(getUserStateLocked(mUserId)); 1930 } 1931 } 1932 } 1933 1934 /** 1935 * Performs a notification for an {@link AccessibilityEvent}. 1936 * 1937 * @param event The event. 1938 */ notifyAccessibilityEvent(AccessibilityEvent event)1939 public void notifyAccessibilityEvent(AccessibilityEvent event) { 1940 synchronized (mLock) { 1941 final int eventType = event.getEventType(); 1942 // Make a copy since during dispatch it is possible the event to 1943 // be modified to remove its source if the receiving service does 1944 // not have permission to access the window content. 1945 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event); 1946 AccessibilityEvent oldEvent = mPendingEvents.get(eventType); 1947 mPendingEvents.put(eventType, newEvent); 1948 1949 final int what = eventType; 1950 if (oldEvent != null) { 1951 mHandler.removeMessages(what); 1952 oldEvent.recycle(); 1953 } 1954 1955 Message message = mHandler.obtainMessage(what); 1956 mHandler.sendMessageDelayed(message, mNotificationTimeout); 1957 } 1958 } 1959 1960 /** 1961 * Notifies an accessibility service client for a scheduled event given the event type. 1962 * 1963 * @param eventType The type of the event to dispatch. 1964 */ notifyAccessibilityEventInternal(int eventType)1965 private void notifyAccessibilityEventInternal(int eventType) { 1966 IAccessibilityServiceClient listener; 1967 AccessibilityEvent event; 1968 1969 synchronized (mLock) { 1970 listener = mServiceInterface; 1971 1972 // If the service died/was disabled while the message for dispatching 1973 // the accessibility event was propagating the listener may be null. 1974 if (listener == null) { 1975 return; 1976 } 1977 1978 event = mPendingEvents.get(eventType); 1979 1980 // Check for null here because there is a concurrent scenario in which this 1981 // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked 1982 // which posts a message for dispatching an event. 2) The message is pulled 1983 // from the queue by the handler on the service thread and the latter is 1984 // just about to acquire the lock and call this method. 3) Now another binder 1985 // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked 1986 // so the service thread waits for the lock; 4) The binder thread replaces 1987 // the event with a more recent one (assume the same event type) and posts a 1988 // dispatch request releasing the lock. 5) Now the main thread is unblocked and 1989 // dispatches the event which is removed from the pending ones. 6) And ... now 1990 // the service thread handles the last message posted by the last binder call 1991 // but the event is already dispatched and hence looking it up in the pending 1992 // ones yields null. This check is much simpler that keeping count for each 1993 // event type of each service to catch such a scenario since only one message 1994 // is processed at a time. 1995 if (event == null) { 1996 return; 1997 } 1998 1999 mPendingEvents.remove(eventType); 2000 if (mSecurityPolicy.canRetrieveWindowContent(this)) { 2001 event.setConnectionId(mId); 2002 } else { 2003 event.setSource(null); 2004 } 2005 event.setSealed(true); 2006 } 2007 2008 try { 2009 listener.onAccessibilityEvent(event); 2010 if (DEBUG) { 2011 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); 2012 } 2013 } catch (RemoteException re) { 2014 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re); 2015 } finally { 2016 event.recycle(); 2017 } 2018 } 2019 notifyGesture(int gestureId)2020 public void notifyGesture(int gestureId) { 2021 mHandler.obtainMessage(MSG_ON_GESTURE, gestureId, 0).sendToTarget(); 2022 } 2023 notifyGestureInternal(int gestureId)2024 private void notifyGestureInternal(int gestureId) { 2025 IAccessibilityServiceClient listener = mServiceInterface; 2026 if (listener != null) { 2027 try { 2028 listener.onGesture(gestureId); 2029 } catch (RemoteException re) { 2030 Slog.e(LOG_TAG, "Error during sending gesture " + gestureId 2031 + " to " + mService, re); 2032 } 2033 } 2034 } 2035 sendDownAndUpKeyEvents(int keyCode)2036 private void sendDownAndUpKeyEvents(int keyCode) { 2037 final long token = Binder.clearCallingIdentity(); 2038 2039 // Inject down. 2040 final long downTime = SystemClock.uptimeMillis(); 2041 KeyEvent down = KeyEvent.obtain(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, 2042 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 2043 InputDevice.SOURCE_KEYBOARD, null); 2044 InputManager.getInstance().injectInputEvent(down, 2045 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 2046 down.recycle(); 2047 2048 // Inject up. 2049 final long upTime = SystemClock.uptimeMillis(); 2050 KeyEvent up = KeyEvent.obtain(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0, 0, 2051 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 2052 InputDevice.SOURCE_KEYBOARD, null); 2053 InputManager.getInstance().injectInputEvent(up, 2054 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 2055 up.recycle(); 2056 2057 Binder.restoreCallingIdentity(token); 2058 } 2059 expandNotifications()2060 private void expandNotifications() { 2061 final long token = Binder.clearCallingIdentity(); 2062 2063 StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( 2064 android.app.Service.STATUS_BAR_SERVICE); 2065 statusBarManager.expandNotificationsPanel(); 2066 2067 Binder.restoreCallingIdentity(token); 2068 } 2069 expandQuickSettings()2070 private void expandQuickSettings() { 2071 final long token = Binder.clearCallingIdentity(); 2072 2073 StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService( 2074 android.app.Service.STATUS_BAR_SERVICE); 2075 statusBarManager.expandSettingsPanel(); 2076 2077 Binder.restoreCallingIdentity(token); 2078 } 2079 openRecents()2080 private void openRecents() { 2081 final long token = Binder.clearCallingIdentity(); 2082 2083 IStatusBarService statusBarService = IStatusBarService.Stub.asInterface( 2084 ServiceManager.getService("statusbar")); 2085 try { 2086 statusBarService.toggleRecentApps(); 2087 } catch (RemoteException e) { 2088 Slog.e(LOG_TAG, "Error toggling recent apps."); 2089 } 2090 2091 Binder.restoreCallingIdentity(token); 2092 } 2093 getConnectionLocked(int windowId)2094 private IAccessibilityInteractionConnection getConnectionLocked(int windowId) { 2095 if (DEBUG) { 2096 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); 2097 } 2098 AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId); 2099 if (wrapper == null) { 2100 wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId); 2101 } 2102 if (wrapper != null && wrapper.mConnection != null) { 2103 return wrapper.mConnection; 2104 } 2105 if (DEBUG) { 2106 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId); 2107 } 2108 return null; 2109 } 2110 resolveAccessibilityWindowIdLocked(int accessibilityWindowId)2111 private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) { 2112 if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) { 2113 return mSecurityPolicy.mActiveWindowId; 2114 } 2115 return accessibilityWindowId; 2116 } 2117 getCompatibilityScale(int windowId)2118 private float getCompatibilityScale(int windowId) { 2119 try { 2120 IBinder windowToken = mGlobalWindowTokens.get(windowId); 2121 if (windowToken != null) { 2122 return mWindowManagerService.getWindowCompatibilityScale(windowToken); 2123 } 2124 windowToken = getCurrentUserStateLocked().mWindowTokens.get(windowId); 2125 if (windowToken != null) { 2126 return mWindowManagerService.getWindowCompatibilityScale(windowToken); 2127 } 2128 } catch (RemoteException re) { 2129 /* ignore */ 2130 } 2131 return 1.0f; 2132 } 2133 } 2134 2135 final class SecurityPolicy { 2136 private static final int VALID_ACTIONS = 2137 AccessibilityNodeInfo.ACTION_CLICK 2138 | AccessibilityNodeInfo.ACTION_LONG_CLICK 2139 | AccessibilityNodeInfo.ACTION_FOCUS 2140 | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS 2141 | AccessibilityNodeInfo.ACTION_SELECT 2142 | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION 2143 | AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS 2144 | AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS 2145 | AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 2146 | AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY 2147 | AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT 2148 | AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT 2149 | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 2150 | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD; 2151 2152 private static final int RETRIEVAL_ALLOWING_EVENT_TYPES = 2153 AccessibilityEvent.TYPE_VIEW_CLICKED 2154 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2155 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2156 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2157 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2158 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2159 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2160 | AccessibilityEvent.TYPE_VIEW_SELECTED 2161 | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 2162 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2163 | AccessibilityEvent.TYPE_VIEW_SCROLLED 2164 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2165 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED; 2166 2167 private int mActiveWindowId; 2168 private boolean mTouchInteractionInProgress; 2169 canDispatchAccessibilityEvent(AccessibilityEvent event)2170 private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) { 2171 final int eventType = event.getEventType(); 2172 switch (eventType) { 2173 // All events that are for changes in a global window 2174 // state should *always* be dispatched. 2175 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: 2176 case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED: 2177 // All events generated by the user touching the 2178 // screen should *always* be dispatched. 2179 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START: 2180 case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END: 2181 case AccessibilityEvent.TYPE_GESTURE_DETECTION_START: 2182 case AccessibilityEvent.TYPE_GESTURE_DETECTION_END: 2183 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START: 2184 case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END: 2185 // These will change the active window, so dispatch. 2186 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: 2187 case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT: { 2188 return true; 2189 } 2190 // All events for changes in window content should be 2191 // dispatched *only* if this window is the active one. 2192 default: 2193 return event.getWindowId() == mActiveWindowId; 2194 } 2195 } 2196 updateEventSourceLocked(AccessibilityEvent event)2197 public void updateEventSourceLocked(AccessibilityEvent event) { 2198 if ((event.getEventType() & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) { 2199 event.setSource(null); 2200 } 2201 } 2202 updateActiveWindow(int windowId, int eventType)2203 public void updateActiveWindow(int windowId, int eventType) { 2204 // The active window is either the window that has input focus or 2205 // the window that the user is currently touching. If the user is 2206 // touching a window that does not have input focus as soon as the 2207 // the user stops touching that window the focused window becomes 2208 // the active one. 2209 switch (eventType) { 2210 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: { 2211 if (getFocusedWindowId() == windowId) { 2212 mActiveWindowId = windowId; 2213 } 2214 } break; 2215 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: { 2216 // Do not allow delayed hover events to confuse us 2217 // which the active window is. 2218 if (mTouchInteractionInProgress) { 2219 mActiveWindowId = windowId; 2220 } 2221 } break; 2222 } 2223 } 2224 onTouchInteractionStart()2225 public void onTouchInteractionStart() { 2226 mTouchInteractionInProgress = true; 2227 } 2228 onTouchInteractionEnd()2229 public void onTouchInteractionEnd() { 2230 mTouchInteractionInProgress = false; 2231 // We want to set the active window to be current immediately 2232 // after the user has stopped touching the screen since if the 2233 // user types with the IME he should get a feedback for the 2234 // letter typed in the text view which is in the input focused 2235 // window. Note that we always deliver hover accessibility events 2236 // (they are a result of user touching the screen) so change of 2237 // the active window before all hover accessibility events from 2238 // the touched window are delivered is fine. 2239 mActiveWindowId = getFocusedWindowId(); 2240 } 2241 getRetrievalAllowingWindowLocked()2242 public int getRetrievalAllowingWindowLocked() { 2243 return mActiveWindowId; 2244 } 2245 canGetAccessibilityNodeInfoLocked(Service service, int windowId)2246 public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) { 2247 return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId); 2248 } 2249 canPerformActionLocked(Service service, int windowId, int action, Bundle arguments)2250 public boolean canPerformActionLocked(Service service, int windowId, int action, 2251 Bundle arguments) { 2252 return canRetrieveWindowContent(service) 2253 && isRetrievalAllowingWindow(windowId) 2254 && isActionPermitted(action); 2255 } 2256 canRetrieveWindowContent(Service service)2257 public boolean canRetrieveWindowContent(Service service) { 2258 return service.mCanRetrieveScreenContent; 2259 } 2260 enforceCanRetrieveWindowContent(Service service)2261 public void enforceCanRetrieveWindowContent(Service service) throws RemoteException { 2262 // This happens due to incorrect registration so make it apparent. 2263 if (!canRetrieveWindowContent(service)) { 2264 Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " + 2265 "declare android:canRetrieveWindowContent."); 2266 throw new RemoteException(); 2267 } 2268 } 2269 resolveCallingUserIdEnforcingPermissionsLocked(int userId)2270 public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) { 2271 final int callingUid = Binder.getCallingUid(); 2272 if (callingUid == Process.SYSTEM_UID 2273 || callingUid == Process.SHELL_UID) { 2274 return mCurrentUserId; 2275 } 2276 final int callingUserId = UserHandle.getUserId(callingUid); 2277 if (callingUserId == userId) { 2278 return userId; 2279 } 2280 if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) 2281 && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { 2282 throw new SecurityException("Call from user " + callingUserId + " as user " 2283 + userId + " without permission INTERACT_ACROSS_USERS or " 2284 + "INTERACT_ACROSS_USERS_FULL not allowed."); 2285 } 2286 if (userId == UserHandle.USER_CURRENT 2287 || userId == UserHandle.USER_CURRENT_OR_SELF) { 2288 return mCurrentUserId; 2289 } 2290 throw new IllegalArgumentException("Calling user can be changed to only " 2291 + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF."); 2292 } 2293 isCallerInteractingAcrossUsers(int userId)2294 public boolean isCallerInteractingAcrossUsers(int userId) { 2295 final int callingUid = Binder.getCallingUid(); 2296 return (Binder.getCallingPid() == android.os.Process.myPid() 2297 || callingUid == Process.SHELL_UID 2298 || userId == UserHandle.USER_CURRENT 2299 || userId == UserHandle.USER_CURRENT_OR_SELF); 2300 } 2301 isRetrievalAllowingWindow(int windowId)2302 private boolean isRetrievalAllowingWindow(int windowId) { 2303 return (mActiveWindowId == windowId); 2304 } 2305 isActionPermitted(int action)2306 private boolean isActionPermitted(int action) { 2307 return (VALID_ACTIONS & action) != 0; 2308 } 2309 enforceCallingPermission(String permission, String function)2310 private void enforceCallingPermission(String permission, String function) { 2311 if (OWN_PROCESS_ID == Binder.getCallingPid()) { 2312 return; 2313 } 2314 if (!hasPermission(permission)) { 2315 throw new SecurityException("You do not have " + permission 2316 + " required to call " + function); 2317 } 2318 } 2319 hasPermission(String permission)2320 private boolean hasPermission(String permission) { 2321 return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; 2322 } 2323 getFocusedWindowId()2324 private int getFocusedWindowId() { 2325 try { 2326 // We call this only on window focus change or after touch 2327 // exploration gesture end and the shown windows are not that 2328 // many, so the linear look up is just fine. 2329 IBinder token = mWindowManagerService.getFocusedWindowToken(); 2330 if (token != null) { 2331 synchronized (mLock) { 2332 int windowId = getFocusedWindowIdLocked(token, mGlobalWindowTokens); 2333 if (windowId < 0) { 2334 windowId = getFocusedWindowIdLocked(token, 2335 getCurrentUserStateLocked().mWindowTokens); 2336 } 2337 return windowId; 2338 } 2339 } 2340 } catch (RemoteException re) { 2341 /* ignore */ 2342 } 2343 return -1; 2344 } 2345 getFocusedWindowIdLocked(IBinder token, SparseArray<IBinder> windows)2346 private int getFocusedWindowIdLocked(IBinder token, SparseArray<IBinder> windows) { 2347 final int windowCount = windows.size(); 2348 for (int i = 0; i < windowCount; i++) { 2349 if (windows.valueAt(i) == token) { 2350 return windows.keyAt(i); 2351 } 2352 } 2353 return -1; 2354 } 2355 } 2356 2357 private class UserState { 2358 public final int mUserId; 2359 2360 public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>(); 2361 2362 public final RemoteCallbackList<IAccessibilityManagerClient> mClients = 2363 new RemoteCallbackList<IAccessibilityManagerClient>(); 2364 2365 public final Map<ComponentName, Service> mComponentNameToServiceMap = 2366 new HashMap<ComponentName, Service>(); 2367 2368 public final List<AccessibilityServiceInfo> mInstalledServices = 2369 new ArrayList<AccessibilityServiceInfo>(); 2370 2371 public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); 2372 2373 public final Set<ComponentName> mTouchExplorationGrantedServices = 2374 new HashSet<ComponentName>(); 2375 2376 public final SparseArray<AccessibilityConnectionWrapper> 2377 mInteractionConnections = 2378 new SparseArray<AccessibilityConnectionWrapper>(); 2379 2380 public final SparseArray<IBinder> mWindowTokens = new SparseArray<IBinder>(); 2381 2382 public int mHandledFeedbackTypes = 0; 2383 2384 public boolean mIsAccessibilityEnabled; 2385 public boolean mIsTouchExplorationEnabled; 2386 public boolean mIsDisplayMagnificationEnabled; 2387 UserState(int userId)2388 public UserState(int userId) { 2389 mUserId = userId; 2390 } 2391 } 2392 2393 private class TempUserStateChangeMemento { 2394 public int mUserId = UserHandle.USER_NULL; 2395 public boolean mIsAccessibilityEnabled; 2396 public boolean mIsTouchExplorationEnabled; 2397 public boolean mIsDisplayMagnificationEnabled; 2398 public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); 2399 public final Set<ComponentName> mTouchExplorationGrantedServices = 2400 new HashSet<ComponentName>(); 2401 initialize(int userId, UserState userState)2402 public void initialize(int userId, UserState userState) { 2403 mUserId = userId; 2404 mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled; 2405 mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled; 2406 mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled; 2407 mEnabledServices.clear(); 2408 mEnabledServices.addAll(userState.mEnabledServices); 2409 mTouchExplorationGrantedServices.clear(); 2410 mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices); 2411 } 2412 applyTo(UserState userState)2413 public void applyTo(UserState userState) { 2414 userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled; 2415 userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled; 2416 userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled; 2417 userState.mEnabledServices.clear(); 2418 userState.mEnabledServices.addAll(mEnabledServices); 2419 userState.mTouchExplorationGrantedServices.clear(); 2420 userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices); 2421 } 2422 clear()2423 public void clear() { 2424 mUserId = UserHandle.USER_NULL; 2425 mIsAccessibilityEnabled = false; 2426 mIsTouchExplorationEnabled = false; 2427 mIsDisplayMagnificationEnabled = false; 2428 mEnabledServices.clear(); 2429 mTouchExplorationGrantedServices.clear(); 2430 } 2431 } 2432 2433 private final class AccessibilityContentObserver extends ContentObserver { 2434 2435 private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor( 2436 Settings.Secure.ACCESSIBILITY_ENABLED); 2437 2438 private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor( 2439 Settings.Secure.TOUCH_EXPLORATION_ENABLED); 2440 2441 private final Uri mDisplayMagnificationEnabledUri = Settings.Secure.getUriFor( 2442 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED); 2443 2444 private final Uri mEnabledAccessibilityServicesUri = Settings.Secure.getUriFor( 2445 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 2446 2447 private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure 2448 .getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES); 2449 AccessibilityContentObserver(Handler handler)2450 public AccessibilityContentObserver(Handler handler) { 2451 super(handler); 2452 } 2453 register(ContentResolver contentResolver)2454 public void register(ContentResolver contentResolver) { 2455 contentResolver.registerContentObserver(mAccessibilityEnabledUri, 2456 false, this, UserHandle.USER_ALL); 2457 contentResolver.registerContentObserver(mTouchExplorationEnabledUri, 2458 false, this, UserHandle.USER_ALL); 2459 contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri, 2460 false, this, UserHandle.USER_ALL); 2461 contentResolver.registerContentObserver(mEnabledAccessibilityServicesUri, 2462 false, this, UserHandle.USER_ALL); 2463 contentResolver.registerContentObserver( 2464 mTouchExplorationGrantedAccessibilityServicesUri, 2465 false, this, UserHandle.USER_ALL); 2466 } 2467 2468 @Override onChange(boolean selfChange, Uri uri)2469 public void onChange(boolean selfChange, Uri uri) { 2470 if (mAccessibilityEnabledUri.equals(uri)) { 2471 synchronized (mLock) { 2472 // We will update when the automation service dies. 2473 if (mUiAutomationService == null) { 2474 UserState userState = getCurrentUserStateLocked(); 2475 handleAccessibilityEnabledSettingChangedLocked(userState); 2476 performServiceManagementLocked(userState); 2477 updateInputFilterLocked(userState); 2478 scheduleSendStateToClientsLocked(userState); 2479 } 2480 } 2481 } else if (mTouchExplorationEnabledUri.equals(uri)) { 2482 synchronized (mLock) { 2483 // We will update when the automation service dies. 2484 if (mUiAutomationService == null) { 2485 UserState userState = getCurrentUserStateLocked(); 2486 handleTouchExplorationEnabledSettingChangedLocked(userState); 2487 updateInputFilterLocked(userState); 2488 scheduleSendStateToClientsLocked(userState); 2489 } 2490 } 2491 } else if (mDisplayMagnificationEnabledUri.equals(uri)) { 2492 synchronized (mLock) { 2493 // We will update when the automation service dies. 2494 if (mUiAutomationService == null) { 2495 UserState userState = getCurrentUserStateLocked(); 2496 handleDisplayMagnificationEnabledSettingChangedLocked(userState); 2497 updateInputFilterLocked(userState); 2498 scheduleSendStateToClientsLocked(userState); 2499 } 2500 } 2501 } else if (mEnabledAccessibilityServicesUri.equals(uri)) { 2502 synchronized (mLock) { 2503 // We will update when the automation service dies. 2504 if (mUiAutomationService == null) { 2505 UserState userState = getCurrentUserStateLocked(); 2506 populateEnabledAccessibilityServicesLocked(userState); 2507 manageServicesLocked(userState); 2508 } 2509 } 2510 } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { 2511 synchronized (mLock) { 2512 // We will update when the automation service dies. 2513 if (mUiAutomationService == null) { 2514 UserState userState = getCurrentUserStateLocked(); 2515 populateTouchExplorationGrantedAccessibilityServicesLocked(userState); 2516 handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState); 2517 } 2518 } 2519 } 2520 } 2521 } 2522 } 2523