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.AccessibilityServiceInfo.DEFAULT; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; 22 23 import android.accessibilityservice.AccessibilityServiceInfo; 24 import android.accessibilityservice.IAccessibilityServiceClient; 25 import android.accessibilityservice.IAccessibilityServiceConnection; 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.app.PendingIntent; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.ServiceConnection; 33 import android.content.pm.PackageManager; 34 import android.content.pm.ParceledListSlice; 35 import android.graphics.Region; 36 import android.os.Binder; 37 import android.os.Build; 38 import android.os.Bundle; 39 import android.os.Handler; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.Message; 43 import android.os.RemoteException; 44 import android.util.Slog; 45 import android.util.SparseArray; 46 import android.view.KeyEvent; 47 import android.view.MagnificationSpec; 48 import android.view.View; 49 import android.view.accessibility.AccessibilityCache; 50 import android.view.accessibility.AccessibilityEvent; 51 import android.view.accessibility.AccessibilityNodeInfo; 52 import android.view.accessibility.AccessibilityWindowInfo; 53 import android.view.accessibility.IAccessibilityInteractionConnection; 54 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 55 56 import com.android.internal.annotations.GuardedBy; 57 import com.android.internal.os.SomeArgs; 58 import com.android.internal.util.DumpUtils; 59 import com.android.server.accessibility.AccessibilityManagerService.RemoteAccessibilityConnection; 60 import com.android.server.accessibility.AccessibilityManagerService.SecurityPolicy; 61 import com.android.server.wm.WindowManagerInternal; 62 63 import java.io.FileDescriptor; 64 import java.io.PrintWriter; 65 import java.util.ArrayList; 66 import java.util.Arrays; 67 import java.util.HashSet; 68 import java.util.List; 69 import java.util.Set; 70 71 /** 72 * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. 73 * It is responsible for behavior common to both types of clients. 74 */ 75 abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub 76 implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter, 77 FingerprintGestureDispatcher.FingerprintGestureClient { 78 private static final boolean DEBUG = false; 79 private static final String LOG_TAG = "AbstractAccessibilityServiceConnection"; 80 81 protected final Context mContext; 82 protected final SystemSupport mSystemSupport; 83 private final WindowManagerInternal mWindowManagerService; 84 private final GlobalActionPerformer mGlobalActionPerformer; 85 86 // Handler for scheduling method invocations on the main thread. 87 public final InvocationHandler mInvocationHandler; 88 89 final int mId; 90 91 protected final AccessibilityServiceInfo mAccessibilityServiceInfo; 92 93 // Lock must match the one used by AccessibilityManagerService 94 protected final Object mLock; 95 96 protected final SecurityPolicy mSecurityPolicy; 97 98 // The service that's bound to this instance. Whenever this value is non-null, this 99 // object is registered as a death recipient 100 IBinder mService; 101 102 IAccessibilityServiceClient mServiceInterface; 103 104 int mEventTypes; 105 106 int mFeedbackType; 107 108 Set<String> mPackageNames = new HashSet<>(); 109 110 boolean mIsDefault; 111 112 boolean mRequestTouchExplorationMode; 113 114 boolean mRequestFilterKeyEvents; 115 116 boolean mRetrieveInteractiveWindows; 117 118 boolean mCaptureFingerprintGestures; 119 120 boolean mRequestAccessibilityButton; 121 122 boolean mReceivedAccessibilityButtonCallbackSinceBind; 123 124 boolean mLastAccessibilityButtonCallbackState; 125 126 int mFetchFlags; 127 128 long mNotificationTimeout; 129 130 final ComponentName mComponentName; 131 132 // the events pending events to be dispatched to this service 133 final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>(); 134 135 /** Whether this service relies on its {@link AccessibilityCache} being up to date */ 136 boolean mUsesAccessibilityCache = false; 137 138 // Handler only for dispatching accessibility events since we use event 139 // types as message types allowing us to remove messages per event type. 140 public Handler mEventDispatchHandler; 141 142 final IBinder mOverlayWindowToken = new Binder(); 143 144 145 public interface SystemSupport { 146 /** 147 * @return The current dispatcher for key events 148 */ getKeyEventDispatcher()149 @NonNull KeyEventDispatcher getKeyEventDispatcher(); 150 151 /** 152 * @param windowId The id of the window of interest 153 * @return The magnification spec for the window, or {@code null} if none is available 154 */ getCompatibleMagnificationSpecLocked(int windowId)155 @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId); 156 157 /** 158 * @return The current injector of motion events, if one exists 159 */ getMotionEventInjectorLocked()160 @Nullable MotionEventInjector getMotionEventInjectorLocked(); 161 162 /** 163 * @return The current dispatcher for fingerprint gestures, if one exists 164 */ getFingerprintGestureDispatcher()165 @Nullable FingerprintGestureDispatcher getFingerprintGestureDispatcher(); 166 167 /** 168 * @return The magnification controller 169 */ getMagnificationController()170 @NonNull MagnificationController getMagnificationController(); 171 172 /** 173 * Resolve a connection wrapper for a window id 174 * 175 * @param windowId The id of the window of interest 176 * 177 * @return a connection to the window 178 */ getConnectionLocked(int windowId)179 RemoteAccessibilityConnection getConnectionLocked(int windowId); 180 181 /** 182 * Perform the specified accessibility action 183 * 184 * @param resolvedWindowId The window ID 185 * [Other parameters match the method on IAccessibilityServiceConnection] 186 * 187 * @return Whether or not the action could be sent to the app process 188 */ performAccessibilityAction(int resolvedWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags, long interrogatingTid)189 boolean performAccessibilityAction(int resolvedWindowId, 190 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 191 IAccessibilityInteractionConnectionCallback callback, int fetchFlags, 192 long interrogatingTid); 193 194 /** 195 * Replace the interaction callback if needed, for example if the window is in picture- 196 * in-picture mode and needs its nodes replaced. 197 * 198 * @param originalCallback The callback we were planning to use 199 * @param resolvedWindowId The ID of the window we're calling 200 * @param interactionId The id for the original callback 201 * @param interrogatingPid Process ID of requester 202 * @param interrogatingTid Thread ID of requester 203 * 204 * @return The callback to use, which may be the original one. 205 */ replaceCallbackIfNeeded( IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId, int interactionId, int interrogatingPid, long interrogatingTid)206 @NonNull IAccessibilityInteractionConnectionCallback replaceCallbackIfNeeded( 207 IAccessibilityInteractionConnectionCallback originalCallback, 208 int resolvedWindowId, int interactionId, int interrogatingPid, 209 long interrogatingTid); 210 211 /** 212 * Request that the system make sure windows are available to interrogate 213 */ ensureWindowsAvailableTimed()214 void ensureWindowsAvailableTimed(); 215 216 /** 217 * Called back to notify system that the client has changed 218 * @param serviceInfoChanged True if the service's AccessibilityServiceInfo changed. 219 */ onClientChangeLocked(boolean serviceInfoChanged)220 void onClientChangeLocked(boolean serviceInfoChanged); 221 getCurrentUserIdLocked()222 int getCurrentUserIdLocked(); 223 isAccessibilityButtonShown()224 boolean isAccessibilityButtonShown(); 225 226 /** 227 * Persists the component names in the specified setting in a 228 * colon separated fashion. 229 * 230 * @param settingName The setting name. 231 * @param componentNames The component names. 232 * @param userId The user id to persist the setting for. 233 */ persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)234 void persistComponentNamesToSettingLocked(String settingName, 235 Set<ComponentName> componentNames, int userId); 236 237 /* This is exactly PendingIntent.getActivity, separated out for testability */ getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)238 PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent, 239 int flags); 240 } 241 AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, SecurityPolicy securityPolicy, SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, GlobalActionPerformer globalActionPerfomer)242 public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, 243 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, 244 Object lock, SecurityPolicy securityPolicy, SystemSupport systemSupport, 245 WindowManagerInternal windowManagerInternal, 246 GlobalActionPerformer globalActionPerfomer) { 247 mContext = context; 248 mWindowManagerService = windowManagerInternal; 249 mId = id; 250 mComponentName = componentName; 251 mAccessibilityServiceInfo = accessibilityServiceInfo; 252 mLock = lock; 253 mSecurityPolicy = securityPolicy; 254 mGlobalActionPerformer = globalActionPerfomer; 255 mSystemSupport = systemSupport; 256 mInvocationHandler = new InvocationHandler(mainHandler.getLooper()); 257 mEventDispatchHandler = new Handler(mainHandler.getLooper()) { 258 @Override 259 public void handleMessage(Message message) { 260 final int eventType = message.what; 261 AccessibilityEvent event = (AccessibilityEvent) message.obj; 262 boolean serviceWantsEvent = message.arg1 != 0; 263 notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent); 264 } 265 }; 266 setDynamicallyConfigurableProperties(accessibilityServiceInfo); 267 } 268 269 @Override onKeyEvent(KeyEvent keyEvent, int sequenceNumber)270 public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) { 271 if (!mRequestFilterKeyEvents || (mServiceInterface == null)) { 272 return false; 273 } 274 if((mAccessibilityServiceInfo.getCapabilities() 275 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) { 276 return false; 277 } 278 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 279 return false; 280 } 281 try { 282 mServiceInterface.onKeyEvent(keyEvent, sequenceNumber); 283 } catch (RemoteException e) { 284 return false; 285 } 286 return true; 287 } 288 setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)289 public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { 290 mEventTypes = info.eventTypes; 291 mFeedbackType = info.feedbackType; 292 String[] packageNames = info.packageNames; 293 if (packageNames != null) { 294 mPackageNames.addAll(Arrays.asList(packageNames)); 295 } 296 mNotificationTimeout = info.notificationTimeout; 297 mIsDefault = (info.flags & DEFAULT) != 0; 298 299 if (supportsFlagForNotImportantViews(info)) { 300 if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) { 301 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 302 } else { 303 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 304 } 305 } 306 307 if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) { 308 mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 309 } else { 310 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 311 } 312 313 mRequestTouchExplorationMode = (info.flags 314 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; 315 mRequestFilterKeyEvents = (info.flags 316 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; 317 mRetrieveInteractiveWindows = (info.flags 318 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; 319 mCaptureFingerprintGestures = (info.flags 320 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0; 321 mRequestAccessibilityButton = (info.flags 322 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 323 } 324 supportsFlagForNotImportantViews(AccessibilityServiceInfo info)325 protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { 326 return info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 327 >= Build.VERSION_CODES.JELLY_BEAN; 328 } 329 canReceiveEventsLocked()330 public boolean canReceiveEventsLocked() { 331 return (mEventTypes != 0 && mFeedbackType != 0 && mService != null); 332 } 333 334 @Override setOnKeyEventResult(boolean handled, int sequence)335 public void setOnKeyEventResult(boolean handled, int sequence) { 336 mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence); 337 } 338 339 @Override getServiceInfo()340 public AccessibilityServiceInfo getServiceInfo() { 341 synchronized (mLock) { 342 return mAccessibilityServiceInfo; 343 } 344 } 345 getCapabilities()346 public int getCapabilities() { 347 return mAccessibilityServiceInfo.getCapabilities(); 348 } 349 getRelevantEventTypes()350 int getRelevantEventTypes() { 351 return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK 352 : AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes; 353 } 354 355 @Override setServiceInfo(AccessibilityServiceInfo info)356 public void setServiceInfo(AccessibilityServiceInfo info) { 357 final long identity = Binder.clearCallingIdentity(); 358 try { 359 synchronized (mLock) { 360 // If the XML manifest had data to configure the service its info 361 // should be already set. In such a case update only the dynamically 362 // configurable properties. 363 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; 364 if (oldInfo != null) { 365 oldInfo.updateDynamicallyConfigurableProperties(info); 366 setDynamicallyConfigurableProperties(oldInfo); 367 } else { 368 setDynamicallyConfigurableProperties(info); 369 } 370 mSystemSupport.onClientChangeLocked(true); 371 } 372 } finally { 373 Binder.restoreCallingIdentity(identity); 374 } 375 } 376 isCalledForCurrentUserLocked()377 protected abstract boolean isCalledForCurrentUserLocked(); 378 379 @Override getWindows()380 public List<AccessibilityWindowInfo> getWindows() { 381 mSystemSupport.ensureWindowsAvailableTimed(); 382 synchronized (mLock) { 383 if (!isCalledForCurrentUserLocked()) { 384 return null; 385 } 386 final boolean permissionGranted = 387 mSecurityPolicy.canRetrieveWindowsLocked(this); 388 if (!permissionGranted) { 389 return null; 390 } 391 if (mSecurityPolicy.mWindows == null) { 392 return null; 393 } 394 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 395 return null; 396 } 397 List<AccessibilityWindowInfo> windows = new ArrayList<>(); 398 final int windowCount = mSecurityPolicy.mWindows.size(); 399 for (int i = 0; i < windowCount; i++) { 400 AccessibilityWindowInfo window = mSecurityPolicy.mWindows.get(i); 401 AccessibilityWindowInfo windowClone = 402 AccessibilityWindowInfo.obtain(window); 403 windowClone.setConnectionId(mId); 404 windows.add(windowClone); 405 } 406 return windows; 407 } 408 } 409 410 @Override getWindow(int windowId)411 public AccessibilityWindowInfo getWindow(int windowId) { 412 mSystemSupport.ensureWindowsAvailableTimed(); 413 synchronized (mLock) { 414 if (!isCalledForCurrentUserLocked()) { 415 return null; 416 } 417 final boolean permissionGranted = 418 mSecurityPolicy.canRetrieveWindowsLocked(this); 419 if (!permissionGranted) { 420 return null; 421 } 422 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 423 return null; 424 } 425 AccessibilityWindowInfo window = mSecurityPolicy.findA11yWindowInfoById(windowId); 426 if (window != null) { 427 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); 428 windowClone.setConnectionId(mId); 429 return windowClone; 430 } 431 return null; 432 } 433 } 434 435 @Override findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewIdResName, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)436 public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId, 437 long accessibilityNodeId, String viewIdResName, int interactionId, 438 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 439 throws RemoteException { 440 final int resolvedWindowId; 441 RemoteAccessibilityConnection connection; 442 Region partialInteractiveRegion = Region.obtain(); 443 MagnificationSpec spec; 444 synchronized (mLock) { 445 mUsesAccessibilityCache = true; 446 if (!isCalledForCurrentUserLocked()) { 447 return null; 448 } 449 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 450 final boolean permissionGranted = 451 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 452 if (!permissionGranted) { 453 return null; 454 } else { 455 connection = mSystemSupport.getConnectionLocked(resolvedWindowId); 456 if (connection == null) { 457 return null; 458 } 459 } 460 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 461 resolvedWindowId, partialInteractiveRegion)) { 462 partialInteractiveRegion.recycle(); 463 partialInteractiveRegion = null; 464 } 465 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 466 } 467 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 468 return null; 469 } 470 final int interrogatingPid = Binder.getCallingPid(); 471 callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 472 interrogatingPid, interrogatingTid); 473 final long identityToken = Binder.clearCallingIdentity(); 474 try { 475 connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId, 476 viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags, 477 interrogatingPid, interrogatingTid, spec); 478 return mSecurityPolicy.computeValidReportedPackages( 479 connection.getPackageName(), connection.getUid()); 480 } catch (RemoteException re) { 481 if (DEBUG) { 482 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId()."); 483 } 484 } finally { 485 Binder.restoreCallingIdentity(identityToken); 486 // Recycle if passed to another process. 487 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 488 partialInteractiveRegion.recycle(); 489 } 490 } 491 return null; 492 } 493 494 @Override findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)495 public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, 496 long accessibilityNodeId, String text, int interactionId, 497 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 498 throws RemoteException { 499 final int resolvedWindowId; 500 RemoteAccessibilityConnection connection; 501 Region partialInteractiveRegion = Region.obtain(); 502 MagnificationSpec spec; 503 synchronized (mLock) { 504 mUsesAccessibilityCache = true; 505 if (!isCalledForCurrentUserLocked()) { 506 return null; 507 } 508 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 509 final boolean permissionGranted = 510 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 511 if (!permissionGranted) { 512 return null; 513 } else { 514 connection = mSystemSupport.getConnectionLocked(resolvedWindowId); 515 if (connection == null) { 516 return null; 517 } 518 } 519 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 520 resolvedWindowId, partialInteractiveRegion)) { 521 partialInteractiveRegion.recycle(); 522 partialInteractiveRegion = null; 523 } 524 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 525 } 526 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 527 return null; 528 } 529 final int interrogatingPid = Binder.getCallingPid(); 530 callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 531 interrogatingPid, interrogatingTid); 532 final long identityToken = Binder.clearCallingIdentity(); 533 try { 534 connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId, 535 text, partialInteractiveRegion, interactionId, callback, mFetchFlags, 536 interrogatingPid, interrogatingTid, spec); 537 return mSecurityPolicy.computeValidReportedPackages( 538 connection.getPackageName(), connection.getUid()); 539 } catch (RemoteException re) { 540 if (DEBUG) { 541 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()"); 542 } 543 } finally { 544 Binder.restoreCallingIdentity(identityToken); 545 // Recycle if passed to another process. 546 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 547 partialInteractiveRegion.recycle(); 548 } 549 } 550 return null; 551 } 552 553 @Override findAccessibilityNodeInfoByAccessibilityId( int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid, Bundle arguments)554 public String[] findAccessibilityNodeInfoByAccessibilityId( 555 int accessibilityWindowId, long accessibilityNodeId, int interactionId, 556 IAccessibilityInteractionConnectionCallback callback, int flags, 557 long interrogatingTid, Bundle arguments) throws RemoteException { 558 final int resolvedWindowId; 559 RemoteAccessibilityConnection connection; 560 Region partialInteractiveRegion = Region.obtain(); 561 MagnificationSpec spec; 562 synchronized (mLock) { 563 mUsesAccessibilityCache = true; 564 if (!isCalledForCurrentUserLocked()) { 565 return null; 566 } 567 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 568 final boolean permissionGranted = 569 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 570 if (!permissionGranted) { 571 return null; 572 } else { 573 connection = mSystemSupport.getConnectionLocked(resolvedWindowId); 574 if (connection == null) { 575 return null; 576 } 577 } 578 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 579 resolvedWindowId, partialInteractiveRegion)) { 580 partialInteractiveRegion.recycle(); 581 partialInteractiveRegion = null; 582 } 583 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 584 } 585 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 586 return null; 587 } 588 final int interrogatingPid = Binder.getCallingPid(); 589 callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 590 interrogatingPid, interrogatingTid); 591 final long identityToken = Binder.clearCallingIdentity(); 592 try { 593 connection.getRemote().findAccessibilityNodeInfoByAccessibilityId( 594 accessibilityNodeId, partialInteractiveRegion, interactionId, callback, 595 mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments); 596 return mSecurityPolicy.computeValidReportedPackages( 597 connection.getPackageName(), connection.getUid()); 598 } catch (RemoteException re) { 599 if (DEBUG) { 600 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); 601 } 602 } finally { 603 Binder.restoreCallingIdentity(identityToken); 604 // Recycle if passed to another process. 605 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 606 partialInteractiveRegion.recycle(); 607 } 608 } 609 return null; 610 } 611 612 @Override findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)613 public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, 614 int focusType, int interactionId, 615 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 616 throws RemoteException { 617 final int resolvedWindowId; 618 RemoteAccessibilityConnection connection; 619 Region partialInteractiveRegion = Region.obtain(); 620 MagnificationSpec spec; 621 synchronized (mLock) { 622 if (!isCalledForCurrentUserLocked()) { 623 return null; 624 } 625 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked( 626 accessibilityWindowId, focusType); 627 final boolean permissionGranted = 628 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 629 if (!permissionGranted) { 630 return null; 631 } else { 632 connection = mSystemSupport.getConnectionLocked(resolvedWindowId); 633 if (connection == null) { 634 return null; 635 } 636 } 637 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 638 resolvedWindowId, partialInteractiveRegion)) { 639 partialInteractiveRegion.recycle(); 640 partialInteractiveRegion = null; 641 } 642 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 643 } 644 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 645 return null; 646 } 647 final int interrogatingPid = Binder.getCallingPid(); 648 callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 649 interrogatingPid, interrogatingTid); 650 final long identityToken = Binder.clearCallingIdentity(); 651 try { 652 connection.getRemote().findFocus(accessibilityNodeId, focusType, 653 partialInteractiveRegion, interactionId, callback, mFetchFlags, 654 interrogatingPid, interrogatingTid, spec); 655 return mSecurityPolicy.computeValidReportedPackages( 656 connection.getPackageName(), connection.getUid()); 657 } catch (RemoteException re) { 658 if (DEBUG) { 659 Slog.e(LOG_TAG, "Error calling findFocus()"); 660 } 661 } finally { 662 Binder.restoreCallingIdentity(identityToken); 663 // Recycle if passed to another process. 664 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 665 partialInteractiveRegion.recycle(); 666 } 667 } 668 return null; 669 } 670 671 @Override focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)672 public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, 673 int direction, int interactionId, 674 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 675 throws RemoteException { 676 final int resolvedWindowId; 677 RemoteAccessibilityConnection connection; 678 Region partialInteractiveRegion = Region.obtain(); 679 MagnificationSpec spec; 680 synchronized (mLock) { 681 if (!isCalledForCurrentUserLocked()) { 682 return null; 683 } 684 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 685 final boolean permissionGranted = 686 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId); 687 if (!permissionGranted) { 688 return null; 689 } else { 690 connection = mSystemSupport.getConnectionLocked(resolvedWindowId); 691 if (connection == null) { 692 return null; 693 } 694 } 695 if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked( 696 resolvedWindowId, partialInteractiveRegion)) { 697 partialInteractiveRegion.recycle(); 698 partialInteractiveRegion = null; 699 } 700 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 701 } 702 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 703 return null; 704 } 705 final int interrogatingPid = Binder.getCallingPid(); 706 callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 707 interrogatingPid, interrogatingTid); 708 final long identityToken = Binder.clearCallingIdentity(); 709 try { 710 connection.getRemote().focusSearch(accessibilityNodeId, direction, 711 partialInteractiveRegion, interactionId, callback, mFetchFlags, 712 interrogatingPid, interrogatingTid, spec); 713 return mSecurityPolicy.computeValidReportedPackages( 714 connection.getPackageName(), connection.getUid()); 715 } catch (RemoteException re) { 716 if (DEBUG) { 717 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()"); 718 } 719 } finally { 720 Binder.restoreCallingIdentity(identityToken); 721 // Recycle if passed to another process. 722 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 723 partialInteractiveRegion.recycle(); 724 } 725 } 726 return null; 727 } 728 729 @Override sendGesture(int sequence, ParceledListSlice gestureSteps)730 public void sendGesture(int sequence, ParceledListSlice gestureSteps) { 731 } 732 733 @Override performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)734 public boolean performAccessibilityAction(int accessibilityWindowId, 735 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 736 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 737 throws RemoteException { 738 final int resolvedWindowId; 739 IAccessibilityInteractionConnection connection = null; 740 synchronized (mLock) { 741 if (!isCalledForCurrentUserLocked()) { 742 return false; 743 } 744 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 745 if (!mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId)) { 746 return false; 747 } 748 } 749 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 750 return false; 751 } 752 boolean returnValue = 753 mSystemSupport.performAccessibilityAction(resolvedWindowId, accessibilityNodeId, 754 action, arguments, interactionId, callback, mFetchFlags, interrogatingTid); 755 return returnValue; 756 } 757 758 @Override performGlobalAction(int action)759 public boolean performGlobalAction(int action) { 760 synchronized (mLock) { 761 if (!isCalledForCurrentUserLocked()) { 762 return false; 763 } 764 } 765 return mGlobalActionPerformer.performGlobalAction(action); 766 } 767 768 @Override isFingerprintGestureDetectionAvailable()769 public boolean isFingerprintGestureDetectionAvailable() { 770 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 771 return false; 772 } 773 if (isCapturingFingerprintGestures()) { 774 FingerprintGestureDispatcher dispatcher = 775 mSystemSupport.getFingerprintGestureDispatcher(); 776 return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable(); 777 } 778 return false; 779 } 780 781 @Override getMagnificationScale(int displayId)782 public float getMagnificationScale(int displayId) { 783 synchronized (mLock) { 784 if (!isCalledForCurrentUserLocked()) { 785 return 1.0f; 786 } 787 } 788 final long identity = Binder.clearCallingIdentity(); 789 try { 790 return mSystemSupport.getMagnificationController().getScale(displayId); 791 } finally { 792 Binder.restoreCallingIdentity(identity); 793 } 794 } 795 796 @Override getMagnificationRegion(int displayId)797 public Region getMagnificationRegion(int displayId) { 798 synchronized (mLock) { 799 final Region region = Region.obtain(); 800 if (!isCalledForCurrentUserLocked()) { 801 return region; 802 } 803 MagnificationController magnificationController = 804 mSystemSupport.getMagnificationController(); 805 boolean registeredJustForThisCall = 806 registerMagnificationIfNeeded(displayId, magnificationController); 807 final long identity = Binder.clearCallingIdentity(); 808 try { 809 magnificationController.getMagnificationRegion(displayId, region); 810 return region; 811 } finally { 812 Binder.restoreCallingIdentity(identity); 813 if (registeredJustForThisCall) { 814 magnificationController.unregister(displayId); 815 } 816 } 817 } 818 } 819 820 @Override getMagnificationCenterX(int displayId)821 public float getMagnificationCenterX(int displayId) { 822 synchronized (mLock) { 823 if (!isCalledForCurrentUserLocked()) { 824 return 0.0f; 825 } 826 MagnificationController magnificationController = 827 mSystemSupport.getMagnificationController(); 828 boolean registeredJustForThisCall = 829 registerMagnificationIfNeeded(displayId, magnificationController); 830 final long identity = Binder.clearCallingIdentity(); 831 try { 832 return magnificationController.getCenterX(displayId); 833 } finally { 834 Binder.restoreCallingIdentity(identity); 835 if (registeredJustForThisCall) { 836 magnificationController.unregister(displayId); 837 } 838 } 839 } 840 } 841 842 @Override getMagnificationCenterY(int displayId)843 public float getMagnificationCenterY(int displayId) { 844 synchronized (mLock) { 845 if (!isCalledForCurrentUserLocked()) { 846 return 0.0f; 847 } 848 MagnificationController magnificationController = 849 mSystemSupport.getMagnificationController(); 850 boolean registeredJustForThisCall = 851 registerMagnificationIfNeeded(displayId, magnificationController); 852 final long identity = Binder.clearCallingIdentity(); 853 try { 854 return magnificationController.getCenterY(displayId); 855 } finally { 856 Binder.restoreCallingIdentity(identity); 857 if (registeredJustForThisCall) { 858 magnificationController.unregister(displayId); 859 } 860 } 861 } 862 } 863 registerMagnificationIfNeeded(int displayId, MagnificationController magnificationController)864 private boolean registerMagnificationIfNeeded(int displayId, 865 MagnificationController magnificationController) { 866 if (!magnificationController.isRegistered(displayId) 867 && mSecurityPolicy.canControlMagnification(this)) { 868 magnificationController.register(displayId); 869 return true; 870 } 871 return false; 872 } 873 874 @Override resetMagnification(int displayId, boolean animate)875 public boolean resetMagnification(int displayId, boolean animate) { 876 synchronized (mLock) { 877 if (!isCalledForCurrentUserLocked()) { 878 return false; 879 } 880 if (!mSecurityPolicy.canControlMagnification(this)) { 881 return false; 882 } 883 } 884 final long identity = Binder.clearCallingIdentity(); 885 try { 886 MagnificationController magnificationController = 887 mSystemSupport.getMagnificationController(); 888 return (magnificationController.reset(displayId, animate) 889 || !magnificationController.isMagnifying(displayId)); 890 } finally { 891 Binder.restoreCallingIdentity(identity); 892 } 893 } 894 895 @Override setMagnificationScaleAndCenter(int displayId, float scale, float centerX, float centerY, boolean animate)896 public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX, 897 float centerY, boolean animate) { 898 synchronized (mLock) { 899 if (!isCalledForCurrentUserLocked()) { 900 return false; 901 } 902 if (!mSecurityPolicy.canControlMagnification(this)) { 903 return false; 904 } 905 final long identity = Binder.clearCallingIdentity(); 906 try { 907 MagnificationController magnificationController = 908 mSystemSupport.getMagnificationController(); 909 if (!magnificationController.isRegistered(displayId)) { 910 magnificationController.register(displayId); 911 } 912 return magnificationController 913 .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId); 914 } finally { 915 Binder.restoreCallingIdentity(identity); 916 } 917 } 918 } 919 920 @Override setMagnificationCallbackEnabled(int displayId, boolean enabled)921 public void setMagnificationCallbackEnabled(int displayId, boolean enabled) { 922 mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled); 923 } 924 isMagnificationCallbackEnabled(int displayId)925 public boolean isMagnificationCallbackEnabled(int displayId) { 926 return mInvocationHandler.isMagnificationCallbackEnabled(displayId); 927 } 928 929 @Override setSoftKeyboardCallbackEnabled(boolean enabled)930 public void setSoftKeyboardCallbackEnabled(boolean enabled) { 931 mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled); 932 } 933 934 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)935 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 936 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; 937 synchronized (mLock) { 938 pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo() 939 .loadLabel(mContext.getPackageManager())); 940 pw.append(", feedbackType" 941 + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType)); 942 pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities()); 943 pw.append(", eventTypes=" 944 + AccessibilityEvent.eventTypeToString(mEventTypes)); 945 pw.append(", notificationTimeout=" + mNotificationTimeout); 946 pw.append("]"); 947 } 948 } 949 onAdded()950 public void onAdded() { 951 final long identity = Binder.clearCallingIdentity(); 952 try { 953 mWindowManagerService.addWindowToken(mOverlayWindowToken, 954 TYPE_ACCESSIBILITY_OVERLAY, DEFAULT_DISPLAY); 955 } finally { 956 Binder.restoreCallingIdentity(identity); 957 } 958 } 959 onRemoved()960 public void onRemoved() { 961 final long identity = Binder.clearCallingIdentity(); 962 try { 963 mWindowManagerService.removeWindowToken(mOverlayWindowToken, true, DEFAULT_DISPLAY); 964 } finally { 965 Binder.restoreCallingIdentity(identity); 966 } 967 } 968 resetLocked()969 public void resetLocked() { 970 mSystemSupport.getKeyEventDispatcher().flush(this); 971 try { 972 // Clear the proxy in the other process so this 973 // IAccessibilityServiceConnection can be garbage collected. 974 if (mServiceInterface != null) { 975 mServiceInterface.init(null, mId, null); 976 } 977 } catch (RemoteException re) { 978 /* ignore */ 979 } 980 if (mService != null) { 981 mService.unlinkToDeath(this, 0); 982 mService = null; 983 } 984 985 mServiceInterface = null; 986 mReceivedAccessibilityButtonCallbackSinceBind = false; 987 } 988 isConnectedLocked()989 public boolean isConnectedLocked() { 990 return (mService != null); 991 } 992 notifyAccessibilityEvent(AccessibilityEvent event)993 public void notifyAccessibilityEvent(AccessibilityEvent event) { 994 synchronized (mLock) { 995 final int eventType = event.getEventType(); 996 997 final boolean serviceWantsEvent = wantsEventLocked(event); 998 final boolean requiredForCacheConsistency = mUsesAccessibilityCache 999 && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0); 1000 if (!serviceWantsEvent && !requiredForCacheConsistency) { 1001 return; 1002 } 1003 1004 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 1005 return; 1006 } 1007 // Make a copy since during dispatch it is possible the event to 1008 // be modified to remove its source if the receiving service does 1009 // not have permission to access the window content. 1010 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event); 1011 Message message; 1012 if ((mNotificationTimeout > 0) 1013 && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) { 1014 // Allow at most one pending event 1015 final AccessibilityEvent oldEvent = mPendingEvents.get(eventType); 1016 mPendingEvents.put(eventType, newEvent); 1017 if (oldEvent != null) { 1018 mEventDispatchHandler.removeMessages(eventType); 1019 oldEvent.recycle(); 1020 } 1021 message = mEventDispatchHandler.obtainMessage(eventType); 1022 } else { 1023 // Send all messages, bypassing mPendingEvents 1024 message = mEventDispatchHandler.obtainMessage(eventType, newEvent); 1025 } 1026 message.arg1 = serviceWantsEvent ? 1 : 0; 1027 1028 mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout); 1029 } 1030 } 1031 1032 /** 1033 * Determines if given event can be dispatched to a service based on the package of the 1034 * event source. Specifically, a service is notified if it is interested in events from the 1035 * package. 1036 * 1037 * @param event The event. 1038 * @return True if the listener should be notified, false otherwise. 1039 */ wantsEventLocked(AccessibilityEvent event)1040 private boolean wantsEventLocked(AccessibilityEvent event) { 1041 1042 if (!canReceiveEventsLocked()) { 1043 return false; 1044 } 1045 1046 if ((event.getWindowId() != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) 1047 && !event.isImportantForAccessibility() 1048 && (mFetchFlags & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 1049 return false; 1050 } 1051 1052 int eventType = event.getEventType(); 1053 if ((mEventTypes & eventType) != eventType) { 1054 return false; 1055 } 1056 1057 Set<String> packageNames = mPackageNames; 1058 String packageName = (event.getPackageName() != null) 1059 ? event.getPackageName().toString() : null; 1060 1061 return (packageNames.isEmpty() || packageNames.contains(packageName)); 1062 } 1063 1064 /** 1065 * Notifies an accessibility service client for a scheduled event given the event type. 1066 * 1067 * @param eventType The type of the event to dispatch. 1068 */ notifyAccessibilityEventInternal( int eventType, AccessibilityEvent event, boolean serviceWantsEvent)1069 private void notifyAccessibilityEventInternal( 1070 int eventType, 1071 AccessibilityEvent event, 1072 boolean serviceWantsEvent) { 1073 IAccessibilityServiceClient listener; 1074 1075 synchronized (mLock) { 1076 listener = mServiceInterface; 1077 1078 // If the service died/was disabled while the message for dispatching 1079 // the accessibility event was propagating the listener may be null. 1080 if (listener == null) { 1081 return; 1082 } 1083 1084 // There are two ways we notify for events, throttled AND non-throttled. If we 1085 // are not throttling, then messages come with events, which we handle with 1086 // minimal fuss. 1087 if (event == null) { 1088 // We are throttling events, so we'll send the event for this type in 1089 // mPendingEvents as long as it it's null. It can only null due to a race 1090 // condition: 1091 // 1092 // 1) A binder thread calls notifyAccessibilityServiceDelayedLocked 1093 // which posts a message for dispatching an event and stores the event 1094 // in mPendingEvents. 1095 // 2) The message is pulled from the queue by the handler on the service 1096 // thread and this method is just about to acquire the lock. 1097 // 3) Another binder thread acquires the lock in notifyAccessibilityEvent 1098 // 4) notifyAccessibilityEvent recycles the event that this method was about 1099 // to process, replaces it with a new one, and posts a second message 1100 // 5) This method grabs the new event, processes it, and removes it from 1101 // mPendingEvents 1102 // 6) The second message dispatched in (4) arrives, but the event has been 1103 // remvoved in (5). 1104 event = mPendingEvents.get(eventType); 1105 if (event == null) { 1106 return; 1107 } 1108 mPendingEvents.remove(eventType); 1109 } 1110 if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) { 1111 event.setConnectionId(mId); 1112 } else { 1113 event.setSource((View) null); 1114 } 1115 event.setSealed(true); 1116 } 1117 1118 try { 1119 listener.onAccessibilityEvent(event, serviceWantsEvent); 1120 if (DEBUG) { 1121 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); 1122 } 1123 } catch (RemoteException re) { 1124 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re); 1125 } finally { 1126 event.recycle(); 1127 } 1128 } 1129 notifyGesture(int gestureId)1130 public void notifyGesture(int gestureId) { 1131 mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE, 1132 gestureId, 0).sendToTarget(); 1133 } 1134 notifyClearAccessibilityNodeInfoCache()1135 public void notifyClearAccessibilityNodeInfoCache() { 1136 mInvocationHandler.sendEmptyMessage( 1137 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE); 1138 } 1139 notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1140 public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, 1141 float scale, float centerX, float centerY) { 1142 mInvocationHandler 1143 .notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY); 1144 } 1145 notifySoftKeyboardShowModeChangedLocked(int showState)1146 public void notifySoftKeyboardShowModeChangedLocked(int showState) { 1147 mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState); 1148 } 1149 notifyAccessibilityButtonClickedLocked()1150 public void notifyAccessibilityButtonClickedLocked() { 1151 mInvocationHandler.notifyAccessibilityButtonClickedLocked(); 1152 } 1153 notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1154 public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) { 1155 mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available); 1156 } 1157 1158 /** 1159 * Called by the invocation handler to notify the service that the 1160 * state of magnification has changed. 1161 */ notifyMagnificationChangedInternal(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1162 private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region, 1163 float scale, float centerX, float centerY) { 1164 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1165 if (listener != null) { 1166 try { 1167 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY); 1168 } catch (RemoteException re) { 1169 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re); 1170 } 1171 } 1172 } 1173 1174 /** 1175 * Called by the invocation handler to notify the service that the state of the soft 1176 * keyboard show mode has changed. 1177 */ notifySoftKeyboardShowModeChangedInternal(int showState)1178 private void notifySoftKeyboardShowModeChangedInternal(int showState) { 1179 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1180 if (listener != null) { 1181 try { 1182 listener.onSoftKeyboardShowModeChanged(showState); 1183 } catch (RemoteException re) { 1184 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService, 1185 re); 1186 } 1187 } 1188 } 1189 notifyAccessibilityButtonClickedInternal()1190 private void notifyAccessibilityButtonClickedInternal() { 1191 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1192 if (listener != null) { 1193 try { 1194 listener.onAccessibilityButtonClicked(); 1195 } catch (RemoteException re) { 1196 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re); 1197 } 1198 } 1199 } 1200 notifyAccessibilityButtonAvailabilityChangedInternal(boolean available)1201 private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) { 1202 // Only notify the service if it's not been notified or the state has changed 1203 if (mReceivedAccessibilityButtonCallbackSinceBind 1204 && (mLastAccessibilityButtonCallbackState == available)) { 1205 return; 1206 } 1207 mReceivedAccessibilityButtonCallbackSinceBind = true; 1208 mLastAccessibilityButtonCallbackState = available; 1209 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1210 if (listener != null) { 1211 try { 1212 listener.onAccessibilityButtonAvailabilityChanged(available); 1213 } catch (RemoteException re) { 1214 Slog.e(LOG_TAG, 1215 "Error sending accessibility button availability change to " + mService, 1216 re); 1217 } 1218 } 1219 } 1220 notifyGestureInternal(int gestureId)1221 private void notifyGestureInternal(int gestureId) { 1222 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1223 if (listener != null) { 1224 try { 1225 listener.onGesture(gestureId); 1226 } catch (RemoteException re) { 1227 Slog.e(LOG_TAG, "Error during sending gesture " + gestureId 1228 + " to " + mService, re); 1229 } 1230 } 1231 } 1232 notifyClearAccessibilityCacheInternal()1233 private void notifyClearAccessibilityCacheInternal() { 1234 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1235 if (listener != null) { 1236 try { 1237 listener.clearAccessibilityCache(); 1238 } catch (RemoteException re) { 1239 Slog.e(LOG_TAG, "Error during requesting accessibility info cache" 1240 + " to be cleared.", re); 1241 } 1242 } 1243 } 1244 getServiceInterfaceSafely()1245 private IAccessibilityServiceClient getServiceInterfaceSafely() { 1246 synchronized (mLock) { 1247 return mServiceInterface; 1248 } 1249 } 1250 resolveAccessibilityWindowIdLocked(int accessibilityWindowId)1251 private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) { 1252 if (accessibilityWindowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) { 1253 return mSecurityPolicy.getActiveWindowId(); 1254 } 1255 return accessibilityWindowId; 1256 } 1257 resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)1258 private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { 1259 if (windowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) { 1260 return mSecurityPolicy.mActiveWindowId; 1261 } 1262 if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) { 1263 if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { 1264 return mSecurityPolicy.mFocusedWindowId; 1265 } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { 1266 return mSecurityPolicy.mAccessibilityFocusedWindowId; 1267 } 1268 } 1269 return windowId; 1270 } 1271 getComponentName()1272 public ComponentName getComponentName() { 1273 return mComponentName; 1274 } 1275 1276 private final class InvocationHandler extends Handler { 1277 public static final int MSG_ON_GESTURE = 1; 1278 public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2; 1279 1280 private static final int MSG_ON_MAGNIFICATION_CHANGED = 5; 1281 private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6; 1282 private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7; 1283 private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8; 1284 1285 /** List of magnification callback states, mapping from displayId -> Boolean */ 1286 @GuardedBy("mlock") 1287 private final SparseArray<Boolean> mMagnificationCallbackState = new SparseArray<>(0); 1288 private boolean mIsSoftKeyboardCallbackEnabled = false; 1289 InvocationHandler(Looper looper)1290 public InvocationHandler(Looper looper) { 1291 super(looper, null, true); 1292 } 1293 1294 @Override handleMessage(Message message)1295 public void handleMessage(Message message) { 1296 final int type = message.what; 1297 switch (type) { 1298 case MSG_ON_GESTURE: { 1299 final int gestureId = message.arg1; 1300 notifyGestureInternal(gestureId); 1301 } break; 1302 1303 case MSG_CLEAR_ACCESSIBILITY_CACHE: { 1304 notifyClearAccessibilityCacheInternal(); 1305 } break; 1306 1307 case MSG_ON_MAGNIFICATION_CHANGED: { 1308 final SomeArgs args = (SomeArgs) message.obj; 1309 final Region region = (Region) args.arg1; 1310 final float scale = (float) args.arg2; 1311 final float centerX = (float) args.arg3; 1312 final float centerY = (float) args.arg4; 1313 final int displayId = args.argi1; 1314 notifyMagnificationChangedInternal(displayId, region, scale, centerX, centerY); 1315 args.recycle(); 1316 } break; 1317 1318 case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: { 1319 final int showState = (int) message.arg1; 1320 notifySoftKeyboardShowModeChangedInternal(showState); 1321 } break; 1322 1323 case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: { 1324 notifyAccessibilityButtonClickedInternal(); 1325 } break; 1326 1327 case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: { 1328 final boolean available = (message.arg1 != 0); 1329 notifyAccessibilityButtonAvailabilityChangedInternal(available); 1330 } break; 1331 1332 default: { 1333 throw new IllegalArgumentException("Unknown message: " + type); 1334 } 1335 } 1336 } 1337 notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1338 public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, 1339 float scale, float centerX, float centerY) { 1340 synchronized (mLock) { 1341 if (mMagnificationCallbackState.get(displayId) == null) { 1342 return; 1343 } 1344 } 1345 1346 final SomeArgs args = SomeArgs.obtain(); 1347 args.arg1 = region; 1348 args.arg2 = scale; 1349 args.arg3 = centerX; 1350 args.arg4 = centerY; 1351 args.argi1 = displayId; 1352 1353 final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args); 1354 msg.sendToTarget(); 1355 } 1356 setMagnificationCallbackEnabled(int displayId, boolean enabled)1357 public void setMagnificationCallbackEnabled(int displayId, boolean enabled) { 1358 synchronized (mLock) { 1359 if (enabled) { 1360 mMagnificationCallbackState.put(displayId, true); 1361 } else { 1362 mMagnificationCallbackState.remove(displayId); 1363 } 1364 } 1365 } 1366 isMagnificationCallbackEnabled(int displayId)1367 public boolean isMagnificationCallbackEnabled(int displayId) { 1368 synchronized (mLock) { 1369 return mMagnificationCallbackState.get(displayId) != null; 1370 } 1371 } 1372 notifySoftKeyboardShowModeChangedLocked(int showState)1373 public void notifySoftKeyboardShowModeChangedLocked(int showState) { 1374 if (!mIsSoftKeyboardCallbackEnabled) { 1375 return; 1376 } 1377 1378 final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0); 1379 msg.sendToTarget(); 1380 } 1381 setSoftKeyboardCallbackEnabled(boolean enabled)1382 public void setSoftKeyboardCallbackEnabled(boolean enabled) { 1383 mIsSoftKeyboardCallbackEnabled = enabled; 1384 } 1385 notifyAccessibilityButtonClickedLocked()1386 public void notifyAccessibilityButtonClickedLocked() { 1387 final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED); 1388 msg.sendToTarget(); 1389 } 1390 notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1391 public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) { 1392 final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, 1393 (available ? 1 : 0), 0); 1394 msg.sendToTarget(); 1395 } 1396 } 1397 } 1398