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