1 /* 2 ** Copyright 2017, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 package com.android.server.accessibility; 18 19 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_UNKNOWN; 20 import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS; 21 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 22 23 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 24 25 import android.Manifest; 26 import android.accessibilityservice.AccessibilityService; 27 import android.accessibilityservice.AccessibilityServiceInfo; 28 import android.accessibilityservice.AccessibilityTrace; 29 import android.accessibilityservice.BrailleDisplayController; 30 import android.accessibilityservice.IAccessibilityServiceClient; 31 import android.accessibilityservice.IBrailleDisplayController; 32 import android.accessibilityservice.TouchInteractionController; 33 import android.annotation.EnforcePermission; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.annotation.RequiresNoPermission; 37 import android.annotation.UserIdInt; 38 import android.app.PendingIntent; 39 import android.bluetooth.BluetoothAdapter; 40 import android.bluetooth.BluetoothDevice; 41 import android.bluetooth.BluetoothManager; 42 import android.content.ComponentName; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.pm.ParceledListSlice; 46 import android.hardware.usb.UsbDevice; 47 import android.hardware.usb.UsbManager; 48 import android.os.Binder; 49 import android.os.Bundle; 50 import android.os.Handler; 51 import android.os.IBinder; 52 import android.os.Message; 53 import android.os.Process; 54 import android.os.RemoteException; 55 import android.os.Trace; 56 import android.os.UserHandle; 57 import android.provider.Settings; 58 import android.text.TextUtils; 59 import android.util.Slog; 60 import android.view.Display; 61 import android.view.MotionEvent; 62 63 import com.android.internal.inputmethod.IAccessibilityInputMethodSession; 64 import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback; 65 import com.android.server.inputmethod.InputMethodManagerInternal; 66 import com.android.server.wm.ActivityTaskManagerInternal; 67 import com.android.server.wm.WindowManagerInternal; 68 69 import java.lang.ref.WeakReference; 70 import java.util.List; 71 import java.util.Objects; 72 import java.util.Set; 73 74 /** 75 * This class represents an accessibility service. It stores all per service 76 * data required for the service management, provides API for starting/stopping the 77 * service and is responsible for adding/removing the service in the data structures 78 * for service management. The class also exposes configuration interface that is 79 * passed to the service it represents as soon it is bound. It also serves as the 80 * connection for the service. 81 */ 82 class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection { 83 private static final String LOG_TAG = "AccessibilityServiceConnection"; 84 85 /* 86 Holding a weak reference so there isn't a loop of references. AccessibilityUserState keeps 87 lists of bound and binding services. These are freed on user changes, but just in case it 88 somehow gets lost the weak reference will let the memory get GCed. 89 90 Having the reference be null when being called is a very bad sign, but we check the condition. 91 */ 92 final WeakReference<AccessibilityUserState> mUserStateWeakReference; 93 @UserIdInt 94 final int mUserId; 95 final Intent mIntent; 96 final ActivityTaskManagerInternal mActivityTaskManagerService; 97 98 private BrailleDisplayConnection mBrailleDisplayConnection; 99 private List<Bundle> mTestBrailleDisplays = null; 100 101 private final Handler mMainHandler; 102 103 private static final class AccessibilityInputMethodSessionCallback 104 extends IAccessibilityInputMethodSessionCallback.Stub { 105 @UserIdInt 106 private final int mUserId; 107 AccessibilityInputMethodSessionCallback(@serIdInt int userId)108 AccessibilityInputMethodSessionCallback(@UserIdInt int userId) { 109 mUserId = userId; 110 } 111 112 @RequiresNoPermission 113 @Override sessionCreated(IAccessibilityInputMethodSession session, int id)114 public void sessionCreated(IAccessibilityInputMethodSession session, int id) { 115 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "ASC.sessionCreated"); 116 final long ident = Binder.clearCallingIdentity(); 117 try { 118 InputMethodManagerInternal.get() 119 .onSessionForAccessibilityCreated(id, session, mUserId); 120 } finally { 121 Binder.restoreCallingIdentity(ident); 122 } 123 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 124 } 125 } 126 AccessibilityServiceConnection(@ullable AccessibilityUserState userState, Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm, ActivityTaskManagerInternal activityTaskManagerService)127 AccessibilityServiceConnection(@Nullable AccessibilityUserState userState, 128 Context context, ComponentName componentName, 129 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, 130 Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, 131 AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, 132 SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm, 133 ActivityTaskManagerInternal activityTaskManagerService) { 134 super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock, 135 securityPolicy, systemSupport, trace, windowManagerInternal, systemActionPerfomer, 136 awm); 137 mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState); 138 // the user ID doesn't matter when userState is null, because it is null only when this is a 139 // ProxyAccessibilityServiceConnection, for which it never creates an IME session and uses 140 // the user ID. 141 mUserId = userState == null ? UserHandle.USER_NULL : userState.mUserId; 142 mIntent = new Intent().setComponent(mComponentName); 143 mMainHandler = mainHandler; 144 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, 145 com.android.internal.R.string.accessibility_binding_label); 146 mActivityTaskManagerService = activityTaskManagerService; 147 final long identity = Binder.clearCallingIdentity(); 148 try { 149 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, mSystemSupport.getPendingIntentActivity( 150 mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 151 PendingIntent.FLAG_IMMUTABLE)); 152 } finally { 153 Binder.restoreCallingIdentity(identity); 154 } 155 } 156 bindLocked()157 public void bindLocked() { 158 AccessibilityUserState userState = mUserStateWeakReference.get(); 159 if (userState == null) return; 160 final long identity = Binder.clearCallingIdentity(); 161 try { 162 int flags = Context.BIND_AUTO_CREATE 163 | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE 164 | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS 165 | Context.BIND_INCLUDE_CAPABILITIES; 166 if (userState.getBindInstantServiceAllowedLocked()) { 167 flags |= Context.BIND_ALLOW_INSTANT; 168 } 169 if (mService == null && mContext.bindServiceAsUser( 170 mIntent, this, flags, new UserHandle(userState.mUserId))) { 171 userState.getBindingServicesLocked().add(mComponentName); 172 } 173 } finally { 174 Binder.restoreCallingIdentity(identity); 175 } 176 mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), 177 mAccessibilityServiceInfo.getResolveInfo().serviceInfo.applicationInfo.uid, 178 userState.mUserId); 179 } 180 unbindLocked()181 public void unbindLocked() { 182 if (requestImeApis()) { 183 mSystemSupport.unbindImeLocked(this); 184 } 185 mContext.unbindService(this); 186 AccessibilityUserState userState = mUserStateWeakReference.get(); 187 if (userState == null) return; 188 userState.removeServiceLocked(this); 189 mSystemSupport.getMagnificationProcessor().resetAllIfNeeded(mId); 190 mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1, 191 userState.mUserId); 192 resetLocked(); 193 } 194 canRetrieveInteractiveWindowsLocked()195 public boolean canRetrieveInteractiveWindowsLocked() { 196 return mSecurityPolicy.canRetrieveWindowContentLocked(this) && mRetrieveInteractiveWindows; 197 } 198 199 @RequiresNoPermission 200 @Override disableSelf()201 public void disableSelf() { 202 if (svcConnTracingEnabled()) { 203 logTraceSvcConn("disableSelf", ""); 204 } 205 synchronized (mLock) { 206 AccessibilityUserState userState = mUserStateWeakReference.get(); 207 if (userState == null) return; 208 if (userState.getEnabledServicesLocked().remove(mComponentName)) { 209 final long identity = Binder.clearCallingIdentity(); 210 try { 211 mSystemSupport.persistComponentNamesToSettingLocked( 212 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 213 userState.getEnabledServicesLocked(), userState.mUserId); 214 215 mSystemSupport.onClientChangeLocked(false); 216 } finally { 217 Binder.restoreCallingIdentity(identity); 218 } 219 } 220 } 221 } 222 223 @Override onServiceConnected(ComponentName componentName, IBinder service)224 public void onServiceConnected(ComponentName componentName, IBinder service) { 225 AccessibilityUserState userState = mUserStateWeakReference.get(); 226 if (userState != null) { 227 addWindowTokensForAllDisplays(); 228 } 229 synchronized (mLock) { 230 if (mService != service) { 231 if (mService != null) { 232 mService.unlinkToDeath(this, 0); 233 } 234 mService = service; 235 try { 236 mService.linkToDeath(this, 0); 237 } catch (RemoteException re) { 238 Slog.e(LOG_TAG, "Failed registering death link"); 239 binderDied(); 240 return; 241 } 242 } 243 mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service); 244 if (userState == null) return; 245 userState.addServiceLocked(this); 246 mSystemSupport.onClientChangeLocked(false); 247 // Initialize the service on the main handler after we're done setting up for 248 // the new configuration (for example, initializing the input filter). 249 mMainHandler.sendMessage(obtainMessage( 250 AccessibilityServiceConnection::initializeService, this)); 251 if (requestImeApis()) { 252 mSystemSupport.requestImeLocked(this); 253 } 254 } 255 } 256 257 @RequiresNoPermission 258 @Override getServiceInfo()259 public AccessibilityServiceInfo getServiceInfo() { 260 return mAccessibilityServiceInfo; 261 } 262 initializeService()263 private void initializeService() { 264 IAccessibilityServiceClient serviceInterface = null; 265 synchronized (mLock) { 266 AccessibilityUserState userState = mUserStateWeakReference.get(); 267 if (userState == null) return; 268 final Set<ComponentName> bindingServices = userState.getBindingServicesLocked(); 269 final Set<ComponentName> crashedServices = userState.getCrashedServicesLocked(); 270 if (bindingServices.contains(mComponentName) 271 || crashedServices.contains(mComponentName)) { 272 bindingServices.remove(mComponentName); 273 crashedServices.remove(mComponentName); 274 mAccessibilityServiceInfo.crashed = false; 275 serviceInterface = mServiceInterface; 276 } 277 // There's a chance that service is removed from enabled_accessibility_services setting 278 // key, but skip unbinding because of it's in binding state. Unbinds it if it's 279 // not in enabled service list. 280 if (serviceInterface != null 281 && !userState.getEnabledServicesLocked().contains(mComponentName)) { 282 mSystemSupport.onClientChangeLocked(false); 283 return; 284 } 285 } 286 if (serviceInterface == null) { 287 binderDied(); 288 return; 289 } 290 try { 291 if (svcClientTracingEnabled()) { 292 logTraceSvcClient("init", 293 this + "," + mId + "," + mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 294 } 295 serviceInterface.init(this, mId, mOverlayWindowTokens.get(Display.DEFAULT_DISPLAY)); 296 } catch (RemoteException re) { 297 Slog.w(LOG_TAG, "Error while setting connection for service: " 298 + serviceInterface, re); 299 binderDied(); 300 } 301 } 302 303 @Override onServiceDisconnected(ComponentName componentName)304 public void onServiceDisconnected(ComponentName componentName) { 305 binderDied(); 306 AccessibilityUserState userState = mUserStateWeakReference.get(); 307 if (userState != null) { 308 mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1, 309 userState.mUserId); 310 } 311 } 312 313 @Override hasRightsToCurrentUserLocked()314 protected boolean hasRightsToCurrentUserLocked() { 315 // We treat calls from a profile as if made by its parent as profiles 316 // share the accessibility state of the parent. The call below 317 // performs the current profile parent resolution. 318 final int callingUid = Binder.getCallingUid(); 319 if (callingUid == Process.ROOT_UID 320 || callingUid == Process.SYSTEM_UID 321 || callingUid == Process.SHELL_UID) { 322 return true; 323 } 324 if (mSecurityPolicy.resolveProfileParentLocked(UserHandle.getUserId(callingUid)) 325 == mSystemSupport.getCurrentUserIdLocked()) { 326 return true; 327 } 328 if (mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) 329 || mSecurityPolicy.hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { 330 return true; 331 } 332 return false; 333 } 334 335 @RequiresNoPermission 336 @Override setSoftKeyboardShowMode(int showMode)337 public boolean setSoftKeyboardShowMode(int showMode) { 338 if (svcConnTracingEnabled()) { 339 logTraceSvcConn("setSoftKeyboardShowMode", "showMode=" + showMode); 340 } 341 synchronized (mLock) { 342 if (!hasRightsToCurrentUserLocked()) { 343 return false; 344 } 345 final AccessibilityUserState userState = mUserStateWeakReference.get(); 346 if (userState == null) return false; 347 348 final long identity = Binder.clearCallingIdentity(); 349 try { 350 return userState.setSoftKeyboardModeLocked(showMode, mComponentName); 351 } finally { 352 Binder.restoreCallingIdentity(identity); 353 } 354 } 355 } 356 357 @RequiresNoPermission 358 @Override getSoftKeyboardShowMode()359 public int getSoftKeyboardShowMode() { 360 if (svcConnTracingEnabled()) { 361 logTraceSvcConn("getSoftKeyboardShowMode", ""); 362 } 363 final AccessibilityUserState userState = mUserStateWeakReference.get(); 364 final long identity = Binder.clearCallingIdentity(); 365 try { 366 return (userState != null) ? userState.getSoftKeyboardShowModeLocked() : 0; 367 } finally { 368 Binder.restoreCallingIdentity(identity); 369 } 370 } 371 372 @RequiresNoPermission 373 @Override switchToInputMethod(String imeId)374 public boolean switchToInputMethod(String imeId) { 375 if (svcConnTracingEnabled()) { 376 logTraceSvcConn("switchToInputMethod", "imeId=" + imeId); 377 } 378 synchronized (mLock) { 379 if (!hasRightsToCurrentUserLocked()) { 380 return false; 381 } 382 } 383 final boolean result; 384 final int callingUserId = UserHandle.getCallingUserId(); 385 final long identity = Binder.clearCallingIdentity(); 386 try { 387 result = InputMethodManagerInternal.get().switchToInputMethod(imeId, callingUserId); 388 } finally { 389 Binder.restoreCallingIdentity(identity); 390 } 391 return result; 392 } 393 394 @RequiresNoPermission 395 @Override 396 @AccessibilityService.SoftKeyboardController.EnableImeResult setInputMethodEnabled(String imeId, boolean enabled)397 public int setInputMethodEnabled(String imeId, boolean enabled) throws SecurityException { 398 if (svcConnTracingEnabled()) { 399 logTraceSvcConn("switchToInputMethod", "imeId=" + imeId); 400 } 401 synchronized (mLock) { 402 if (!hasRightsToCurrentUserLocked()) { 403 return ENABLE_IME_FAIL_UNKNOWN; 404 } 405 } 406 407 final int callingUserId = UserHandle.getCallingUserId(); 408 final InputMethodManagerInternal inputMethodManagerInternal = 409 InputMethodManagerInternal.get(); 410 411 final @AccessibilityService.SoftKeyboardController.EnableImeResult int checkResult; 412 final long identity = Binder.clearCallingIdentity(); 413 try { 414 synchronized (mLock) { 415 checkResult = mSecurityPolicy.canEnableDisableInputMethod(imeId, this); 416 } 417 if (checkResult != ENABLE_IME_SUCCESS) { 418 return checkResult; 419 } 420 if (inputMethodManagerInternal.setInputMethodEnabled(imeId, 421 enabled, callingUserId)) { 422 return ENABLE_IME_SUCCESS; 423 } 424 } finally { 425 Binder.restoreCallingIdentity(identity); 426 } 427 return ENABLE_IME_FAIL_UNKNOWN; 428 } 429 430 @RequiresNoPermission 431 @Override isAccessibilityButtonAvailable()432 public boolean isAccessibilityButtonAvailable() { 433 if (svcConnTracingEnabled()) { 434 logTraceSvcConn("isAccessibilityButtonAvailable", ""); 435 } 436 synchronized (mLock) { 437 if (!hasRightsToCurrentUserLocked()) { 438 return false; 439 } 440 441 final long identity = Binder.clearCallingIdentity(); 442 try { 443 AccessibilityUserState userState = mUserStateWeakReference.get(); 444 return (userState != null) && isAccessibilityButtonAvailableLocked(userState); 445 } finally { 446 Binder.restoreCallingIdentity(identity); 447 } 448 } 449 } 450 451 @Override binderDied()452 public void binderDied() { 453 synchronized (mLock) { 454 // It is possible that this service's package was force stopped during 455 // whose handling the death recipient is unlinked and still get a call 456 // on binderDied since the call was made before we unlink but was 457 // waiting on the lock we held during the force stop handling. 458 if (!isConnectedLocked()) { 459 return; 460 } 461 if (requestImeApis()) { 462 mSystemSupport.unbindImeLocked(this); 463 } 464 mAccessibilityServiceInfo.crashed = true; 465 AccessibilityUserState userState = mUserStateWeakReference.get(); 466 if (userState != null) { 467 userState.serviceDisconnectedLocked(this); 468 } 469 resetLocked(); 470 mSystemSupport.getMagnificationProcessor().resetAllIfNeeded(mId); 471 mSystemSupport.onClientChangeLocked(false); 472 } 473 } 474 475 @Override resetLocked()476 public void resetLocked() { 477 super.resetLocked(); 478 if (android.view.accessibility.Flags.brailleDisplayHid()) { 479 if (mBrailleDisplayConnection != null) { 480 mBrailleDisplayConnection.disconnect(); 481 } 482 } 483 } 484 isAccessibilityButtonAvailableLocked(AccessibilityUserState userState)485 public boolean isAccessibilityButtonAvailableLocked(AccessibilityUserState userState) { 486 // If the service does not request the accessibility button, it isn't available 487 if (!mRequestAccessibilityButton) { 488 return false; 489 } 490 // If the accessibility button isn't currently shown, it cannot be available to services 491 if (!mSystemSupport.isAccessibilityButtonShown()) { 492 return false; 493 } 494 return true; 495 } 496 497 @Override isCapturingFingerprintGestures()498 public boolean isCapturingFingerprintGestures() { 499 return (mServiceInterface != null) 500 && mSecurityPolicy.canCaptureFingerprintGestures(this) 501 && mCaptureFingerprintGestures; 502 } 503 504 @Override onFingerprintGestureDetectionActiveChanged(boolean active)505 public void onFingerprintGestureDetectionActiveChanged(boolean active) { 506 if (!isCapturingFingerprintGestures()) { 507 return; 508 } 509 IAccessibilityServiceClient serviceInterface; 510 synchronized (mLock) { 511 serviceInterface = mServiceInterface; 512 } 513 if (serviceInterface != null) { 514 try { 515 if (svcClientTracingEnabled()) { 516 logTraceSvcClient( 517 "onFingerprintCapturingGesturesChanged", String.valueOf(active)); 518 } 519 mServiceInterface.onFingerprintCapturingGesturesChanged(active); 520 } catch (RemoteException e) { 521 } 522 } 523 } 524 525 @Override onFingerprintGesture(int gesture)526 public void onFingerprintGesture(int gesture) { 527 if (!isCapturingFingerprintGestures()) { 528 return; 529 } 530 IAccessibilityServiceClient serviceInterface; 531 synchronized (mLock) { 532 serviceInterface = mServiceInterface; 533 } 534 if (serviceInterface != null) { 535 try { 536 if (svcClientTracingEnabled()) { 537 logTraceSvcClient("onFingerprintGesture", String.valueOf(gesture)); 538 } 539 mServiceInterface.onFingerprintGesture(gesture); 540 } catch (RemoteException e) { 541 } 542 } 543 } 544 545 @RequiresNoPermission 546 @Override dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)547 public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) { 548 synchronized (mLock) { 549 if (mServiceInterface != null && mSecurityPolicy.canPerformGestures(this)) { 550 final long identity = Binder.clearCallingIdentity(); 551 try { 552 MotionEventInjector motionEventInjector = 553 mSystemSupport.getMotionEventInjectorForDisplayLocked(displayId); 554 if (wmTracingEnabled()) { 555 logTraceWM("isTouchOrFaketouchDevice", ""); 556 } 557 if (motionEventInjector != null 558 && mWindowManagerService.isTouchOrFaketouchDevice()) { 559 motionEventInjector.injectEvents( 560 gestureSteps.getList(), mServiceInterface, sequence, displayId); 561 } else { 562 try { 563 if (svcClientTracingEnabled()) { 564 logTraceSvcClient("onPerformGestureResult", sequence + ", false"); 565 } 566 mServiceInterface.onPerformGestureResult(sequence, false); 567 } catch (RemoteException re) { 568 Slog.e(LOG_TAG, "Error sending motion event injection failure to " 569 + mServiceInterface, re); 570 } 571 } 572 } finally { 573 Binder.restoreCallingIdentity(identity); 574 } 575 576 } 577 } 578 } 579 580 @RequiresNoPermission 581 @Override setFocusAppearance(int strokeWidth, int color)582 public void setFocusAppearance(int strokeWidth, int color) { 583 AccessibilityUserState userState = mUserStateWeakReference.get(); 584 if (userState == null) { 585 return; 586 } 587 588 synchronized (mLock) { 589 if (!hasRightsToCurrentUserLocked()) { 590 return; 591 } 592 593 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 594 return; 595 } 596 597 if (userState.getFocusStrokeWidthLocked() == strokeWidth 598 && userState.getFocusColorLocked() == color) { 599 return; 600 } 601 602 final long identity = Binder.clearCallingIdentity(); 603 try { 604 // Sets the appearance data in the A11yUserState. 605 userState.setFocusAppearanceLocked(strokeWidth, color); 606 // Updates the appearance data in the A11yManager. 607 mSystemSupport.onClientChangeLocked(false); 608 } finally { 609 Binder.restoreCallingIdentity(identity); 610 } 611 } 612 } 613 notifyMotionEvent(MotionEvent event)614 public void notifyMotionEvent(MotionEvent event) { 615 final Message msg = obtainMessage( 616 AccessibilityServiceConnection::notifyMotionEventInternal, 617 AccessibilityServiceConnection.this, event); 618 mMainHandler.sendMessage(msg); 619 } 620 notifyTouchState(int displayId, int state)621 public void notifyTouchState(int displayId, int state) { 622 final Message msg = obtainMessage( 623 AccessibilityServiceConnection::notifyTouchStateInternal, 624 AccessibilityServiceConnection.this, displayId, state); 625 mMainHandler.sendMessage(msg); 626 } 627 requestImeApis()628 public boolean requestImeApis() { 629 return mRequestImeApis; 630 } 631 632 @Override createImeSessionInternal()633 protected void createImeSessionInternal() { 634 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 635 if (listener != null) { 636 try { 637 if (svcClientTracingEnabled()) { 638 logTraceSvcClient("createImeSession", ""); 639 } 640 AccessibilityInputMethodSessionCallback 641 callback = new AccessibilityInputMethodSessionCallback(mUserId); 642 listener.createImeSession(callback); 643 } catch (RemoteException re) { 644 Slog.e(LOG_TAG, 645 "Error requesting IME session from " + mService, re); 646 } 647 } 648 } 649 notifyMotionEventInternal(MotionEvent event)650 private void notifyMotionEventInternal(MotionEvent event) { 651 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 652 if (listener != null) { 653 try { 654 if (mTrace.isA11yTracingEnabled()) { 655 logTraceSvcClient(".onMotionEvent ", 656 event.toString()); 657 } 658 listener.onMotionEvent(event); 659 } catch (RemoteException re) { 660 Slog.e(LOG_TAG, "Error sending motion event to" + mService, re); 661 } 662 } 663 } 664 notifyTouchStateInternal(int displayId, int state)665 private void notifyTouchStateInternal(int displayId, int state) { 666 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 667 if (listener != null) { 668 try { 669 if (mTrace.isA11yTracingEnabled()) { 670 logTraceSvcClient(".onTouchStateChanged ", 671 TouchInteractionController.stateToString(state)); 672 } 673 listener.onTouchStateChanged(displayId, state); 674 } catch (RemoteException re) { 675 Slog.e(LOG_TAG, "Error sending motion event to" + mService, re); 676 } 677 } 678 } 679 checkAccessibilityAccessLocked()680 private void checkAccessibilityAccessLocked() { 681 if (!hasRightsToCurrentUserLocked() 682 || !mSecurityPolicy.checkAccessibilityAccess(this)) { 683 throw new SecurityException("Caller does not have accessibility access"); 684 } 685 } 686 687 /** 688 * Sets up a BrailleDisplayConnection interface for the requested Bluetooth-connected 689 * Braille display. 690 * 691 * @param bluetoothAddress The address from 692 * {@link android.bluetooth.BluetoothDevice#getAddress()}. 693 */ 694 @Override 695 @EnforcePermission(Manifest.permission.BLUETOOTH_CONNECT) connectBluetoothBrailleDisplay( @onNull String bluetoothAddress, @NonNull IBrailleDisplayController controller)696 public void connectBluetoothBrailleDisplay( 697 @NonNull String bluetoothAddress, @NonNull IBrailleDisplayController controller) { 698 connectBluetoothBrailleDisplay_enforcePermission(); 699 if (!android.view.accessibility.Flags.brailleDisplayHid()) { 700 throw new IllegalStateException("Flag BRAILLE_DISPLAY_HID not enabled"); 701 } 702 Objects.requireNonNull(bluetoothAddress); 703 Objects.requireNonNull(controller); 704 if (!BluetoothAdapter.checkBluetoothAddress(bluetoothAddress)) { 705 throw new IllegalArgumentException( 706 bluetoothAddress + " is not a valid Bluetooth address"); 707 } 708 final BluetoothManager bluetoothManager = 709 mContext.getSystemService(BluetoothManager.class); 710 final String bluetoothDeviceName = bluetoothManager == null ? null : 711 bluetoothManager.getAdapter().getBondedDevices().stream() 712 .filter(device -> device.getAddress().equalsIgnoreCase(bluetoothAddress)) 713 .map(BluetoothDevice::getName) 714 .findFirst().orElse(null); 715 synchronized (mLock) { 716 checkAccessibilityAccessLocked(); 717 if (mBrailleDisplayConnection != null) { 718 throw new IllegalStateException( 719 "This service already has a connected Braille display"); 720 } 721 BrailleDisplayConnection connection = new BrailleDisplayConnection(mLock, this); 722 if (mTestBrailleDisplays != null) { 723 connection.setTestData(mTestBrailleDisplays); 724 } 725 connection.connectLocked( 726 bluetoothAddress, 727 bluetoothDeviceName, 728 BrailleDisplayConnection.BUS_BLUETOOTH, 729 controller); 730 } 731 } 732 733 /** 734 * Sets up a BrailleDisplayConnection interface for the requested USB-connected 735 * Braille display. 736 * 737 * <p>The caller package must already have USB permission for this {@link UsbDevice}. 738 */ 739 @RequiresNoPermission 740 @Override 741 @NonNull connectUsbBrailleDisplay(@onNull UsbDevice usbDevice, @NonNull IBrailleDisplayController controller)742 public void connectUsbBrailleDisplay(@NonNull UsbDevice usbDevice, 743 @NonNull IBrailleDisplayController controller) { 744 if (!android.view.accessibility.Flags.brailleDisplayHid()) { 745 throw new IllegalStateException("Flag BRAILLE_DISPLAY_HID not enabled"); 746 } 747 Objects.requireNonNull(usbDevice); 748 Objects.requireNonNull(controller); 749 final UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); 750 final String usbSerialNumber; 751 final int uid = Binder.getCallingUid(); 752 final int pid = Binder.getCallingPid(); 753 final long identity = Binder.clearCallingIdentity(); 754 try { 755 if (usbManager == null || !usbManager.hasPermission( 756 usbDevice, mComponentName.getPackageName(), /*pid=*/ pid, /*uid=*/ uid)) { 757 throw new SecurityException( 758 "Caller does not have permission to access this UsbDevice"); 759 } 760 usbSerialNumber = usbDevice.getSerialNumber(); 761 if (TextUtils.isEmpty(usbSerialNumber)) { 762 // If the UsbDevice does not report a serial number for locating the HIDRAW 763 // node then notify connection error ERROR_BRAILLE_DISPLAY_NOT_FOUND. 764 try { 765 controller.onConnectionFailed(BrailleDisplayController.BrailleDisplayCallback 766 .FLAG_ERROR_BRAILLE_DISPLAY_NOT_FOUND); 767 } catch (RemoteException e) { 768 Slog.e(LOG_TAG, "Error calling onConnectionFailed", e); 769 } 770 return; 771 } 772 } finally { 773 Binder.restoreCallingIdentity(identity); 774 } 775 synchronized (mLock) { 776 checkAccessibilityAccessLocked(); 777 if (mBrailleDisplayConnection != null) { 778 throw new IllegalStateException( 779 "This service already has a connected Braille display"); 780 } 781 BrailleDisplayConnection connection = new BrailleDisplayConnection(mLock, this); 782 if (mTestBrailleDisplays != null) { 783 connection.setTestData(mTestBrailleDisplays); 784 } 785 connection.connectLocked( 786 usbSerialNumber, 787 usbDevice.getProductName(), 788 BrailleDisplayConnection.BUS_USB, 789 controller); 790 } 791 } 792 793 @Override 794 @EnforcePermission(Manifest.permission.MANAGE_ACCESSIBILITY) setTestBrailleDisplayData(List<Bundle> brailleDisplays)795 public void setTestBrailleDisplayData(List<Bundle> brailleDisplays) { 796 setTestBrailleDisplayData_enforcePermission(); 797 // Enforce that this TestApi is only called by trusted (test) callers. 798 mTestBrailleDisplays = brailleDisplays; 799 } 800 onBrailleDisplayConnectedLocked(BrailleDisplayConnection connection)801 void onBrailleDisplayConnectedLocked(BrailleDisplayConnection connection) { 802 mBrailleDisplayConnection = connection; 803 } 804 805 // Reset state when the BrailleDisplayConnection object disconnects itself. onBrailleDisplayDisconnectedLocked()806 void onBrailleDisplayDisconnectedLocked() { 807 mBrailleDisplayConnection = null; 808 } 809 } 810