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