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.KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE; 20 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER; 21 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_STATUS; 22 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP; 23 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT; 24 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; 25 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; 26 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS; 27 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; 28 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK; 29 30 import android.accessibilityservice.AccessibilityGestureEvent; 31 import android.accessibilityservice.AccessibilityService; 32 import android.accessibilityservice.AccessibilityServiceInfo; 33 import android.accessibilityservice.IAccessibilityServiceClient; 34 import android.accessibilityservice.IAccessibilityServiceConnection; 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.app.PendingIntent; 38 import android.content.ComponentName; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.ServiceConnection; 42 import android.content.pm.PackageManager; 43 import android.content.pm.ParceledListSlice; 44 import android.graphics.GraphicBuffer; 45 import android.graphics.ParcelableColorSpace; 46 import android.graphics.Region; 47 import android.hardware.HardwareBuffer; 48 import android.hardware.display.DisplayManager; 49 import android.hardware.display.DisplayManagerInternal; 50 import android.os.Binder; 51 import android.os.Build; 52 import android.os.Bundle; 53 import android.os.Handler; 54 import android.os.IBinder; 55 import android.os.Looper; 56 import android.os.Message; 57 import android.os.PowerManager; 58 import android.os.RemoteCallback; 59 import android.os.RemoteException; 60 import android.os.ServiceManager; 61 import android.os.SystemClock; 62 import android.util.Slog; 63 import android.util.SparseArray; 64 import android.view.Display; 65 import android.view.KeyEvent; 66 import android.view.MagnificationSpec; 67 import android.view.SurfaceControl.ScreenshotGraphicBuffer; 68 import android.view.View; 69 import android.view.WindowInfo; 70 import android.view.accessibility.AccessibilityCache; 71 import android.view.accessibility.AccessibilityEvent; 72 import android.view.accessibility.AccessibilityNodeInfo; 73 import android.view.accessibility.AccessibilityWindowInfo; 74 import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 75 76 import com.android.internal.annotations.GuardedBy; 77 import com.android.internal.compat.IPlatformCompat; 78 import com.android.internal.os.SomeArgs; 79 import com.android.internal.util.DumpUtils; 80 import com.android.internal.util.function.pooled.PooledLambda; 81 import com.android.server.LocalServices; 82 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection; 83 import com.android.server.wm.ActivityTaskManagerInternal; 84 import com.android.server.wm.WindowManagerInternal; 85 86 import java.io.FileDescriptor; 87 import java.io.PrintWriter; 88 import java.util.ArrayList; 89 import java.util.Arrays; 90 import java.util.Collections; 91 import java.util.HashSet; 92 import java.util.List; 93 import java.util.Set; 94 95 /** 96 * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. 97 * It is responsible for behavior common to both types of clients. 98 */ 99 abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub 100 implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter, 101 FingerprintGestureDispatcher.FingerprintGestureClient { 102 private static final boolean DEBUG = false; 103 private static final String LOG_TAG = "AbstractAccessibilityServiceConnection"; 104 private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000; 105 106 protected static final String TAKE_SCREENSHOT = "takeScreenshot"; 107 protected final Context mContext; 108 protected final SystemSupport mSystemSupport; 109 protected final WindowManagerInternal mWindowManagerService; 110 private final SystemActionPerformer mSystemActionPerformer; 111 private final AccessibilityWindowManager mA11yWindowManager; 112 private final DisplayManager mDisplayManager; 113 private final PowerManager mPowerManager; 114 private final IPlatformCompat mIPlatformCompat; 115 116 private final Handler mMainHandler; 117 118 // Handler for scheduling method invocations on the main thread. 119 public final InvocationHandler mInvocationHandler; 120 121 final int mId; 122 123 protected final AccessibilityServiceInfo mAccessibilityServiceInfo; 124 125 // Lock must match the one used by AccessibilityManagerService 126 protected final Object mLock; 127 128 protected final AccessibilitySecurityPolicy mSecurityPolicy; 129 130 // The service that's bound to this instance. Whenever this value is non-null, this 131 // object is registered as a death recipient 132 IBinder mService; 133 134 IAccessibilityServiceClient mServiceInterface; 135 136 int mEventTypes; 137 138 int mFeedbackType; 139 140 Set<String> mPackageNames = new HashSet<>(); 141 142 boolean mIsDefault; 143 144 boolean mRequestTouchExplorationMode; 145 146 private boolean mServiceHandlesDoubleTap; 147 148 private boolean mRequestMultiFingerGestures; 149 150 boolean mRequestFilterKeyEvents; 151 152 boolean mRetrieveInteractiveWindows; 153 154 boolean mCaptureFingerprintGestures; 155 156 boolean mRequestAccessibilityButton; 157 158 boolean mReceivedAccessibilityButtonCallbackSinceBind; 159 160 boolean mLastAccessibilityButtonCallbackState; 161 162 int mFetchFlags; 163 164 long mNotificationTimeout; 165 166 final ComponentName mComponentName; 167 168 // the events pending events to be dispatched to this service 169 final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>(); 170 171 /** Whether this service relies on its {@link AccessibilityCache} being up to date */ 172 boolean mUsesAccessibilityCache = false; 173 174 // Handler only for dispatching accessibility events since we use event 175 // types as message types allowing us to remove messages per event type. 176 public Handler mEventDispatchHandler; 177 178 final SparseArray<IBinder> mOverlayWindowTokens = new SparseArray(); 179 180 /** The timestamp of requesting to take screenshot in milliseconds */ 181 private long mRequestTakeScreenshotTimestampMs; 182 183 public interface SystemSupport { 184 /** 185 * @return The current dispatcher for key events 186 */ getKeyEventDispatcher()187 @NonNull KeyEventDispatcher getKeyEventDispatcher(); 188 189 /** 190 * @param windowId The id of the window of interest 191 * @return The magnification spec for the window, or {@code null} if none is available 192 */ getCompatibleMagnificationSpecLocked(int windowId)193 @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId); 194 195 /** 196 * @param displayId The display id. 197 * @return The current injector of motion events used on the display, if one exists. 198 */ getMotionEventInjectorForDisplayLocked(int displayId)199 @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId); 200 201 /** 202 * @return The current dispatcher for fingerprint gestures, if one exists 203 */ getFingerprintGestureDispatcher()204 @Nullable FingerprintGestureDispatcher getFingerprintGestureDispatcher(); 205 206 /** 207 * @return The magnification controller 208 */ getMagnificationController()209 @NonNull MagnificationController getMagnificationController(); 210 211 /** 212 * Called back to notify system that the client has changed 213 * @param serviceInfoChanged True if the service's AccessibilityServiceInfo changed. 214 */ onClientChangeLocked(boolean serviceInfoChanged)215 void onClientChangeLocked(boolean serviceInfoChanged); 216 getCurrentUserIdLocked()217 int getCurrentUserIdLocked(); 218 isAccessibilityButtonShown()219 boolean isAccessibilityButtonShown(); 220 221 /** 222 * Persists the component names in the specified setting in a 223 * colon separated fashion. 224 * 225 * @param settingName The setting name. 226 * @param componentNames The component names. 227 * @param userId The user id to persist the setting for. 228 */ persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)229 void persistComponentNamesToSettingLocked(String settingName, 230 Set<ComponentName> componentNames, int userId); 231 232 /* This is exactly PendingIntent.getActivity, separated out for testability */ getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)233 PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent, 234 int flags); 235 setGestureDetectionPassthroughRegion(int displayId, Region region)236 void setGestureDetectionPassthroughRegion(int displayId, Region region); 237 setTouchExplorationPassthroughRegion(int displayId, Region region)238 void setTouchExplorationPassthroughRegion(int displayId, Region region); 239 } 240 AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager a11yWindowManager)241 public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, 242 AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, 243 Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, 244 WindowManagerInternal windowManagerInternal, 245 SystemActionPerformer systemActionPerfomer, 246 AccessibilityWindowManager a11yWindowManager) { 247 mContext = context; 248 mWindowManagerService = windowManagerInternal; 249 mId = id; 250 mComponentName = componentName; 251 mAccessibilityServiceInfo = accessibilityServiceInfo; 252 mLock = lock; 253 mSecurityPolicy = securityPolicy; 254 mSystemActionPerformer = systemActionPerfomer; 255 mSystemSupport = systemSupport; 256 mMainHandler = mainHandler; 257 mInvocationHandler = new InvocationHandler(mainHandler.getLooper()); 258 mA11yWindowManager = a11yWindowManager; 259 mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 260 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 261 mIPlatformCompat = IPlatformCompat.Stub.asInterface( 262 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); 263 mEventDispatchHandler = new Handler(mainHandler.getLooper()) { 264 @Override 265 public void handleMessage(Message message) { 266 final int eventType = message.what; 267 AccessibilityEvent event = (AccessibilityEvent) message.obj; 268 boolean serviceWantsEvent = message.arg1 != 0; 269 notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent); 270 } 271 }; 272 setDynamicallyConfigurableProperties(accessibilityServiceInfo); 273 } 274 275 @Override onKeyEvent(KeyEvent keyEvent, int sequenceNumber)276 public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) { 277 if (!mRequestFilterKeyEvents || (mServiceInterface == null)) { 278 return false; 279 } 280 if((mAccessibilityServiceInfo.getCapabilities() 281 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) { 282 return false; 283 } 284 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 285 return false; 286 } 287 try { 288 mServiceInterface.onKeyEvent(keyEvent, sequenceNumber); 289 } catch (RemoteException e) { 290 return false; 291 } 292 return true; 293 } 294 setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)295 public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { 296 mEventTypes = info.eventTypes; 297 mFeedbackType = info.feedbackType; 298 String[] packageNames = info.packageNames; 299 if (packageNames != null) { 300 mPackageNames.addAll(Arrays.asList(packageNames)); 301 } 302 mNotificationTimeout = info.notificationTimeout; 303 mIsDefault = (info.flags & DEFAULT) != 0; 304 305 if (supportsFlagForNotImportantViews(info)) { 306 if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) { 307 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 308 } else { 309 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS; 310 } 311 } 312 313 if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) { 314 mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 315 } else { 316 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS; 317 } 318 319 mRequestTouchExplorationMode = (info.flags 320 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0; 321 mServiceHandlesDoubleTap = (info.flags 322 & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0; 323 mRequestMultiFingerGestures = (info.flags 324 & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0; 325 mRequestFilterKeyEvents = (info.flags 326 & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; 327 mRetrieveInteractiveWindows = (info.flags 328 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; 329 mCaptureFingerprintGestures = (info.flags 330 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0; 331 mRequestAccessibilityButton = (info.flags 332 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; 333 } 334 supportsFlagForNotImportantViews(AccessibilityServiceInfo info)335 protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) { 336 return info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion 337 >= Build.VERSION_CODES.JELLY_BEAN; 338 } 339 canReceiveEventsLocked()340 public boolean canReceiveEventsLocked() { 341 return (mEventTypes != 0 && mService != null); 342 } 343 344 @Override setOnKeyEventResult(boolean handled, int sequence)345 public void setOnKeyEventResult(boolean handled, int sequence) { 346 mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence); 347 } 348 349 @Override getServiceInfo()350 public AccessibilityServiceInfo getServiceInfo() { 351 synchronized (mLock) { 352 return mAccessibilityServiceInfo; 353 } 354 } 355 getCapabilities()356 public int getCapabilities() { 357 return mAccessibilityServiceInfo.getCapabilities(); 358 } 359 getRelevantEventTypes()360 int getRelevantEventTypes() { 361 return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK 362 : AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes; 363 } 364 365 @Override setServiceInfo(AccessibilityServiceInfo info)366 public void setServiceInfo(AccessibilityServiceInfo info) { 367 final long identity = Binder.clearCallingIdentity(); 368 try { 369 synchronized (mLock) { 370 // If the XML manifest had data to configure the service its info 371 // should be already set. In such a case update only the dynamically 372 // configurable properties. 373 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo; 374 if (oldInfo != null) { 375 oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info); 376 setDynamicallyConfigurableProperties(oldInfo); 377 } else { 378 setDynamicallyConfigurableProperties(info); 379 } 380 mSystemSupport.onClientChangeLocked(true); 381 } 382 } finally { 383 Binder.restoreCallingIdentity(identity); 384 } 385 } 386 hasRightsToCurrentUserLocked()387 protected abstract boolean hasRightsToCurrentUserLocked(); 388 389 @Nullable 390 @Override getWindows()391 public AccessibilityWindowInfo.WindowListSparseArray getWindows() { 392 synchronized (mLock) { 393 if (!hasRightsToCurrentUserLocked()) { 394 return null; 395 } 396 final boolean permissionGranted = 397 mSecurityPolicy.canRetrieveWindowsLocked(this); 398 if (!permissionGranted) { 399 return null; 400 } 401 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 402 return null; 403 } 404 final AccessibilityWindowInfo.WindowListSparseArray allWindows = 405 new AccessibilityWindowInfo.WindowListSparseArray(); 406 final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(); 407 final int displayListCounts = displayList.size(); 408 if (displayListCounts > 0) { 409 for (int i = 0; i < displayListCounts; i++) { 410 final int displayId = displayList.get(i); 411 ensureWindowsAvailableTimedLocked(displayId); 412 413 final List<AccessibilityWindowInfo> windowList = getWindowsByDisplayLocked( 414 displayId); 415 if (windowList != null) { 416 allWindows.put(displayId, windowList); 417 } 418 } 419 } 420 return allWindows; 421 } 422 } 423 424 @Override getWindow(int windowId)425 public AccessibilityWindowInfo getWindow(int windowId) { 426 synchronized (mLock) { 427 int displayId = Display.INVALID_DISPLAY; 428 if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) { 429 displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked( 430 mSystemSupport.getCurrentUserIdLocked(), windowId); 431 } 432 ensureWindowsAvailableTimedLocked(displayId); 433 434 if (!hasRightsToCurrentUserLocked()) { 435 return null; 436 } 437 final boolean permissionGranted = 438 mSecurityPolicy.canRetrieveWindowsLocked(this); 439 if (!permissionGranted) { 440 return null; 441 } 442 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 443 return null; 444 } 445 AccessibilityWindowInfo window = 446 mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId); 447 if (window != null) { 448 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window); 449 windowClone.setConnectionId(mId); 450 return windowClone; 451 } 452 return null; 453 } 454 } 455 456 @Override findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewIdResName, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)457 public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId, 458 long accessibilityNodeId, String viewIdResName, int interactionId, 459 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 460 throws RemoteException { 461 final int resolvedWindowId; 462 RemoteAccessibilityConnection connection; 463 Region partialInteractiveRegion = Region.obtain(); 464 MagnificationSpec spec; 465 synchronized (mLock) { 466 mUsesAccessibilityCache = true; 467 if (!hasRightsToCurrentUserLocked()) { 468 return null; 469 } 470 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 471 final boolean permissionGranted = 472 mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 473 mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId); 474 if (!permissionGranted) { 475 return null; 476 } else { 477 connection = mA11yWindowManager.getConnectionLocked( 478 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId); 479 if (connection == null) { 480 return null; 481 } 482 } 483 if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked( 484 resolvedWindowId, partialInteractiveRegion)) { 485 partialInteractiveRegion.recycle(); 486 partialInteractiveRegion = null; 487 } 488 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 489 } 490 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 491 return null; 492 } 493 final int interrogatingPid = Binder.getCallingPid(); 494 callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 495 interrogatingPid, interrogatingTid); 496 final long identityToken = Binder.clearCallingIdentity(); 497 try { 498 connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId, 499 viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags, 500 interrogatingPid, interrogatingTid, spec); 501 return mSecurityPolicy.computeValidReportedPackages( 502 connection.getPackageName(), connection.getUid()); 503 } catch (RemoteException re) { 504 if (DEBUG) { 505 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId()."); 506 } 507 } finally { 508 Binder.restoreCallingIdentity(identityToken); 509 // Recycle if passed to another process. 510 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 511 partialInteractiveRegion.recycle(); 512 } 513 } 514 return null; 515 } 516 517 @Override findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)518 public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId, 519 long accessibilityNodeId, String text, int interactionId, 520 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 521 throws RemoteException { 522 final int resolvedWindowId; 523 RemoteAccessibilityConnection connection; 524 Region partialInteractiveRegion = Region.obtain(); 525 MagnificationSpec spec; 526 synchronized (mLock) { 527 mUsesAccessibilityCache = true; 528 if (!hasRightsToCurrentUserLocked()) { 529 return null; 530 } 531 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 532 final boolean permissionGranted = 533 mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 534 mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId); 535 if (!permissionGranted) { 536 return null; 537 } else { 538 connection = mA11yWindowManager.getConnectionLocked( 539 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId); 540 if (connection == null) { 541 return null; 542 } 543 } 544 if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked( 545 resolvedWindowId, partialInteractiveRegion)) { 546 partialInteractiveRegion.recycle(); 547 partialInteractiveRegion = null; 548 } 549 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 550 } 551 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 552 return null; 553 } 554 final int interrogatingPid = Binder.getCallingPid(); 555 callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 556 interrogatingPid, interrogatingTid); 557 final long identityToken = Binder.clearCallingIdentity(); 558 try { 559 connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId, 560 text, partialInteractiveRegion, interactionId, callback, mFetchFlags, 561 interrogatingPid, interrogatingTid, spec); 562 return mSecurityPolicy.computeValidReportedPackages( 563 connection.getPackageName(), connection.getUid()); 564 } catch (RemoteException re) { 565 if (DEBUG) { 566 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()"); 567 } 568 } finally { 569 Binder.restoreCallingIdentity(identityToken); 570 // Recycle if passed to another process. 571 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 572 partialInteractiveRegion.recycle(); 573 } 574 } 575 return null; 576 } 577 578 @Override findAccessibilityNodeInfoByAccessibilityId( int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid, Bundle arguments)579 public String[] findAccessibilityNodeInfoByAccessibilityId( 580 int accessibilityWindowId, long accessibilityNodeId, int interactionId, 581 IAccessibilityInteractionConnectionCallback callback, int flags, 582 long interrogatingTid, Bundle arguments) throws RemoteException { 583 final int resolvedWindowId; 584 RemoteAccessibilityConnection connection; 585 Region partialInteractiveRegion = Region.obtain(); 586 MagnificationSpec spec; 587 synchronized (mLock) { 588 mUsesAccessibilityCache = true; 589 if (!hasRightsToCurrentUserLocked()) { 590 return null; 591 } 592 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 593 final boolean permissionGranted = 594 mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 595 mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId); 596 if (!permissionGranted) { 597 return null; 598 } else { 599 connection = mA11yWindowManager.getConnectionLocked( 600 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId); 601 if (connection == null) { 602 return null; 603 } 604 } 605 if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked( 606 resolvedWindowId, partialInteractiveRegion)) { 607 partialInteractiveRegion.recycle(); 608 partialInteractiveRegion = null; 609 } 610 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 611 } 612 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 613 return null; 614 } 615 final int interrogatingPid = Binder.getCallingPid(); 616 callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 617 interrogatingPid, interrogatingTid); 618 final long identityToken = Binder.clearCallingIdentity(); 619 try { 620 connection.getRemote().findAccessibilityNodeInfoByAccessibilityId( 621 accessibilityNodeId, partialInteractiveRegion, interactionId, callback, 622 mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments); 623 return mSecurityPolicy.computeValidReportedPackages( 624 connection.getPackageName(), connection.getUid()); 625 } catch (RemoteException re) { 626 if (DEBUG) { 627 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()"); 628 } 629 } finally { 630 Binder.restoreCallingIdentity(identityToken); 631 // Recycle if passed to another process. 632 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 633 partialInteractiveRegion.recycle(); 634 } 635 } 636 return null; 637 } 638 639 @Override findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)640 public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId, 641 int focusType, int interactionId, 642 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 643 throws RemoteException { 644 final int resolvedWindowId; 645 RemoteAccessibilityConnection connection; 646 Region partialInteractiveRegion = Region.obtain(); 647 MagnificationSpec spec; 648 synchronized (mLock) { 649 if (!hasRightsToCurrentUserLocked()) { 650 return null; 651 } 652 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked( 653 accessibilityWindowId, focusType); 654 final boolean permissionGranted = 655 mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 656 mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId); 657 if (!permissionGranted) { 658 return null; 659 } else { 660 connection = mA11yWindowManager.getConnectionLocked( 661 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId); 662 if (connection == null) { 663 return null; 664 } 665 } 666 if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked( 667 resolvedWindowId, partialInteractiveRegion)) { 668 partialInteractiveRegion.recycle(); 669 partialInteractiveRegion = null; 670 } 671 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 672 } 673 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 674 return null; 675 } 676 final int interrogatingPid = Binder.getCallingPid(); 677 callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 678 interrogatingPid, interrogatingTid); 679 final long identityToken = Binder.clearCallingIdentity(); 680 try { 681 connection.getRemote().findFocus(accessibilityNodeId, focusType, 682 partialInteractiveRegion, interactionId, callback, mFetchFlags, 683 interrogatingPid, interrogatingTid, spec); 684 return mSecurityPolicy.computeValidReportedPackages( 685 connection.getPackageName(), connection.getUid()); 686 } catch (RemoteException re) { 687 if (DEBUG) { 688 Slog.e(LOG_TAG, "Error calling findFocus()"); 689 } 690 } finally { 691 Binder.restoreCallingIdentity(identityToken); 692 // Recycle if passed to another process. 693 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 694 partialInteractiveRegion.recycle(); 695 } 696 } 697 return null; 698 } 699 700 @Override focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)701 public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId, 702 int direction, int interactionId, 703 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 704 throws RemoteException { 705 final int resolvedWindowId; 706 RemoteAccessibilityConnection connection; 707 Region partialInteractiveRegion = Region.obtain(); 708 MagnificationSpec spec; 709 synchronized (mLock) { 710 if (!hasRightsToCurrentUserLocked()) { 711 return null; 712 } 713 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 714 final boolean permissionGranted = 715 mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 716 mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId); 717 if (!permissionGranted) { 718 return null; 719 } else { 720 connection = mA11yWindowManager.getConnectionLocked( 721 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId); 722 if (connection == null) { 723 return null; 724 } 725 } 726 if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked( 727 resolvedWindowId, partialInteractiveRegion)) { 728 partialInteractiveRegion.recycle(); 729 partialInteractiveRegion = null; 730 } 731 spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId); 732 } 733 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 734 return null; 735 } 736 final int interrogatingPid = Binder.getCallingPid(); 737 callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId, 738 interrogatingPid, interrogatingTid); 739 final long identityToken = Binder.clearCallingIdentity(); 740 try { 741 connection.getRemote().focusSearch(accessibilityNodeId, direction, 742 partialInteractiveRegion, interactionId, callback, mFetchFlags, 743 interrogatingPid, interrogatingTid, spec); 744 return mSecurityPolicy.computeValidReportedPackages( 745 connection.getPackageName(), connection.getUid()); 746 } catch (RemoteException re) { 747 if (DEBUG) { 748 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()"); 749 } 750 } finally { 751 Binder.restoreCallingIdentity(identityToken); 752 // Recycle if passed to another process. 753 if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) { 754 partialInteractiveRegion.recycle(); 755 } 756 } 757 return null; 758 } 759 760 @Override sendGesture(int sequence, ParceledListSlice gestureSteps)761 public void sendGesture(int sequence, ParceledListSlice gestureSteps) { 762 } 763 764 @Override dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)765 public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) { 766 } 767 768 @Override performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)769 public boolean performAccessibilityAction(int accessibilityWindowId, 770 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 771 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 772 throws RemoteException { 773 final int resolvedWindowId; 774 synchronized (mLock) { 775 if (!hasRightsToCurrentUserLocked()) { 776 return false; 777 } 778 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId); 779 if (!mSecurityPolicy.canGetAccessibilityNodeInfoLocked( 780 mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId)) { 781 return false; 782 } 783 } 784 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 785 return false; 786 } 787 return performAccessibilityActionInternal( 788 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId, accessibilityNodeId, 789 action, arguments, interactionId, callback, mFetchFlags, interrogatingTid); 790 } 791 792 @Override performGlobalAction(int action)793 public boolean performGlobalAction(int action) { 794 synchronized (mLock) { 795 if (!hasRightsToCurrentUserLocked()) { 796 return false; 797 } 798 } 799 return mSystemActionPerformer.performSystemAction(action); 800 } 801 802 @Override getSystemActions()803 public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() { 804 synchronized (mLock) { 805 if (!hasRightsToCurrentUserLocked()) { 806 return Collections.emptyList(); 807 } 808 } 809 return mSystemActionPerformer.getSystemActions(); 810 } 811 812 @Override isFingerprintGestureDetectionAvailable()813 public boolean isFingerprintGestureDetectionAvailable() { 814 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 815 return false; 816 } 817 if (isCapturingFingerprintGestures()) { 818 FingerprintGestureDispatcher dispatcher = 819 mSystemSupport.getFingerprintGestureDispatcher(); 820 return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable(); 821 } 822 return false; 823 } 824 825 @Override getMagnificationScale(int displayId)826 public float getMagnificationScale(int displayId) { 827 synchronized (mLock) { 828 if (!hasRightsToCurrentUserLocked()) { 829 return 1.0f; 830 } 831 } 832 final long identity = Binder.clearCallingIdentity(); 833 try { 834 return mSystemSupport.getMagnificationController().getScale(displayId); 835 } finally { 836 Binder.restoreCallingIdentity(identity); 837 } 838 } 839 840 @Override getMagnificationRegion(int displayId)841 public Region getMagnificationRegion(int displayId) { 842 synchronized (mLock) { 843 final Region region = Region.obtain(); 844 if (!hasRightsToCurrentUserLocked()) { 845 return region; 846 } 847 MagnificationController magnificationController = 848 mSystemSupport.getMagnificationController(); 849 boolean registeredJustForThisCall = 850 registerMagnificationIfNeeded(displayId, magnificationController); 851 final long identity = Binder.clearCallingIdentity(); 852 try { 853 magnificationController.getMagnificationRegion(displayId, region); 854 return region; 855 } finally { 856 Binder.restoreCallingIdentity(identity); 857 if (registeredJustForThisCall) { 858 magnificationController.unregister(displayId); 859 } 860 } 861 } 862 } 863 864 @Override getMagnificationCenterX(int displayId)865 public float getMagnificationCenterX(int displayId) { 866 synchronized (mLock) { 867 if (!hasRightsToCurrentUserLocked()) { 868 return 0.0f; 869 } 870 MagnificationController magnificationController = 871 mSystemSupport.getMagnificationController(); 872 boolean registeredJustForThisCall = 873 registerMagnificationIfNeeded(displayId, magnificationController); 874 final long identity = Binder.clearCallingIdentity(); 875 try { 876 return magnificationController.getCenterX(displayId); 877 } finally { 878 Binder.restoreCallingIdentity(identity); 879 if (registeredJustForThisCall) { 880 magnificationController.unregister(displayId); 881 } 882 } 883 } 884 } 885 886 @Override getMagnificationCenterY(int displayId)887 public float getMagnificationCenterY(int displayId) { 888 synchronized (mLock) { 889 if (!hasRightsToCurrentUserLocked()) { 890 return 0.0f; 891 } 892 MagnificationController magnificationController = 893 mSystemSupport.getMagnificationController(); 894 boolean registeredJustForThisCall = 895 registerMagnificationIfNeeded(displayId, magnificationController); 896 final long identity = Binder.clearCallingIdentity(); 897 try { 898 return magnificationController.getCenterY(displayId); 899 } finally { 900 Binder.restoreCallingIdentity(identity); 901 if (registeredJustForThisCall) { 902 magnificationController.unregister(displayId); 903 } 904 } 905 } 906 } 907 registerMagnificationIfNeeded(int displayId, MagnificationController magnificationController)908 private boolean registerMagnificationIfNeeded(int displayId, 909 MagnificationController magnificationController) { 910 if (!magnificationController.isRegistered(displayId) 911 && mSecurityPolicy.canControlMagnification(this)) { 912 magnificationController.register(displayId); 913 return true; 914 } 915 return false; 916 } 917 918 @Override resetMagnification(int displayId, boolean animate)919 public boolean resetMagnification(int displayId, boolean animate) { 920 synchronized (mLock) { 921 if (!hasRightsToCurrentUserLocked()) { 922 return false; 923 } 924 if (!mSecurityPolicy.canControlMagnification(this)) { 925 return false; 926 } 927 } 928 final long identity = Binder.clearCallingIdentity(); 929 try { 930 MagnificationController magnificationController = 931 mSystemSupport.getMagnificationController(); 932 return (magnificationController.reset(displayId, animate) 933 || !magnificationController.isMagnifying(displayId)); 934 } finally { 935 Binder.restoreCallingIdentity(identity); 936 } 937 } 938 939 @Override setMagnificationScaleAndCenter(int displayId, float scale, float centerX, float centerY, boolean animate)940 public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX, 941 float centerY, boolean animate) { 942 synchronized (mLock) { 943 if (!hasRightsToCurrentUserLocked()) { 944 return false; 945 } 946 if (!mSecurityPolicy.canControlMagnification(this)) { 947 return false; 948 } 949 final long identity = Binder.clearCallingIdentity(); 950 try { 951 MagnificationController magnificationController = 952 mSystemSupport.getMagnificationController(); 953 if (!magnificationController.isRegistered(displayId)) { 954 magnificationController.register(displayId); 955 } 956 return magnificationController 957 .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId); 958 } finally { 959 Binder.restoreCallingIdentity(identity); 960 } 961 } 962 } 963 964 @Override setMagnificationCallbackEnabled(int displayId, boolean enabled)965 public void setMagnificationCallbackEnabled(int displayId, boolean enabled) { 966 mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled); 967 } 968 isMagnificationCallbackEnabled(int displayId)969 public boolean isMagnificationCallbackEnabled(int displayId) { 970 return mInvocationHandler.isMagnificationCallbackEnabled(displayId); 971 } 972 973 @Override setSoftKeyboardCallbackEnabled(boolean enabled)974 public void setSoftKeyboardCallbackEnabled(boolean enabled) { 975 mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled); 976 } 977 978 @Override takeScreenshot(int displayId, RemoteCallback callback)979 public void takeScreenshot(int displayId, RemoteCallback callback) { 980 final long currentTimestamp = SystemClock.uptimeMillis(); 981 if (mRequestTakeScreenshotTimestampMs != 0 982 && (currentTimestamp - mRequestTakeScreenshotTimestampMs) 983 <= AccessibilityService.ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS) { 984 sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT, 985 callback); 986 return; 987 } 988 mRequestTakeScreenshotTimestampMs = currentTimestamp; 989 990 synchronized (mLock) { 991 if (!hasRightsToCurrentUserLocked()) { 992 sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, 993 callback); 994 return; 995 } 996 997 if (!mSecurityPolicy.canTakeScreenshotLocked(this)) { 998 throw new SecurityException("Services don't have the capability of taking" 999 + " the screenshot."); 1000 } 1001 } 1002 1003 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 1004 sendScreenshotFailure( 1005 AccessibilityService.ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS, 1006 callback); 1007 return; 1008 } 1009 1010 // Private virtual displays are created by the ap and is not allowed to access by other 1011 // aps. We assume the contents on this display should not be captured. 1012 final DisplayManager displayManager = 1013 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); 1014 final Display display = displayManager.getDisplay(displayId); 1015 if ((display == null) || (display.getType() == Display.TYPE_VIRTUAL 1016 && (display.getFlags() & Display.FLAG_PRIVATE) != 0)) { 1017 sendScreenshotFailure( 1018 AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback); 1019 return; 1020 } 1021 1022 final long identity = Binder.clearCallingIdentity(); 1023 try { 1024 mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> { 1025 final ScreenshotGraphicBuffer screenshotBuffer = LocalServices 1026 .getService(DisplayManagerInternal.class).userScreenshot(displayId); 1027 if (screenshotBuffer != null) { 1028 sendScreenshotSuccess(screenshotBuffer, callback); 1029 } else { 1030 sendScreenshotFailure( 1031 AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback); 1032 } 1033 }, null).recycleOnUse()); 1034 } finally { 1035 Binder.restoreCallingIdentity(identity); 1036 } 1037 } 1038 sendScreenshotSuccess(ScreenshotGraphicBuffer screenshotBuffer, RemoteCallback callback)1039 private void sendScreenshotSuccess(ScreenshotGraphicBuffer screenshotBuffer, 1040 RemoteCallback callback) { 1041 final GraphicBuffer graphicBuffer = screenshotBuffer.getGraphicBuffer(); 1042 try (HardwareBuffer hardwareBuffer = 1043 HardwareBuffer.createFromGraphicBuffer(graphicBuffer)) { 1044 final ParcelableColorSpace colorSpace = 1045 new ParcelableColorSpace(screenshotBuffer.getColorSpace()); 1046 1047 final Bundle payload = new Bundle(); 1048 payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS, 1049 AccessibilityService.TAKE_SCREENSHOT_SUCCESS); 1050 payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER, 1051 hardwareBuffer); 1052 payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace); 1053 payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP, 1054 SystemClock.uptimeMillis()); 1055 1056 // Send back the result. 1057 callback.sendResult(payload); 1058 hardwareBuffer.close(); 1059 } 1060 } 1061 sendScreenshotFailure(@ccessibilityService.ScreenshotErrorCode int errorCode, RemoteCallback callback)1062 private void sendScreenshotFailure(@AccessibilityService.ScreenshotErrorCode int errorCode, 1063 RemoteCallback callback) { 1064 mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> { 1065 final Bundle payload = new Bundle(); 1066 payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS, errorCode); 1067 // Send back the result. 1068 callback.sendResult(payload); 1069 }, null).recycleOnUse()); 1070 } 1071 1072 @Override dump(FileDescriptor fd, final PrintWriter pw, String[] args)1073 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 1074 if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; 1075 synchronized (mLock) { 1076 pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo() 1077 .loadLabel(mContext.getPackageManager())); 1078 pw.append(", feedbackType" 1079 + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType)); 1080 pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities()); 1081 pw.append(", eventTypes=" 1082 + AccessibilityEvent.eventTypeToString(mEventTypes)); 1083 pw.append(", notificationTimeout=" + mNotificationTimeout); 1084 pw.append(", requestA11yBtn=" + mRequestAccessibilityButton); 1085 pw.append("]"); 1086 } 1087 } 1088 onAdded()1089 public void onAdded() { 1090 final Display[] displays = mDisplayManager.getDisplays(); 1091 for (int i = 0; i < displays.length; i++) { 1092 final int displayId = displays[i].getDisplayId(); 1093 onDisplayAdded(displayId); 1094 } 1095 } 1096 1097 /** 1098 * Called whenever a logical display has been added to the system. Add a window token for adding 1099 * an accessibility overlay. 1100 * 1101 * @param displayId The id of the logical display that was added. 1102 */ onDisplayAdded(int displayId)1103 public void onDisplayAdded(int displayId) { 1104 final long identity = Binder.clearCallingIdentity(); 1105 try { 1106 final IBinder overlayWindowToken = new Binder(); 1107 mWindowManagerService.addWindowToken(overlayWindowToken, TYPE_ACCESSIBILITY_OVERLAY, 1108 displayId); 1109 synchronized (mLock) { 1110 mOverlayWindowTokens.put(displayId, overlayWindowToken); 1111 } 1112 } finally { 1113 Binder.restoreCallingIdentity(identity); 1114 } 1115 } 1116 onRemoved()1117 public void onRemoved() { 1118 final Display[] displays = mDisplayManager.getDisplays(); 1119 for (int i = 0; i < displays.length; i++) { 1120 final int displayId = displays[i].getDisplayId(); 1121 onDisplayRemoved(displayId); 1122 } 1123 } 1124 1125 /** 1126 * Called whenever a logical display has been removed from the system. Remove a window token for 1127 * removing an accessibility overlay. 1128 * 1129 * @param displayId The id of the logical display that was added. 1130 */ onDisplayRemoved(int displayId)1131 public void onDisplayRemoved(int displayId) { 1132 final long identity = Binder.clearCallingIdentity(); 1133 try { 1134 mWindowManagerService.removeWindowToken(mOverlayWindowTokens.get(displayId), true, 1135 displayId); 1136 synchronized (mLock) { 1137 mOverlayWindowTokens.remove(displayId); 1138 } 1139 } finally { 1140 Binder.restoreCallingIdentity(identity); 1141 } 1142 } 1143 1144 /** 1145 * Gets overlay window token by the display Id. 1146 * 1147 * @param displayId The id of the logical display that was added. 1148 * @return window token. 1149 */ 1150 @Override getOverlayWindowToken(int displayId)1151 public IBinder getOverlayWindowToken(int displayId) { 1152 synchronized (mLock) { 1153 return mOverlayWindowTokens.get(displayId); 1154 } 1155 } 1156 1157 /** 1158 * Gets windowId of given token. 1159 * 1160 * @param token The token 1161 * @return window id 1162 */ 1163 @Override getWindowIdForLeashToken(@onNull IBinder token)1164 public int getWindowIdForLeashToken(@NonNull IBinder token) { 1165 synchronized (mLock) { 1166 return mA11yWindowManager.getWindowIdLocked(token); 1167 } 1168 } 1169 resetLocked()1170 public void resetLocked() { 1171 mSystemSupport.getKeyEventDispatcher().flush(this); 1172 try { 1173 // Clear the proxy in the other process so this 1174 // IAccessibilityServiceConnection can be garbage collected. 1175 if (mServiceInterface != null) { 1176 mServiceInterface.init(null, mId, null); 1177 } 1178 } catch (RemoteException re) { 1179 /* ignore */ 1180 } 1181 if (mService != null) { 1182 mService.unlinkToDeath(this, 0); 1183 mService = null; 1184 } 1185 1186 mServiceInterface = null; 1187 mReceivedAccessibilityButtonCallbackSinceBind = false; 1188 } 1189 isConnectedLocked()1190 public boolean isConnectedLocked() { 1191 return (mService != null); 1192 } 1193 notifyAccessibilityEvent(AccessibilityEvent event)1194 public void notifyAccessibilityEvent(AccessibilityEvent event) { 1195 synchronized (mLock) { 1196 final int eventType = event.getEventType(); 1197 1198 final boolean serviceWantsEvent = wantsEventLocked(event); 1199 final boolean requiredForCacheConsistency = mUsesAccessibilityCache 1200 && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0); 1201 if (!serviceWantsEvent && !requiredForCacheConsistency) { 1202 return; 1203 } 1204 1205 if (!mSecurityPolicy.checkAccessibilityAccess(this)) { 1206 return; 1207 } 1208 // Make a copy since during dispatch it is possible the event to 1209 // be modified to remove its source if the receiving service does 1210 // not have permission to access the window content. 1211 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event); 1212 Message message; 1213 if ((mNotificationTimeout > 0) 1214 && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) { 1215 // Allow at most one pending event 1216 final AccessibilityEvent oldEvent = mPendingEvents.get(eventType); 1217 mPendingEvents.put(eventType, newEvent); 1218 if (oldEvent != null) { 1219 mEventDispatchHandler.removeMessages(eventType); 1220 oldEvent.recycle(); 1221 } 1222 message = mEventDispatchHandler.obtainMessage(eventType); 1223 } else { 1224 // Send all messages, bypassing mPendingEvents 1225 message = mEventDispatchHandler.obtainMessage(eventType, newEvent); 1226 } 1227 message.arg1 = serviceWantsEvent ? 1 : 0; 1228 1229 mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout); 1230 } 1231 } 1232 1233 /** 1234 * Determines if given event can be dispatched to a service based on the package of the 1235 * event source. Specifically, a service is notified if it is interested in events from the 1236 * package. 1237 * 1238 * @param event The event. 1239 * @return True if the listener should be notified, false otherwise. 1240 */ wantsEventLocked(AccessibilityEvent event)1241 private boolean wantsEventLocked(AccessibilityEvent event) { 1242 1243 if (!canReceiveEventsLocked()) { 1244 return false; 1245 } 1246 1247 if ((event.getWindowId() != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) 1248 && !event.isImportantForAccessibility() 1249 && (mFetchFlags & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 1250 return false; 1251 } 1252 1253 int eventType = event.getEventType(); 1254 if ((mEventTypes & eventType) != eventType) { 1255 return false; 1256 } 1257 1258 Set<String> packageNames = mPackageNames; 1259 String packageName = (event.getPackageName() != null) 1260 ? event.getPackageName().toString() : null; 1261 1262 return (packageNames.isEmpty() || packageNames.contains(packageName)); 1263 } 1264 1265 /** 1266 * Notifies an accessibility service client for a scheduled event given the event type. 1267 * 1268 * @param eventType The type of the event to dispatch. 1269 */ notifyAccessibilityEventInternal( int eventType, AccessibilityEvent event, boolean serviceWantsEvent)1270 private void notifyAccessibilityEventInternal( 1271 int eventType, 1272 AccessibilityEvent event, 1273 boolean serviceWantsEvent) { 1274 IAccessibilityServiceClient listener; 1275 1276 synchronized (mLock) { 1277 listener = mServiceInterface; 1278 1279 // If the service died/was disabled while the message for dispatching 1280 // the accessibility event was propagating the listener may be null. 1281 if (listener == null) { 1282 return; 1283 } 1284 1285 // There are two ways we notify for events, throttled AND non-throttled. If we 1286 // are not throttling, then messages come with events, which we handle with 1287 // minimal fuss. 1288 if (event == null) { 1289 // We are throttling events, so we'll send the event for this type in 1290 // mPendingEvents as long as it it's null. It can only null due to a race 1291 // condition: 1292 // 1293 // 1) A binder thread calls notifyAccessibilityServiceDelayedLocked 1294 // which posts a message for dispatching an event and stores the event 1295 // in mPendingEvents. 1296 // 2) The message is pulled from the queue by the handler on the service 1297 // thread and this method is just about to acquire the lock. 1298 // 3) Another binder thread acquires the lock in notifyAccessibilityEvent 1299 // 4) notifyAccessibilityEvent recycles the event that this method was about 1300 // to process, replaces it with a new one, and posts a second message 1301 // 5) This method grabs the new event, processes it, and removes it from 1302 // mPendingEvents 1303 // 6) The second message dispatched in (4) arrives, but the event has been 1304 // remvoved in (5). 1305 event = mPendingEvents.get(eventType); 1306 if (event == null) { 1307 return; 1308 } 1309 mPendingEvents.remove(eventType); 1310 } 1311 if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) { 1312 event.setConnectionId(mId); 1313 } else { 1314 event.setSource((View) null); 1315 } 1316 event.setSealed(true); 1317 } 1318 1319 try { 1320 listener.onAccessibilityEvent(event, serviceWantsEvent); 1321 if (DEBUG) { 1322 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); 1323 } 1324 } catch (RemoteException re) { 1325 Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re); 1326 } finally { 1327 event.recycle(); 1328 } 1329 } 1330 notifyGesture(AccessibilityGestureEvent gestureEvent)1331 public void notifyGesture(AccessibilityGestureEvent gestureEvent) { 1332 mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE, 1333 gestureEvent).sendToTarget(); 1334 } 1335 notifySystemActionsChangedLocked()1336 public void notifySystemActionsChangedLocked() { 1337 mInvocationHandler.sendEmptyMessage( 1338 InvocationHandler.MSG_ON_SYSTEM_ACTIONS_CHANGED); 1339 } 1340 notifyClearAccessibilityNodeInfoCache()1341 public void notifyClearAccessibilityNodeInfoCache() { 1342 mInvocationHandler.sendEmptyMessage( 1343 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE); 1344 } 1345 notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1346 public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, 1347 float scale, float centerX, float centerY) { 1348 mInvocationHandler 1349 .notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY); 1350 } 1351 notifySoftKeyboardShowModeChangedLocked(int showState)1352 public void notifySoftKeyboardShowModeChangedLocked(int showState) { 1353 mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState); 1354 } 1355 notifyAccessibilityButtonClickedLocked(int displayId)1356 public void notifyAccessibilityButtonClickedLocked(int displayId) { 1357 mInvocationHandler.notifyAccessibilityButtonClickedLocked(displayId); 1358 } 1359 notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1360 public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) { 1361 mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available); 1362 } 1363 1364 /** 1365 * Called by the invocation handler to notify the service that the 1366 * state of magnification has changed. 1367 */ notifyMagnificationChangedInternal(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1368 private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region, 1369 float scale, float centerX, float centerY) { 1370 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1371 if (listener != null) { 1372 try { 1373 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY); 1374 } catch (RemoteException re) { 1375 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re); 1376 } 1377 } 1378 } 1379 1380 /** 1381 * Called by the invocation handler to notify the service that the state of the soft 1382 * keyboard show mode has changed. 1383 */ notifySoftKeyboardShowModeChangedInternal(int showState)1384 private void notifySoftKeyboardShowModeChangedInternal(int showState) { 1385 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1386 if (listener != null) { 1387 try { 1388 listener.onSoftKeyboardShowModeChanged(showState); 1389 } catch (RemoteException re) { 1390 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService, 1391 re); 1392 } 1393 } 1394 } 1395 notifyAccessibilityButtonClickedInternal(int displayId)1396 private void notifyAccessibilityButtonClickedInternal(int displayId) { 1397 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1398 if (listener != null) { 1399 try { 1400 listener.onAccessibilityButtonClicked(displayId); 1401 } catch (RemoteException re) { 1402 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re); 1403 } 1404 } 1405 } 1406 notifyAccessibilityButtonAvailabilityChangedInternal(boolean available)1407 private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) { 1408 // Only notify the service if it's not been notified or the state has changed 1409 if (mReceivedAccessibilityButtonCallbackSinceBind 1410 && (mLastAccessibilityButtonCallbackState == available)) { 1411 return; 1412 } 1413 mReceivedAccessibilityButtonCallbackSinceBind = true; 1414 mLastAccessibilityButtonCallbackState = available; 1415 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1416 if (listener != null) { 1417 try { 1418 listener.onAccessibilityButtonAvailabilityChanged(available); 1419 } catch (RemoteException re) { 1420 Slog.e(LOG_TAG, 1421 "Error sending accessibility button availability change to " + mService, 1422 re); 1423 } 1424 } 1425 } 1426 notifyGestureInternal(AccessibilityGestureEvent gestureInfo)1427 private void notifyGestureInternal(AccessibilityGestureEvent gestureInfo) { 1428 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1429 if (listener != null) { 1430 try { 1431 listener.onGesture(gestureInfo); 1432 } catch (RemoteException re) { 1433 Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo 1434 + " to " + mService, re); 1435 } 1436 } 1437 } 1438 notifySystemActionsChangedInternal()1439 private void notifySystemActionsChangedInternal() { 1440 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1441 if (listener != null) { 1442 try { 1443 listener.onSystemActionsChanged(); 1444 } catch (RemoteException re) { 1445 Slog.e(LOG_TAG, "Error sending system actions change to " + mService, 1446 re); 1447 } 1448 } 1449 } 1450 notifyClearAccessibilityCacheInternal()1451 private void notifyClearAccessibilityCacheInternal() { 1452 final IAccessibilityServiceClient listener = getServiceInterfaceSafely(); 1453 if (listener != null) { 1454 try { 1455 listener.clearAccessibilityCache(); 1456 } catch (RemoteException re) { 1457 Slog.e(LOG_TAG, "Error during requesting accessibility info cache" 1458 + " to be cleared.", re); 1459 } 1460 } 1461 } 1462 getServiceInterfaceSafely()1463 private IAccessibilityServiceClient getServiceInterfaceSafely() { 1464 synchronized (mLock) { 1465 return mServiceInterface; 1466 } 1467 } 1468 resolveAccessibilityWindowIdLocked(int accessibilityWindowId)1469 private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) { 1470 if (accessibilityWindowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) { 1471 return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked()); 1472 } 1473 return accessibilityWindowId; 1474 } 1475 resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)1476 private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) { 1477 if (windowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) { 1478 return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked()); 1479 } 1480 if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) { 1481 return mA11yWindowManager.getFocusedWindowId(focusType); 1482 } 1483 return windowId; 1484 } 1485 1486 /** 1487 * Request that the system make sure windows are available to interrogate. 1488 * 1489 * @param displayId The logical display id. 1490 */ ensureWindowsAvailableTimedLocked(int displayId)1491 private void ensureWindowsAvailableTimedLocked(int displayId) { 1492 if (mA11yWindowManager.getWindowListLocked(displayId) != null) { 1493 return; 1494 } 1495 // If we have no registered callback, update the state we 1496 // we may have to register one but it didn't happen yet. 1497 if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) { 1498 // Invokes client change to make sure tracking window enabled. 1499 mSystemSupport.onClientChangeLocked(false); 1500 } 1501 // We have no windows but do not care about them, done. 1502 if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) { 1503 return; 1504 } 1505 1506 // Wait for the windows with a timeout. 1507 final long startMillis = SystemClock.uptimeMillis(); 1508 while (mA11yWindowManager.getWindowListLocked(displayId) == null) { 1509 final long elapsedMillis = SystemClock.uptimeMillis() - startMillis; 1510 final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis; 1511 if (remainMillis <= 0) { 1512 return; 1513 } 1514 try { 1515 mLock.wait(remainMillis); 1516 } catch (InterruptedException ie) { 1517 /* ignore */ 1518 } 1519 } 1520 } 1521 1522 /** 1523 * Perform the specified accessibility action 1524 * 1525 * @param resolvedWindowId The window ID 1526 * [Other parameters match the method on IAccessibilityServiceConnection] 1527 * 1528 * @return Whether or not the action could be sent to the app process 1529 */ performAccessibilityActionInternal(int userId, int resolvedWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags, long interrogatingTid)1530 private boolean performAccessibilityActionInternal(int userId, int resolvedWindowId, 1531 long accessibilityNodeId, int action, Bundle arguments, int interactionId, 1532 IAccessibilityInteractionConnectionCallback callback, int fetchFlags, 1533 long interrogatingTid) { 1534 RemoteAccessibilityConnection connection; 1535 IBinder activityToken = null; 1536 synchronized (mLock) { 1537 connection = mA11yWindowManager.getConnectionLocked(userId, resolvedWindowId); 1538 if (connection == null) { 1539 return false; 1540 } 1541 final boolean isA11yFocusAction = (action == ACTION_ACCESSIBILITY_FOCUS) 1542 || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS); 1543 if (!isA11yFocusAction) { 1544 final WindowInfo windowInfo = 1545 mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId); 1546 if (windowInfo != null) activityToken = windowInfo.activityToken; 1547 } 1548 final AccessibilityWindowInfo a11yWindowInfo = 1549 mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId); 1550 if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode() 1551 && mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null 1552 && !isA11yFocusAction) { 1553 connection = mA11yWindowManager.getPictureInPictureActionReplacingConnection(); 1554 } 1555 } 1556 final int interrogatingPid = Binder.getCallingPid(); 1557 final long identityToken = Binder.clearCallingIdentity(); 1558 try { 1559 // Regardless of whether or not the action succeeds, it was generated by an 1560 // accessibility service that is driven by user actions, so note user activity. 1561 mPowerManager.userActivity(SystemClock.uptimeMillis(), 1562 PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0); 1563 1564 if (action == ACTION_CLICK || action == ACTION_LONG_CLICK) { 1565 mA11yWindowManager.notifyOutsideTouch(userId, resolvedWindowId); 1566 } 1567 if (activityToken != null) { 1568 LocalServices.getService(ActivityTaskManagerInternal.class) 1569 .setFocusedActivity(activityToken); 1570 } 1571 connection.getRemote().performAccessibilityAction(accessibilityNodeId, action, 1572 arguments, interactionId, callback, fetchFlags, interrogatingPid, 1573 interrogatingTid); 1574 } catch (RemoteException re) { 1575 if (DEBUG) { 1576 Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re); 1577 } 1578 return false; 1579 } finally { 1580 Binder.restoreCallingIdentity(identityToken); 1581 } 1582 return true; 1583 } 1584 1585 /** 1586 * Replace the interaction callback if needed, for example if the window is in picture- 1587 * in-picture mode and needs its nodes replaced. 1588 * 1589 * @param originalCallback The callback we were planning to use 1590 * @param resolvedWindowId The ID of the window we're calling 1591 * @param interactionId The id for the original callback 1592 * @param interrogatingPid Process ID of requester 1593 * @param interrogatingTid Thread ID of requester 1594 * 1595 * @return The callback to use, which may be the original one. 1596 */ replaceCallbackIfNeeded( IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId, int interactionId, int interrogatingPid, long interrogatingTid)1597 private IAccessibilityInteractionConnectionCallback replaceCallbackIfNeeded( 1598 IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId, 1599 int interactionId, int interrogatingPid, long interrogatingTid) { 1600 final RemoteAccessibilityConnection pipActionReplacingConnection = 1601 mA11yWindowManager.getPictureInPictureActionReplacingConnection(); 1602 synchronized (mLock) { 1603 final AccessibilityWindowInfo windowInfo = 1604 mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId); 1605 if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode() 1606 || (pipActionReplacingConnection == null)) { 1607 return originalCallback; 1608 } 1609 } 1610 return new ActionReplacingCallback(originalCallback, 1611 pipActionReplacingConnection.getRemote(), interactionId, 1612 interrogatingPid, interrogatingTid); 1613 } 1614 getWindowsByDisplayLocked(int displayId)1615 private List<AccessibilityWindowInfo> getWindowsByDisplayLocked(int displayId) { 1616 final List<AccessibilityWindowInfo> internalWindowList = 1617 mA11yWindowManager.getWindowListLocked(displayId); 1618 if (internalWindowList == null) { 1619 return null; 1620 } 1621 final List<AccessibilityWindowInfo> returnedWindowList = new ArrayList<>(); 1622 final int windowCount = internalWindowList.size(); 1623 for (int i = 0; i < windowCount; i++) { 1624 AccessibilityWindowInfo window = internalWindowList.get(i); 1625 AccessibilityWindowInfo windowClone = 1626 AccessibilityWindowInfo.obtain(window); 1627 windowClone.setConnectionId(mId); 1628 returnedWindowList.add(windowClone); 1629 } 1630 return returnedWindowList; 1631 } 1632 getComponentName()1633 public ComponentName getComponentName() { 1634 return mComponentName; 1635 } 1636 1637 private final class InvocationHandler extends Handler { 1638 public static final int MSG_ON_GESTURE = 1; 1639 public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2; 1640 1641 private static final int MSG_ON_MAGNIFICATION_CHANGED = 5; 1642 private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6; 1643 private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7; 1644 private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8; 1645 private static final int MSG_ON_SYSTEM_ACTIONS_CHANGED = 9; 1646 1647 /** List of magnification callback states, mapping from displayId -> Boolean */ 1648 @GuardedBy("mlock") 1649 private final SparseArray<Boolean> mMagnificationCallbackState = new SparseArray<>(0); 1650 private boolean mIsSoftKeyboardCallbackEnabled = false; 1651 InvocationHandler(Looper looper)1652 public InvocationHandler(Looper looper) { 1653 super(looper, null, true); 1654 } 1655 1656 @Override handleMessage(Message message)1657 public void handleMessage(Message message) { 1658 final int type = message.what; 1659 switch (type) { 1660 case MSG_ON_GESTURE: { 1661 notifyGestureInternal((AccessibilityGestureEvent) message.obj); 1662 } break; 1663 1664 case MSG_CLEAR_ACCESSIBILITY_CACHE: { 1665 notifyClearAccessibilityCacheInternal(); 1666 } break; 1667 1668 case MSG_ON_MAGNIFICATION_CHANGED: { 1669 final SomeArgs args = (SomeArgs) message.obj; 1670 final Region region = (Region) args.arg1; 1671 final float scale = (float) args.arg2; 1672 final float centerX = (float) args.arg3; 1673 final float centerY = (float) args.arg4; 1674 final int displayId = args.argi1; 1675 notifyMagnificationChangedInternal(displayId, region, scale, centerX, centerY); 1676 args.recycle(); 1677 } break; 1678 1679 case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: { 1680 final int showState = (int) message.arg1; 1681 notifySoftKeyboardShowModeChangedInternal(showState); 1682 } break; 1683 1684 case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: { 1685 final int displayId = (int) message.arg1; 1686 notifyAccessibilityButtonClickedInternal(displayId); 1687 } break; 1688 1689 case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: { 1690 final boolean available = (message.arg1 != 0); 1691 notifyAccessibilityButtonAvailabilityChangedInternal(available); 1692 } break; 1693 case MSG_ON_SYSTEM_ACTIONS_CHANGED: { 1694 notifySystemActionsChangedInternal(); 1695 break; 1696 } 1697 default: { 1698 throw new IllegalArgumentException("Unknown message: " + type); 1699 } 1700 } 1701 } 1702 notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1703 public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region, 1704 float scale, float centerX, float centerY) { 1705 synchronized (mLock) { 1706 if (mMagnificationCallbackState.get(displayId) == null) { 1707 return; 1708 } 1709 } 1710 1711 final SomeArgs args = SomeArgs.obtain(); 1712 args.arg1 = region; 1713 args.arg2 = scale; 1714 args.arg3 = centerX; 1715 args.arg4 = centerY; 1716 args.argi1 = displayId; 1717 1718 final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args); 1719 msg.sendToTarget(); 1720 } 1721 setMagnificationCallbackEnabled(int displayId, boolean enabled)1722 public void setMagnificationCallbackEnabled(int displayId, boolean enabled) { 1723 synchronized (mLock) { 1724 if (enabled) { 1725 mMagnificationCallbackState.put(displayId, true); 1726 } else { 1727 mMagnificationCallbackState.remove(displayId); 1728 } 1729 } 1730 } 1731 isMagnificationCallbackEnabled(int displayId)1732 public boolean isMagnificationCallbackEnabled(int displayId) { 1733 synchronized (mLock) { 1734 return mMagnificationCallbackState.get(displayId) != null; 1735 } 1736 } 1737 notifySoftKeyboardShowModeChangedLocked(int showState)1738 public void notifySoftKeyboardShowModeChangedLocked(int showState) { 1739 if (!mIsSoftKeyboardCallbackEnabled) { 1740 return; 1741 } 1742 1743 final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0); 1744 msg.sendToTarget(); 1745 } 1746 setSoftKeyboardCallbackEnabled(boolean enabled)1747 public void setSoftKeyboardCallbackEnabled(boolean enabled) { 1748 mIsSoftKeyboardCallbackEnabled = enabled; 1749 } 1750 notifyAccessibilityButtonClickedLocked(int displayId)1751 public void notifyAccessibilityButtonClickedLocked(int displayId) { 1752 final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED, displayId, 0); 1753 msg.sendToTarget(); 1754 } 1755 notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1756 public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) { 1757 final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED, 1758 (available ? 1 : 0), 0); 1759 msg.sendToTarget(); 1760 } 1761 } 1762 isServiceHandlesDoubleTapEnabled()1763 public boolean isServiceHandlesDoubleTapEnabled() { 1764 return mServiceHandlesDoubleTap; 1765 } 1766 isMultiFingerGesturesEnabled()1767 public boolean isMultiFingerGesturesEnabled() { 1768 return mRequestMultiFingerGestures; 1769 } 1770 1771 @Override setGestureDetectionPassthroughRegion(int displayId, Region region)1772 public void setGestureDetectionPassthroughRegion(int displayId, Region region) { 1773 mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region); 1774 } 1775 1776 @Override setTouchExplorationPassthroughRegion(int displayId, Region region)1777 public void setTouchExplorationPassthroughRegion(int displayId, Region region) { 1778 mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region); 1779 } 1780 } 1781