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