1 /* 2 * Copyright (C) 2019 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.AccessibilityTrace.FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION; 20 import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; 21 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; 22 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED; 23 24 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; 25 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.graphics.Region; 29 import android.os.Binder; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Process; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.text.TextUtils; 36 import android.util.ArrayMap; 37 import android.util.Slog; 38 import android.util.SparseArray; 39 import android.view.Display; 40 import android.view.IWindow; 41 import android.view.WindowInfo; 42 import android.view.WindowManager; 43 import android.view.accessibility.AccessibilityEvent; 44 import android.view.accessibility.AccessibilityNodeInfo; 45 import android.view.accessibility.AccessibilityWindowInfo; 46 import android.view.accessibility.IAccessibilityInteractionConnection; 47 48 import com.android.internal.annotations.VisibleForTesting; 49 import com.android.server.accessibility.AccessibilitySecurityPolicy.AccessibilityUserManager; 50 import com.android.server.wm.WindowManagerInternal; 51 52 import java.io.FileDescriptor; 53 import java.io.PrintWriter; 54 import java.util.ArrayList; 55 import java.util.Collections; 56 import java.util.List; 57 58 /** 59 * This class provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and 60 * {@link WindowInfo}s. 61 */ 62 public class AccessibilityWindowManager { 63 private static final String LOG_TAG = "AccessibilityWindowManager"; 64 private static final boolean DEBUG = false; 65 66 private static int sNextWindowId; 67 68 private final Object mLock; 69 private final Handler mHandler; 70 private final WindowManagerInternal mWindowManagerInternal; 71 private final AccessibilityEventSender mAccessibilityEventSender; 72 private final AccessibilitySecurityPolicy mSecurityPolicy; 73 private final AccessibilityUserManager mAccessibilityUserManager; 74 private final AccessibilityTraceManager mTraceManager; 75 76 // Connections and window tokens for cross-user windows 77 private final SparseArray<RemoteAccessibilityConnection> 78 mGlobalInteractionConnections = new SparseArray<>(); 79 private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>(); 80 81 // Connections and window tokens for per-user windows, indexed as one sparse array per user 82 private final SparseArray<SparseArray<RemoteAccessibilityConnection>> 83 mInteractionConnections = new SparseArray<>(); 84 private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>(); 85 86 private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection; 87 // There is only one active window in the system. It is updated when the top focused window 88 // of the top focused display changes and when we receive a TYPE_WINDOW_STATE_CHANGED event. 89 private int mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 90 // There is only one top focused window in the system. It is updated when the window manager 91 // updates the window lists. 92 private int mTopFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 93 private int mAccessibilityFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 94 private long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 95 // The top focused display and window token updated with the callback of window lists change. 96 private int mTopFocusedDisplayId; 97 private IBinder mTopFocusedWindowToken; 98 // The display has the accessibility focused window currently. 99 private int mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY; 100 101 private boolean mTouchInteractionInProgress; 102 103 /** List of Display Windows Observer, mapping from displayId -> DisplayWindowsObserver. */ 104 private final SparseArray<DisplayWindowsObserver> mDisplayWindowsObservers = 105 new SparseArray<>(); 106 107 /** 108 * Map of host view and embedded hierarchy, mapping from leash token of its ViewRootImpl. 109 * The key is the token from embedded hierarchy, and the value is the token from its host. 110 */ 111 private final ArrayMap<IBinder, IBinder> mHostEmbeddedMap = new ArrayMap<>(); 112 113 /** 114 * Map of window id and view hierarchy. 115 * The key is the window id when the ViewRootImpl register to accessibility, and the value is 116 * its leash token. 117 */ 118 private final SparseArray<IBinder> mWindowIdMap = new SparseArray<>(); 119 120 /** 121 * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to 122 * receive {@link WindowInfo}s from window manager when there's an accessibility change in 123 * window and holds window lists information per display. 124 */ 125 private final class DisplayWindowsObserver implements 126 WindowManagerInternal.WindowsForAccessibilityCallback { 127 128 private final int mDisplayId; 129 private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById = 130 new SparseArray<>(); 131 private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>(); 132 private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>(); 133 private List<AccessibilityWindowInfo> mWindows; 134 private boolean mTrackingWindows = false; 135 private boolean mHasWatchOutsideTouchWindow; 136 137 /** 138 * Constructor for DisplayWindowsObserver. 139 */ DisplayWindowsObserver(int displayId)140 DisplayWindowsObserver(int displayId) { 141 mDisplayId = displayId; 142 } 143 144 /** 145 * Starts tracking windows changes from window manager by registering callback. 146 * 147 * @return true if callback registers successful. 148 */ startTrackingWindowsLocked()149 boolean startTrackingWindowsLocked() { 150 boolean result = true; 151 152 if (!mTrackingWindows) { 153 // Turns on the flag before setup the callback. 154 // In some cases, onWindowsForAccessibilityChanged will be called immediately in 155 // setWindowsForAccessibilityCallback. We'll lost windows if flag is false. 156 mTrackingWindows = true; 157 if (traceWMEnabled()) { 158 logTraceWM("setWindowsForAccessibilityCallback", 159 "displayId=" + mDisplayId + ";callback=" + this); 160 } 161 result = mWindowManagerInternal.setWindowsForAccessibilityCallback( 162 mDisplayId, this); 163 if (!result) { 164 mTrackingWindows = false; 165 Slog.w(LOG_TAG, "set windowsObserver callbacks fail, displayId:" 166 + mDisplayId); 167 } 168 } 169 return result; 170 } 171 172 /** 173 * Stops tracking windows changes from window manager, and clear all windows info. 174 */ stopTrackingWindowsLocked()175 void stopTrackingWindowsLocked() { 176 if (mTrackingWindows) { 177 if (traceWMEnabled()) { 178 logTraceWM("setWindowsForAccessibilityCallback", 179 "displayId=" + mDisplayId + ";callback=null"); 180 } 181 mWindowManagerInternal.setWindowsForAccessibilityCallback( 182 mDisplayId, null); 183 mTrackingWindows = false; 184 clearWindowsLocked(); 185 } 186 } 187 188 /** 189 * Returns true if windows changes tracking. 190 * 191 * @return true if windows changes tracking 192 */ isTrackingWindowsLocked()193 boolean isTrackingWindowsLocked() { 194 return mTrackingWindows; 195 } 196 197 /** 198 * Returns accessibility windows. 199 * @return accessibility windows. 200 */ 201 @Nullable getWindowListLocked()202 List<AccessibilityWindowInfo> getWindowListLocked() { 203 return mWindows; 204 } 205 206 /** 207 * Returns accessibility window info according to given windowId. 208 * 209 * @param windowId The windowId 210 * @return The accessibility window info 211 */ 212 @Nullable findA11yWindowInfoByIdLocked(int windowId)213 AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { 214 return mA11yWindowInfoById.get(windowId); 215 } 216 217 /** 218 * Returns the window info according to given windowId. 219 * 220 * @param windowId The windowId 221 * @return The window info 222 */ 223 @Nullable findWindowInfoByIdLocked(int windowId)224 WindowInfo findWindowInfoByIdLocked(int windowId) { 225 return mWindowInfoById.get(windowId); 226 } 227 228 /** 229 * Returns {@link AccessibilityWindowInfo} of PIP window. 230 * 231 * @return PIP accessibility window info 232 */ 233 @Nullable getPictureInPictureWindowLocked()234 AccessibilityWindowInfo getPictureInPictureWindowLocked() { 235 if (mWindows != null) { 236 final int windowCount = mWindows.size(); 237 for (int i = 0; i < windowCount; i++) { 238 final AccessibilityWindowInfo window = mWindows.get(i); 239 if (window.isInPictureInPictureMode()) { 240 return window; 241 } 242 } 243 } 244 return null; 245 } 246 247 /** 248 * Sets the active flag of the window according to given windowId, others set to inactive. 249 * 250 * @param windowId The windowId 251 */ setActiveWindowLocked(int windowId)252 void setActiveWindowLocked(int windowId) { 253 if (mWindows != null) { 254 final int windowCount = mWindows.size(); 255 for (int i = 0; i < windowCount; i++) { 256 AccessibilityWindowInfo window = mWindows.get(i); 257 if (window.getId() == windowId) { 258 window.setActive(true); 259 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( 260 AccessibilityEvent.obtainWindowsChangedEvent(windowId, 261 AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); 262 } else { 263 window.setActive(false); 264 } 265 } 266 } 267 } 268 269 /** 270 * Sets the window accessibility focused according to given windowId, others set 271 * unfocused. 272 * 273 * @param windowId The windowId 274 */ setAccessibilityFocusedWindowLocked(int windowId)275 void setAccessibilityFocusedWindowLocked(int windowId) { 276 if (mWindows != null) { 277 final int windowCount = mWindows.size(); 278 for (int i = 0; i < windowCount; i++) { 279 AccessibilityWindowInfo window = mWindows.get(i); 280 if (window.getId() == windowId) { 281 mAccessibilityFocusedDisplayId = mDisplayId; 282 window.setAccessibilityFocused(true); 283 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( 284 AccessibilityEvent.obtainWindowsChangedEvent( 285 windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); 286 287 } else { 288 window.setAccessibilityFocused(false); 289 } 290 } 291 } 292 } 293 294 /** 295 * Computes partial interactive region of given windowId. 296 * 297 * @param windowId The windowId 298 * @param forceComputeRegion set outRegion when the windowId matches one on the screen even 299 * though the region is not covered by other windows above it. 300 * @param outRegion The output to which to write the bounds. 301 * @return {@code true} if outRegion is not empty. 302 */ computePartialInteractiveRegionForWindowLocked(int windowId, boolean forceComputeRegion, @NonNull Region outRegion)303 boolean computePartialInteractiveRegionForWindowLocked(int windowId, 304 boolean forceComputeRegion, @NonNull Region outRegion) { 305 if (mWindows == null) { 306 return false; 307 } 308 309 // Windows are ordered in z order so start from the bottom and find 310 // the window of interest. After that all windows that cover it should 311 // be subtracted from the resulting region. Note that for accessibility 312 // we are returning only interactive windows. 313 Region windowInteractiveRegion = null; 314 boolean windowInteractiveRegionChanged = false; 315 316 final int windowCount = mWindows.size(); 317 final Region currentWindowRegions = new Region(); 318 for (int i = windowCount - 1; i >= 0; i--) { 319 AccessibilityWindowInfo currentWindow = mWindows.get(i); 320 if (windowInteractiveRegion == null) { 321 if (currentWindow.getId() == windowId) { 322 currentWindow.getRegionInScreen(currentWindowRegions); 323 outRegion.set(currentWindowRegions); 324 windowInteractiveRegion = outRegion; 325 if (forceComputeRegion) { 326 windowInteractiveRegionChanged = true; 327 } 328 continue; 329 } 330 } else if (currentWindow.getType() 331 != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) { 332 currentWindow.getRegionInScreen(currentWindowRegions); 333 if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) { 334 windowInteractiveRegionChanged = true; 335 } 336 } 337 } 338 339 return windowInteractiveRegionChanged; 340 } 341 getWatchOutsideTouchWindowIdLocked(int targetWindowId)342 List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) { 343 final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId); 344 if (targetWindow != null && mHasWatchOutsideTouchWindow) { 345 final List<Integer> outsideWindowsId = new ArrayList<>(); 346 for (int i = 0; i < mWindowInfoById.size(); i++) { 347 final WindowInfo window = mWindowInfoById.valueAt(i); 348 if (window != null && window.layer < targetWindow.layer 349 && window.hasFlagWatchOutsideTouch) { 350 outsideWindowsId.add(mWindowInfoById.keyAt(i)); 351 } 352 } 353 return outsideWindowsId; 354 } 355 return Collections.emptyList(); 356 } 357 358 /** 359 * Callbacks from window manager when there's an accessibility change in windows. 360 * 361 * @param forceSend Send the windows for accessibility even if they haven't changed. 362 * @param topFocusedDisplayId The display Id which has the top focused window. 363 * @param topFocusedWindowToken The window token of top focused window. 364 * @param windows The windows for accessibility. 365 */ 366 @Override onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows)367 public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, 368 IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) { 369 synchronized (mLock) { 370 if (DEBUG) { 371 Slog.i(LOG_TAG, "Display Id = " + mDisplayId); 372 Slog.i(LOG_TAG, "Windows changed: " + windows); 373 } 374 if (shouldUpdateWindowsLocked(forceSend, windows)) { 375 mTopFocusedDisplayId = topFocusedDisplayId; 376 mTopFocusedWindowToken = topFocusedWindowToken; 377 cacheWindows(windows); 378 // Lets the policy update the focused and active windows. 379 updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), 380 windows); 381 // Someone may be waiting for the windows - advertise it. 382 mLock.notifyAll(); 383 } 384 } 385 } 386 387 /** 388 * Called when the display is reparented and becomes an embedded 389 * display. 390 * 391 * @param embeddedDisplayId The embedded display Id. 392 */ 393 @Override onDisplayReparented(int embeddedDisplayId)394 public void onDisplayReparented(int embeddedDisplayId) { 395 // Removes the un-used window observer for the embedded display. 396 synchronized (mLock) { 397 mDisplayWindowsObservers.remove(embeddedDisplayId); 398 } 399 } 400 shouldUpdateWindowsLocked(boolean forceSend, @NonNull List<WindowInfo> windows)401 private boolean shouldUpdateWindowsLocked(boolean forceSend, 402 @NonNull List<WindowInfo> windows) { 403 if (forceSend) { 404 return true; 405 } 406 407 final int windowCount = windows.size(); 408 // We computed the windows and if they changed notify the client. 409 if (mCachedWindowInfos.size() != windowCount) { 410 // Different size means something changed. 411 return true; 412 } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) { 413 // Since we always traverse windows from high to low layer 414 // the old and new windows at the same index should be the 415 // same, otherwise something changed. 416 for (int i = 0; i < windowCount; i++) { 417 WindowInfo oldWindow = mCachedWindowInfos.get(i); 418 WindowInfo newWindow = windows.get(i); 419 // We do not care for layer changes given the window 420 // order does not change. This brings no new information 421 // to the clients. 422 if (windowChangedNoLayer(oldWindow, newWindow)) { 423 return true; 424 } 425 } 426 } 427 428 return false; 429 } 430 cacheWindows(List<WindowInfo> windows)431 private void cacheWindows(List<WindowInfo> windows) { 432 final int oldWindowCount = mCachedWindowInfos.size(); 433 for (int i = oldWindowCount - 1; i >= 0; i--) { 434 mCachedWindowInfos.remove(i).recycle(); 435 } 436 final int newWindowCount = windows.size(); 437 for (int i = 0; i < newWindowCount; i++) { 438 WindowInfo newWindow = windows.get(i); 439 mCachedWindowInfos.add(WindowInfo.obtain(newWindow)); 440 } 441 } 442 windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow)443 private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) { 444 if (oldWindow == newWindow) { 445 return false; 446 } 447 if (oldWindow == null) { 448 return true; 449 } 450 if (newWindow == null) { 451 return true; 452 } 453 if (oldWindow.type != newWindow.type) { 454 return true; 455 } 456 if (oldWindow.focused != newWindow.focused) { 457 return true; 458 } 459 if (oldWindow.token == null) { 460 if (newWindow.token != null) { 461 return true; 462 } 463 } else if (!oldWindow.token.equals(newWindow.token)) { 464 return true; 465 } 466 if (oldWindow.parentToken == null) { 467 if (newWindow.parentToken != null) { 468 return true; 469 } 470 } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) { 471 return true; 472 } 473 if (oldWindow.activityToken == null) { 474 if (newWindow.activityToken != null) { 475 return true; 476 } 477 } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) { 478 return true; 479 } 480 if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) { 481 return true; 482 } 483 if (oldWindow.childTokens != null && newWindow.childTokens != null 484 && !oldWindow.childTokens.equals(newWindow.childTokens)) { 485 return true; 486 } 487 if (!TextUtils.equals(oldWindow.title, newWindow.title)) { 488 return true; 489 } 490 if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) { 491 return true; 492 } 493 if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) { 494 return true; 495 } 496 if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) { 497 return true; 498 } 499 if (oldWindow.displayId != newWindow.displayId) { 500 return true; 501 } 502 if (oldWindow.taskId != newWindow.taskId) { 503 return true; 504 } 505 return false; 506 } 507 508 /** 509 * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s. 510 */ clearWindowsLocked()511 private void clearWindowsLocked() { 512 final List<WindowInfo> windows = Collections.emptyList(); 513 final int activeWindowId = mActiveWindowId; 514 // UserId is useless in updateWindowsLocked, when we update a empty window list. 515 // Just pass current userId here. 516 updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows); 517 // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility 518 // interaction connection removed. 519 mActiveWindowId = activeWindowId; 520 mWindows = null; 521 } 522 523 /** 524 * Updates windows info according to specified userId and windows. 525 * 526 * @param userId The userId to update 527 * @param windows The windows to update 528 */ updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows)529 private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) { 530 if (mWindows == null) { 531 mWindows = new ArrayList<>(); 532 } 533 534 final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows); 535 final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone(); 536 boolean shouldClearAccessibilityFocus = false; 537 538 mWindows.clear(); 539 mA11yWindowInfoById.clear(); 540 541 for (int i = 0; i < mWindowInfoById.size(); i++) { 542 mWindowInfoById.valueAt(i).recycle(); 543 } 544 mWindowInfoById.clear(); 545 mHasWatchOutsideTouchWindow = false; 546 547 final int windowCount = windows.size(); 548 final boolean isTopFocusedDisplay = mDisplayId == mTopFocusedDisplayId; 549 final boolean isAccessibilityFocusedDisplay = 550 mDisplayId == mAccessibilityFocusedDisplayId; 551 // Modifies the value of top focused window, active window and a11y focused window 552 // only if this display is top focused display which has the top focused window. 553 if (isTopFocusedDisplay) { 554 if (windowCount > 0) { 555 // Sets the top focus window by top focused window token. 556 mTopFocusedWindowId = findWindowIdLocked(userId, mTopFocusedWindowToken); 557 } else { 558 // Resets the top focus window when stopping tracking window of this display. 559 mTopFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 560 } 561 // The active window doesn't need to be reset if the touch operation is progressing. 562 if (!mTouchInteractionInProgress) { 563 mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 564 } 565 } 566 567 // If the active window goes away while the user is touch exploring we 568 // reset the active window id and wait for the next hover event from 569 // under the user's finger to determine which one is the new one. It 570 // is possible that the finger is not moving and the input system 571 // filters out such events. 572 boolean activeWindowGone = true; 573 574 // We'll clear accessibility focus if the window with focus is no longer visible to 575 // accessibility services. 576 if (isAccessibilityFocusedDisplay) { 577 shouldClearAccessibilityFocus = mAccessibilityFocusedWindowId 578 != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 579 } 580 if (windowCount > 0) { 581 for (int i = 0; i < windowCount; i++) { 582 final WindowInfo windowInfo = windows.get(i); 583 final AccessibilityWindowInfo window; 584 if (mTrackingWindows) { 585 window = populateReportedWindowLocked(userId, windowInfo); 586 } else { 587 window = null; 588 } 589 if (window != null) { 590 591 // Flip layers in list to be consistent with AccessibilityService#getWindows 592 window.setLayer(windowCount - 1 - window.getLayer()); 593 594 final int windowId = window.getId(); 595 if (window.isFocused() && isTopFocusedDisplay) { 596 if (!mTouchInteractionInProgress) { 597 // This display is top one, and sets the focus window 598 // as active window. 599 mActiveWindowId = windowId; 600 window.setActive(true); 601 } else if (windowId == mActiveWindowId) { 602 activeWindowGone = false; 603 } 604 } 605 if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) { 606 mHasWatchOutsideTouchWindow = true; 607 } 608 mWindows.add(window); 609 mA11yWindowInfoById.put(windowId, window); 610 mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo)); 611 } 612 } 613 final int accessibilityWindowCount = mWindows.size(); 614 if (isTopFocusedDisplay) { 615 if (mTouchInteractionInProgress && activeWindowGone) { 616 mActiveWindowId = mTopFocusedWindowId; 617 } 618 // Focused window may change the active one, so set the 619 // active window once we decided which it is. 620 for (int i = 0; i < accessibilityWindowCount; i++) { 621 final AccessibilityWindowInfo window = mWindows.get(i); 622 if (window.getId() == mActiveWindowId) { 623 window.setActive(true); 624 } 625 } 626 } 627 if (isAccessibilityFocusedDisplay) { 628 for (int i = 0; i < accessibilityWindowCount; i++) { 629 final AccessibilityWindowInfo window = mWindows.get(i); 630 if (window.getId() == mAccessibilityFocusedWindowId) { 631 window.setAccessibilityFocused(true); 632 shouldClearAccessibilityFocus = false; 633 break; 634 } 635 } 636 } 637 } 638 639 sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById); 640 641 final int oldWindowCount = oldWindowList.size(); 642 for (int i = oldWindowCount - 1; i >= 0; i--) { 643 oldWindowList.remove(i).recycle(); 644 } 645 646 if (shouldClearAccessibilityFocus) { 647 clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); 648 } 649 } 650 sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, SparseArray<AccessibilityWindowInfo> oldWindowsById)651 private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, 652 SparseArray<AccessibilityWindowInfo> oldWindowsById) { 653 List<AccessibilityEvent> events = new ArrayList<>(); 654 // Sends events for all removed windows. 655 final int oldWindowsCount = oldWindows.size(); 656 for (int i = 0; i < oldWindowsCount; i++) { 657 final AccessibilityWindowInfo window = oldWindows.get(i); 658 if (mA11yWindowInfoById.get(window.getId()) == null) { 659 events.add(AccessibilityEvent.obtainWindowsChangedEvent( 660 window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED)); 661 } 662 } 663 664 // Looks for other changes. 665 final int newWindowCount = mWindows.size(); 666 for (int i = 0; i < newWindowCount; i++) { 667 final AccessibilityWindowInfo newWindow = mWindows.get(i); 668 final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId()); 669 if (oldWindow == null) { 670 events.add(AccessibilityEvent.obtainWindowsChangedEvent( 671 newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED)); 672 } else { 673 int changes = newWindow.differenceFrom(oldWindow); 674 if (changes != 0) { 675 events.add(AccessibilityEvent.obtainWindowsChangedEvent( 676 newWindow.getId(), changes)); 677 } 678 } 679 } 680 681 final int numEvents = events.size(); 682 for (int i = 0; i < numEvents; i++) { 683 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i)); 684 } 685 } 686 populateReportedWindowLocked(int userId, WindowInfo window)687 private AccessibilityWindowInfo populateReportedWindowLocked(int userId, 688 WindowInfo window) { 689 final int windowId = findWindowIdLocked(userId, window.token); 690 if (windowId < 0) { 691 return null; 692 } 693 694 final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain(); 695 696 reportedWindow.setId(windowId); 697 reportedWindow.setType(getTypeForWindowManagerWindowType(window.type)); 698 reportedWindow.setLayer(window.layer); 699 reportedWindow.setFocused(window.focused); 700 reportedWindow.setRegionInScreen(window.regionInScreen); 701 reportedWindow.setTitle(window.title); 702 reportedWindow.setAnchorId(window.accessibilityIdOfAnchor); 703 reportedWindow.setPictureInPicture(window.inPictureInPicture); 704 reportedWindow.setDisplayId(window.displayId); 705 reportedWindow.setTaskId(window.taskId); 706 707 final int parentId = findWindowIdLocked(userId, window.parentToken); 708 if (parentId >= 0) { 709 reportedWindow.setParentId(parentId); 710 } 711 712 if (window.childTokens != null) { 713 final int childCount = window.childTokens.size(); 714 for (int i = 0; i < childCount; i++) { 715 final IBinder childToken = window.childTokens.get(i); 716 final int childId = findWindowIdLocked(userId, childToken); 717 if (childId >= 0) { 718 reportedWindow.addChild(childId); 719 } 720 } 721 } 722 723 return reportedWindow; 724 } 725 getTypeForWindowManagerWindowType(int windowType)726 private int getTypeForWindowManagerWindowType(int windowType) { 727 switch (windowType) { 728 case WindowManager.LayoutParams.TYPE_APPLICATION: 729 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA: 730 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL: 731 case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING: 732 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL: 733 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL: 734 case WindowManager.LayoutParams.TYPE_BASE_APPLICATION: 735 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION: 736 case WindowManager.LayoutParams.TYPE_PHONE: 737 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE: 738 case WindowManager.LayoutParams.TYPE_TOAST: 739 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG: 740 case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: { 741 return AccessibilityWindowInfo.TYPE_APPLICATION; 742 } 743 744 case WindowManager.LayoutParams.TYPE_INPUT_METHOD: { 745 return AccessibilityWindowInfo.TYPE_INPUT_METHOD; 746 } 747 748 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: 749 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR: 750 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: 751 case WindowManager.LayoutParams.TYPE_SEARCH_BAR: 752 case WindowManager.LayoutParams.TYPE_STATUS_BAR: 753 case WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE: 754 case WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL: 755 case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: 756 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: 757 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: 758 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: 759 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: 760 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: 761 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY: 762 case WindowManager.LayoutParams.TYPE_SCREENSHOT: 763 case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY: { 764 return AccessibilityWindowInfo.TYPE_SYSTEM; 765 } 766 767 case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { 768 return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; 769 } 770 771 case TYPE_ACCESSIBILITY_OVERLAY: { 772 return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; 773 } 774 775 default: { 776 return -1; 777 } 778 } 779 } 780 781 /** 782 * Dumps all {@link AccessibilityWindowInfo}s here. 783 */ dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args)784 void dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args) { 785 pw.append("Global Info [ "); 786 pw.println("Top focused display Id = " + mTopFocusedDisplayId); 787 pw.println(" Active Window Id = " + mActiveWindowId); 788 pw.println(" Top Focused Window Id = " + mTopFocusedWindowId); 789 pw.println(" Accessibility Focused Window Id = " + mAccessibilityFocusedWindowId 790 + " ]"); 791 pw.println(); 792 if (mWindows != null) { 793 final int windowCount = mWindows.size(); 794 for (int j = 0; j < windowCount; j++) { 795 if (j == 0) { 796 pw.append("Display["); 797 pw.append(Integer.toString(mDisplayId)); 798 pw.append("] : "); 799 pw.println(); 800 } 801 if (j > 0) { 802 pw.append(','); 803 pw.println(); 804 } 805 pw.append("Window["); 806 AccessibilityWindowInfo window = mWindows.get(j); 807 pw.append(window.toString()); 808 pw.append(']'); 809 } 810 pw.println(); 811 } 812 } 813 } 814 /** 815 * Interface to send {@link AccessibilityEvent}. 816 */ 817 public interface AccessibilityEventSender { 818 /** 819 * Sends {@link AccessibilityEvent} for current user. 820 */ sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event)821 void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event); 822 } 823 824 /** 825 * Wrapper of accessibility interaction connection for window. 826 */ 827 // In order to avoid using DexmakerShareClassLoaderRule, make this class visible for testing. 828 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 829 public final class RemoteAccessibilityConnection implements IBinder.DeathRecipient { 830 private final int mUid; 831 private final String mPackageName; 832 private final int mWindowId; 833 private final int mUserId; 834 private final IAccessibilityInteractionConnection mConnection; 835 RemoteAccessibilityConnection(int windowId, IAccessibilityInteractionConnection connection, String packageName, int uid, int userId)836 RemoteAccessibilityConnection(int windowId, 837 IAccessibilityInteractionConnection connection, 838 String packageName, int uid, int userId) { 839 mWindowId = windowId; 840 mPackageName = packageName; 841 mUid = uid; 842 mUserId = userId; 843 mConnection = connection; 844 } 845 getUid()846 int getUid() { 847 return mUid; 848 } 849 getPackageName()850 String getPackageName() { 851 return mPackageName; 852 } 853 getRemote()854 IAccessibilityInteractionConnection getRemote() { 855 return mConnection; 856 } 857 linkToDeath()858 void linkToDeath() throws RemoteException { 859 mConnection.asBinder().linkToDeath(this, 0); 860 } 861 unlinkToDeath()862 void unlinkToDeath() { 863 mConnection.asBinder().unlinkToDeath(this, 0); 864 } 865 866 @Override binderDied()867 public void binderDied() { 868 unlinkToDeath(); 869 synchronized (mLock) { 870 removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId); 871 } 872 } 873 } 874 875 /** 876 * Constructor for AccessibilityWindowManager. 877 */ AccessibilityWindowManager(@onNull Object lock, @NonNull Handler handler, @NonNull WindowManagerInternal windowManagerInternal, @NonNull AccessibilityEventSender accessibilityEventSender, @NonNull AccessibilitySecurityPolicy securityPolicy, @NonNull AccessibilityUserManager accessibilityUserManager, @NonNull AccessibilityTraceManager traceManager)878 public AccessibilityWindowManager(@NonNull Object lock, @NonNull Handler handler, 879 @NonNull WindowManagerInternal windowManagerInternal, 880 @NonNull AccessibilityEventSender accessibilityEventSender, 881 @NonNull AccessibilitySecurityPolicy securityPolicy, 882 @NonNull AccessibilityUserManager accessibilityUserManager, 883 @NonNull AccessibilityTraceManager traceManager) { 884 mLock = lock; 885 mHandler = handler; 886 mWindowManagerInternal = windowManagerInternal; 887 mAccessibilityEventSender = accessibilityEventSender; 888 mSecurityPolicy = securityPolicy; 889 mAccessibilityUserManager = accessibilityUserManager; 890 mTraceManager = traceManager; 891 } 892 893 /** 894 * Starts tracking windows changes from window manager for specified display. 895 * 896 * @param displayId The logical display id. 897 */ startTrackingWindows(int displayId)898 public void startTrackingWindows(int displayId) { 899 synchronized (mLock) { 900 DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); 901 if (observer == null) { 902 observer = new DisplayWindowsObserver(displayId); 903 } 904 if (observer.isTrackingWindowsLocked()) { 905 return; 906 } 907 if (observer.startTrackingWindowsLocked()) { 908 mDisplayWindowsObservers.put(displayId, observer); 909 } 910 } 911 } 912 913 /** 914 * Stops tracking windows changes from window manager, and clear all windows info for specified 915 * display. 916 * 917 * @param displayId The logical display id. 918 */ stopTrackingWindows(int displayId)919 public void stopTrackingWindows(int displayId) { 920 synchronized (mLock) { 921 final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); 922 if (observer != null) { 923 observer.stopTrackingWindowsLocked(); 924 mDisplayWindowsObservers.remove(displayId); 925 } 926 } 927 } 928 929 /** 930 * Checks if we are tracking windows on any display. 931 * 932 * @return {@code true} if the observer is tracking windows on any display, 933 * {@code false} otherwise. 934 */ isTrackingWindowsLocked()935 public boolean isTrackingWindowsLocked() { 936 final int count = mDisplayWindowsObservers.size(); 937 if (count > 0) { 938 return true; 939 } 940 return false; 941 } 942 943 /** 944 * Checks if we are tracking windows on specified display. 945 * 946 * @param displayId The logical display id. 947 * @return {@code true} if the observer is tracking windows on specified display, 948 * {@code false} otherwise. 949 */ isTrackingWindowsLocked(int displayId)950 public boolean isTrackingWindowsLocked(int displayId) { 951 final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); 952 if (observer != null) { 953 return observer.isTrackingWindowsLocked(); 954 } 955 return false; 956 } 957 958 /** 959 * Returns accessibility windows for specified display. 960 * 961 * @param displayId The logical display id. 962 * @return accessibility windows for specified display. 963 */ 964 @Nullable getWindowListLocked(int displayId)965 public List<AccessibilityWindowInfo> getWindowListLocked(int displayId) { 966 final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId); 967 if (observer != null) { 968 return observer.getWindowListLocked(); 969 } 970 return null; 971 } 972 973 /** 974 * Adds accessibility interaction connection according to given window token, package name and 975 * window token. 976 * 977 * @param window The window token of accessibility interaction connection 978 * @param leashToken The leash token of accessibility interaction connection 979 * @param connection The accessibility interaction connection 980 * @param packageName The package name 981 * @param userId The userId 982 * @return The windowId of added connection 983 * @throws RemoteException 984 */ addAccessibilityInteractionConnection(@onNull IWindow window, @NonNull IBinder leashToken, @NonNull IAccessibilityInteractionConnection connection, @NonNull String packageName, int userId)985 public int addAccessibilityInteractionConnection(@NonNull IWindow window, 986 @NonNull IBinder leashToken, @NonNull IAccessibilityInteractionConnection connection, 987 @NonNull String packageName, int userId) throws RemoteException { 988 final int windowId; 989 boolean shouldComputeWindows = false; 990 final IBinder token = window.asBinder(); 991 if (traceWMEnabled()) { 992 logTraceWM("getDisplayIdForWindow", "token=" + token); 993 } 994 final int displayId = mWindowManagerInternal.getDisplayIdForWindow(token); 995 synchronized (mLock) { 996 // We treat calls from a profile as if made by its parent as profiles 997 // share the accessibility state of the parent. The call below 998 // performs the current profile parent resolution. 999 final int resolvedUserId = mSecurityPolicy 1000 .resolveCallingUserIdEnforcingPermissionsLocked(userId); 1001 final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId()); 1002 1003 // Makes sure the reported package is one the caller has access to. 1004 packageName = mSecurityPolicy.resolveValidReportedPackageLocked( 1005 packageName, UserHandle.getCallingAppId(), resolvedUserId, 1006 Binder.getCallingPid()); 1007 1008 windowId = sNextWindowId++; 1009 // If the window is from a process that runs across users such as 1010 // the system UI or the system we add it to the global state that 1011 // is shared across users. 1012 if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { 1013 RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection( 1014 windowId, connection, packageName, resolvedUid, UserHandle.USER_ALL); 1015 wrapper.linkToDeath(); 1016 mGlobalInteractionConnections.put(windowId, wrapper); 1017 mGlobalWindowTokens.put(windowId, token); 1018 if (DEBUG) { 1019 Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid() 1020 + " with windowId: " + windowId + " and token: " + token); 1021 } 1022 } else { 1023 RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection( 1024 windowId, connection, packageName, resolvedUid, resolvedUserId); 1025 wrapper.linkToDeath(); 1026 getInteractionConnectionsForUserLocked(resolvedUserId).put(windowId, wrapper); 1027 getWindowTokensForUserLocked(resolvedUserId).put(windowId, token); 1028 if (DEBUG) { 1029 Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid() 1030 + " with windowId: " + windowId + " and token: " + token); 1031 } 1032 } 1033 1034 if (isTrackingWindowsLocked(displayId)) { 1035 shouldComputeWindows = true; 1036 } 1037 registerIdLocked(leashToken, windowId); 1038 } 1039 if (shouldComputeWindows) { 1040 if (traceWMEnabled()) { 1041 logTraceWM("computeWindowsForAccessibility", "displayId=" + displayId); 1042 } 1043 mWindowManagerInternal.computeWindowsForAccessibility(displayId); 1044 } 1045 if (traceWMEnabled()) { 1046 logTraceWM("setAccessibilityIdToSurfaceMetadata", 1047 "token=" + token + ";windowId=" + windowId); 1048 } 1049 mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(token, windowId); 1050 return windowId; 1051 } 1052 1053 /** 1054 * Removes accessibility interaction connection according to given window token. 1055 * 1056 * @param window The window token of accessibility interaction connection 1057 */ removeAccessibilityInteractionConnection(@onNull IWindow window)1058 public void removeAccessibilityInteractionConnection(@NonNull IWindow window) { 1059 synchronized (mLock) { 1060 // We treat calls from a profile as if made by its parent as profiles 1061 // share the accessibility state of the parent. The call below 1062 // performs the current profile parent resolution. 1063 mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( 1064 UserHandle.getCallingUserId()); 1065 IBinder token = window.asBinder(); 1066 final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked( 1067 token, mGlobalWindowTokens, mGlobalInteractionConnections); 1068 if (removedWindowId >= 0) { 1069 onAccessibilityInteractionConnectionRemovedLocked(removedWindowId, token); 1070 if (DEBUG) { 1071 Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid() 1072 + " with windowId: " + removedWindowId + " and token: " 1073 + window.asBinder()); 1074 } 1075 return; 1076 } 1077 final int userCount = mWindowTokens.size(); 1078 for (int i = 0; i < userCount; i++) { 1079 final int userId = mWindowTokens.keyAt(i); 1080 final int removedWindowIdForUser = 1081 removeAccessibilityInteractionConnectionInternalLocked(token, 1082 getWindowTokensForUserLocked(userId), 1083 getInteractionConnectionsForUserLocked(userId)); 1084 if (removedWindowIdForUser >= 0) { 1085 onAccessibilityInteractionConnectionRemovedLocked( 1086 removedWindowIdForUser, token); 1087 if (DEBUG) { 1088 Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid() 1089 + " with windowId: " + removedWindowIdForUser + " and userId:" 1090 + userId + " and token: " + window.asBinder()); 1091 } 1092 return; 1093 } 1094 } 1095 } 1096 } 1097 1098 /** 1099 * Resolves a connection wrapper for a window id. 1100 * 1101 * @param userId The user id for any user-specific windows 1102 * @param windowId The id of the window of interest 1103 * 1104 * @return a connection to the window 1105 */ 1106 @Nullable getConnectionLocked(int userId, int windowId)1107 public RemoteAccessibilityConnection getConnectionLocked(int userId, int windowId) { 1108 if (DEBUG) { 1109 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); 1110 } 1111 RemoteAccessibilityConnection connection = mGlobalInteractionConnections.get(windowId); 1112 if (connection == null && isValidUserForInteractionConnectionsLocked(userId)) { 1113 connection = getInteractionConnectionsForUserLocked(userId).get(windowId); 1114 } 1115 if (connection != null && connection.getRemote() != null) { 1116 return connection; 1117 } 1118 if (DEBUG) { 1119 Slog.e(LOG_TAG, "No interaction connection to window: " + windowId); 1120 } 1121 return null; 1122 } 1123 removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, SparseArray<IBinder> windowTokens, SparseArray<RemoteAccessibilityConnection> interactionConnections)1124 private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, 1125 SparseArray<IBinder> windowTokens, SparseArray<RemoteAccessibilityConnection> 1126 interactionConnections) { 1127 final int count = windowTokens.size(); 1128 for (int i = 0; i < count; i++) { 1129 if (windowTokens.valueAt(i) == windowToken) { 1130 final int windowId = windowTokens.keyAt(i); 1131 windowTokens.removeAt(i); 1132 RemoteAccessibilityConnection wrapper = interactionConnections.get(windowId); 1133 wrapper.unlinkToDeath(); 1134 interactionConnections.remove(windowId); 1135 return windowId; 1136 } 1137 } 1138 return -1; 1139 } 1140 1141 /** 1142 * Removes accessibility interaction connection according to given windowId and userId. 1143 * 1144 * @param windowId The windowId of accessibility interaction connection 1145 * @param userId The userId to remove 1146 */ removeAccessibilityInteractionConnectionLocked(int windowId, int userId)1147 private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) { 1148 IBinder window = null; 1149 if (userId == UserHandle.USER_ALL) { 1150 window = mGlobalWindowTokens.get(windowId); 1151 mGlobalWindowTokens.remove(windowId); 1152 mGlobalInteractionConnections.remove(windowId); 1153 } else { 1154 if (isValidUserForWindowTokensLocked(userId)) { 1155 window = getWindowTokensForUserLocked(userId).get(windowId); 1156 getWindowTokensForUserLocked(userId).remove(windowId); 1157 } 1158 if (isValidUserForInteractionConnectionsLocked(userId)) { 1159 getInteractionConnectionsForUserLocked(userId).remove(windowId); 1160 } 1161 } 1162 onAccessibilityInteractionConnectionRemovedLocked(windowId, window); 1163 if (DEBUG) { 1164 Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); 1165 } 1166 } 1167 1168 /** 1169 * Invoked when accessibility interaction connection of window is removed. 1170 * 1171 * @param windowId Removed windowId 1172 * @param binder Removed window token 1173 */ onAccessibilityInteractionConnectionRemovedLocked( int windowId, @Nullable IBinder binder)1174 private void onAccessibilityInteractionConnectionRemovedLocked( 1175 int windowId, @Nullable IBinder binder) { 1176 // Active window will not update, if windows callback is unregistered. 1177 // Update active window to invalid, when its a11y interaction connection is removed. 1178 if (!isTrackingWindowsLocked() && windowId >= 0 && mActiveWindowId == windowId) { 1179 mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1180 } 1181 if (binder != null) { 1182 if (traceWMEnabled()) { 1183 logTraceWM("setAccessibilityIdToSurfaceMetadata", "token=" + binder 1184 + ";windowId=AccessibilityWindowInfo.UNDEFINED_WINDOW_ID"); 1185 } 1186 mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata( 1187 binder, AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); 1188 } 1189 unregisterIdLocked(windowId); 1190 } 1191 1192 /** 1193 * Gets window token according to given userId and windowId. 1194 * 1195 * @param userId The userId 1196 * @param windowId The windowId 1197 * @return The window token 1198 */ 1199 @Nullable getWindowTokenForUserAndWindowIdLocked(int userId, int windowId)1200 public IBinder getWindowTokenForUserAndWindowIdLocked(int userId, int windowId) { 1201 IBinder windowToken = mGlobalWindowTokens.get(windowId); 1202 if (windowToken == null && isValidUserForWindowTokensLocked(userId)) { 1203 windowToken = getWindowTokensForUserLocked(userId).get(windowId); 1204 } 1205 return windowToken; 1206 } 1207 1208 /** 1209 * Returns the userId that owns the given window token, {@link UserHandle#USER_NULL} 1210 * if not found. 1211 * 1212 * @param windowToken The window token 1213 * @return The userId 1214 */ getWindowOwnerUserId(@onNull IBinder windowToken)1215 public int getWindowOwnerUserId(@NonNull IBinder windowToken) { 1216 if (traceWMEnabled()) { 1217 logTraceWM("getWindowOwnerUserId", "token=" + windowToken); 1218 } 1219 return mWindowManagerInternal.getWindowOwnerUserId(windowToken); 1220 } 1221 1222 /** 1223 * Returns windowId of given userId and window token. 1224 * 1225 * @param userId The userId 1226 * @param token The window token 1227 * @return The windowId 1228 */ findWindowIdLocked(int userId, @NonNull IBinder token)1229 public int findWindowIdLocked(int userId, @NonNull IBinder token) { 1230 final int globalIndex = mGlobalWindowTokens.indexOfValue(token); 1231 if (globalIndex >= 0) { 1232 return mGlobalWindowTokens.keyAt(globalIndex); 1233 } 1234 if (isValidUserForWindowTokensLocked(userId)) { 1235 final int userIndex = getWindowTokensForUserLocked(userId).indexOfValue(token); 1236 if (userIndex >= 0) { 1237 return getWindowTokensForUserLocked(userId).keyAt(userIndex); 1238 } 1239 } 1240 return -1; 1241 } 1242 1243 /** 1244 * Establish the relationship between the host and the embedded view hierarchy. 1245 * 1246 * @param host The token of host hierarchy 1247 * @param embedded The token of the embedded hierarchy 1248 */ associateEmbeddedHierarchyLocked(@onNull IBinder host, @NonNull IBinder embedded)1249 public void associateEmbeddedHierarchyLocked(@NonNull IBinder host, @NonNull IBinder embedded) { 1250 // Use embedded window as key, since one host window may have multiple embedded windows. 1251 associateLocked(embedded, host); 1252 } 1253 1254 /** 1255 * Clear the relationship by given token. 1256 * 1257 * @param token The token 1258 */ disassociateEmbeddedHierarchyLocked(@onNull IBinder token)1259 public void disassociateEmbeddedHierarchyLocked(@NonNull IBinder token) { 1260 disassociateLocked(token); 1261 } 1262 1263 /** 1264 * Gets the parent windowId of the window according to the specified windowId. 1265 * 1266 * @param windowId The windowId to check 1267 * @return The windowId of the parent window, or self if no parent exists 1268 */ resolveParentWindowIdLocked(int windowId)1269 public int resolveParentWindowIdLocked(int windowId) { 1270 final IBinder token = getTokenLocked(windowId); 1271 if (token == null) { 1272 return windowId; 1273 } 1274 final IBinder resolvedToken = resolveTopParentTokenLocked(token); 1275 final int resolvedWindowId = getWindowIdLocked(resolvedToken); 1276 return resolvedWindowId != -1 ? resolvedWindowId : windowId; 1277 } 1278 resolveTopParentTokenLocked(IBinder token)1279 private IBinder resolveTopParentTokenLocked(IBinder token) { 1280 final IBinder hostToken = getHostTokenLocked(token); 1281 if (hostToken == null) { 1282 return token; 1283 } 1284 return resolveTopParentTokenLocked(hostToken); 1285 } 1286 1287 /** 1288 * Computes partial interactive region of given windowId. 1289 * 1290 * @param windowId The windowId 1291 * @param outRegion The output to which to write the bounds. 1292 * @return true if outRegion is not empty. 1293 */ computePartialInteractiveRegionForWindowLocked(int windowId, @NonNull Region outRegion)1294 public boolean computePartialInteractiveRegionForWindowLocked(int windowId, 1295 @NonNull Region outRegion) { 1296 final int parentWindowId = resolveParentWindowIdLocked(windowId); 1297 final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked( 1298 parentWindowId); 1299 1300 if (observer != null) { 1301 return observer.computePartialInteractiveRegionForWindowLocked(parentWindowId, 1302 parentWindowId != windowId, outRegion); 1303 } 1304 1305 return false; 1306 } 1307 1308 /** 1309 * Updates active windowId and accessibility focused windowId according to given accessibility 1310 * event and action. 1311 * 1312 * @param userId The userId 1313 * @param windowId The windowId of accessibility event 1314 * @param nodeId The accessibility node id of accessibility event 1315 * @param eventType The accessibility event type 1316 * @param eventAction The accessibility event action 1317 */ updateActiveAndAccessibilityFocusedWindowLocked(int userId, int windowId, long nodeId, int eventType, int eventAction)1318 public void updateActiveAndAccessibilityFocusedWindowLocked(int userId, int windowId, 1319 long nodeId, int eventType, int eventAction) { 1320 // The active window is either the window that has input focus or 1321 // the window that the user is currently touching. If the user is 1322 // touching a window that does not have input focus as soon as the 1323 // the user stops touching that window the focused window becomes 1324 // the active one. Here we detect the touched window and make it 1325 // active. In updateWindowsLocked() we update the focused window 1326 // and if the user is not touching the screen, we make the focused 1327 // window the active one. 1328 switch (eventType) { 1329 case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: { 1330 // If no service has the capability to introspect screen, 1331 // we do not register callback in the window manager for 1332 // window changes, so we have to ask the window manager 1333 // what the focused window is to update the active one. 1334 // The active window also determined events from which 1335 // windows are delivered. 1336 synchronized (mLock) { 1337 if (!isTrackingWindowsLocked()) { 1338 mTopFocusedWindowId = findFocusedWindowId(userId); 1339 if (windowId == mTopFocusedWindowId) { 1340 mActiveWindowId = windowId; 1341 } 1342 } 1343 } 1344 } break; 1345 1346 case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: { 1347 // Do not allow delayed hover events to confuse us 1348 // which the active window is. 1349 synchronized (mLock) { 1350 if (mTouchInteractionInProgress && mActiveWindowId != windowId) { 1351 setActiveWindowLocked(windowId); 1352 } 1353 } 1354 } break; 1355 1356 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: { 1357 synchronized (mLock) { 1358 if (mAccessibilityFocusedWindowId != windowId) { 1359 clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); 1360 setAccessibilityFocusedWindowLocked(windowId); 1361 } 1362 mAccessibilityFocusNodeId = nodeId; 1363 } 1364 } break; 1365 1366 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: { 1367 synchronized (mLock) { 1368 if (mAccessibilityFocusNodeId == nodeId) { 1369 mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 1370 } 1371 // Clear the window with focus if it no longer has focus and we aren't 1372 // just moving focus from one view to the other in the same window. 1373 if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) 1374 && (mAccessibilityFocusedWindowId == windowId) 1375 && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)) { 1376 mAccessibilityFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1377 mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY; 1378 } 1379 } 1380 } break; 1381 } 1382 } 1383 1384 /** 1385 * Callbacks from AccessibilityManagerService when touch explorer turn on and 1386 * motion down detected. 1387 */ onTouchInteractionStart()1388 public void onTouchInteractionStart() { 1389 synchronized (mLock) { 1390 mTouchInteractionInProgress = true; 1391 } 1392 } 1393 1394 /** 1395 * Callbacks from AccessibilityManagerService when touch explorer turn on and 1396 * gesture or motion up detected. 1397 */ onTouchInteractionEnd()1398 public void onTouchInteractionEnd() { 1399 synchronized (mLock) { 1400 mTouchInteractionInProgress = false; 1401 // We want to set the active window to be current immediately 1402 // after the user has stopped touching the screen since if the 1403 // user types with the IME they should get a feedback for the 1404 // letter typed in the text view which is in the input focused 1405 // window. Note that we always deliver hover accessibility events 1406 // (they are a result of user touching the screen) so change of 1407 // the active window before all hover accessibility events from 1408 // the touched window are delivered is fine. 1409 final int oldActiveWindow = mActiveWindowId; 1410 setActiveWindowLocked(mTopFocusedWindowId); 1411 1412 // If there is no service that can operate with interactive windows 1413 // then we keep the old behavior where a window loses accessibility 1414 // focus if it is no longer active. This still changes the behavior 1415 // for services that do not operate with interactive windows and run 1416 // at the same time as the one(s) which does. In practice however, 1417 // there is only one service that uses accessibility focus and it 1418 // is typically the one that operates with interactive windows, So, 1419 // this is fine. Note that to allow a service to work across windows 1420 // we have to allow accessibility focus stay in any of them. Sigh... 1421 final boolean accessibilityFocusOnlyInActiveWindow = !isTrackingWindowsLocked(); 1422 if (oldActiveWindow != mActiveWindowId 1423 && mAccessibilityFocusedWindowId == oldActiveWindow 1424 && accessibilityFocusOnlyInActiveWindow) { 1425 clearAccessibilityFocusLocked(oldActiveWindow); 1426 } 1427 } 1428 } 1429 1430 /** 1431 * Gets the id of the current active window. 1432 * 1433 * @return The userId 1434 */ getActiveWindowId(int userId)1435 public int getActiveWindowId(int userId) { 1436 if (mActiveWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID 1437 && !mTouchInteractionInProgress) { 1438 mActiveWindowId = findFocusedWindowId(userId); 1439 } 1440 return mActiveWindowId; 1441 } 1442 setActiveWindowLocked(int windowId)1443 private void setActiveWindowLocked(int windowId) { 1444 if (mActiveWindowId != windowId) { 1445 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( 1446 AccessibilityEvent.obtainWindowsChangedEvent( 1447 mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)); 1448 1449 mActiveWindowId = windowId; 1450 // Goes through all windows for each display. 1451 final int count = mDisplayWindowsObservers.size(); 1452 for (int i = 0; i < count; i++) { 1453 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); 1454 if (observer != null) { 1455 observer.setActiveWindowLocked(windowId); 1456 } 1457 } 1458 } 1459 } 1460 setAccessibilityFocusedWindowLocked(int windowId)1461 private void setAccessibilityFocusedWindowLocked(int windowId) { 1462 if (mAccessibilityFocusedWindowId != windowId) { 1463 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked( 1464 AccessibilityEvent.obtainWindowsChangedEvent( 1465 mAccessibilityFocusedWindowId, 1466 WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)); 1467 1468 mAccessibilityFocusedWindowId = windowId; 1469 // Goes through all windows for each display. 1470 final int count = mDisplayWindowsObservers.size(); 1471 for (int i = 0; i < count; i++) { 1472 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); 1473 if (observer != null) { 1474 observer.setAccessibilityFocusedWindowLocked(windowId); 1475 } 1476 } 1477 } 1478 } 1479 1480 /** 1481 * Returns accessibility window info according to given windowId. 1482 * 1483 * @param windowId The windowId 1484 * @return The accessibility window info 1485 */ 1486 @Nullable findA11yWindowInfoByIdLocked(int windowId)1487 public AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) { 1488 windowId = resolveParentWindowIdLocked(windowId); 1489 final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId); 1490 if (observer != null) { 1491 return observer.findA11yWindowInfoByIdLocked(windowId); 1492 } 1493 return null; 1494 } 1495 1496 /** 1497 * Returns the window info according to given windowId. 1498 * 1499 * @param windowId The windowId 1500 * @return The window info 1501 */ 1502 @Nullable findWindowInfoByIdLocked(int windowId)1503 public WindowInfo findWindowInfoByIdLocked(int windowId) { 1504 windowId = resolveParentWindowIdLocked(windowId); 1505 final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId); 1506 if (observer != null) { 1507 return observer.findWindowInfoByIdLocked(windowId); 1508 } 1509 return null; 1510 } 1511 1512 /** 1513 * Returns focused windowId or accessibility focused windowId according to given focusType. 1514 * 1515 * @param focusType {@link AccessibilityNodeInfo#FOCUS_INPUT} or 1516 * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY} 1517 * @return The focused windowId 1518 */ getFocusedWindowId(int focusType)1519 public int getFocusedWindowId(int focusType) { 1520 if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) { 1521 return mTopFocusedWindowId; 1522 } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) { 1523 return mAccessibilityFocusedWindowId; 1524 } 1525 return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 1526 } 1527 1528 /** 1529 * Returns {@link AccessibilityWindowInfo} of PIP window. 1530 * 1531 * @return PIP accessibility window info 1532 */ 1533 @Nullable getPictureInPictureWindowLocked()1534 public AccessibilityWindowInfo getPictureInPictureWindowLocked() { 1535 AccessibilityWindowInfo windowInfo = null; 1536 final int count = mDisplayWindowsObservers.size(); 1537 for (int i = 0; i < count; i++) { 1538 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); 1539 if (observer != null) { 1540 if ((windowInfo = observer.getPictureInPictureWindowLocked()) != null) { 1541 break; 1542 } 1543 } 1544 } 1545 return windowInfo; 1546 } 1547 1548 /** 1549 * Sets an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture 1550 * window. 1551 */ setPictureInPictureActionReplacingConnection( @ullable IAccessibilityInteractionConnection connection)1552 public void setPictureInPictureActionReplacingConnection( 1553 @Nullable IAccessibilityInteractionConnection connection) throws RemoteException { 1554 synchronized (mLock) { 1555 if (mPictureInPictureActionReplacingConnection != null) { 1556 mPictureInPictureActionReplacingConnection.unlinkToDeath(); 1557 mPictureInPictureActionReplacingConnection = null; 1558 } 1559 if (connection != null) { 1560 RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection( 1561 AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID, 1562 connection, "foo.bar.baz", Process.SYSTEM_UID, UserHandle.USER_ALL); 1563 mPictureInPictureActionReplacingConnection = wrapper; 1564 wrapper.linkToDeath(); 1565 } 1566 } 1567 } 1568 1569 /** 1570 * Returns accessibility interaction connection for picture-in-picture window. 1571 */ 1572 @Nullable getPictureInPictureActionReplacingConnection()1573 public RemoteAccessibilityConnection getPictureInPictureActionReplacingConnection() { 1574 return mPictureInPictureActionReplacingConnection; 1575 } 1576 1577 /** 1578 * Invokes {@link IAccessibilityInteractionConnection#notifyOutsideTouch()} for windows that 1579 * have watch outside touch flag and its layer is upper than target window. 1580 */ notifyOutsideTouch(int userId, int targetWindowId)1581 public void notifyOutsideTouch(int userId, int targetWindowId) { 1582 final List<Integer> outsideWindowsIds; 1583 final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>(); 1584 synchronized (mLock) { 1585 final DisplayWindowsObserver observer = 1586 getDisplayWindowObserverByWindowIdLocked(targetWindowId); 1587 if (observer != null) { 1588 outsideWindowsIds = observer.getWatchOutsideTouchWindowIdLocked(targetWindowId); 1589 for (int i = 0; i < outsideWindowsIds.size(); i++) { 1590 connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i))); 1591 } 1592 } 1593 } 1594 for (int i = 0; i < connectionList.size(); i++) { 1595 final RemoteAccessibilityConnection connection = connectionList.get(i); 1596 if (connection != null) { 1597 if (traceIntConnEnabled()) { 1598 logTraceIntConn("notifyOutsideTouch"); 1599 } 1600 1601 try { 1602 connection.getRemote().notifyOutsideTouch(); 1603 } catch (RemoteException re) { 1604 if (DEBUG) { 1605 Slog.e(LOG_TAG, "Error calling notifyOutsideTouch()"); 1606 } 1607 } 1608 } 1609 } 1610 } 1611 1612 /** 1613 * Returns the display ID according to given userId and windowId. 1614 * 1615 * @param userId The userId 1616 * @param windowId The windowId 1617 * @return The display ID 1618 */ getDisplayIdByUserIdAndWindowIdLocked(int userId, int windowId)1619 public int getDisplayIdByUserIdAndWindowIdLocked(int userId, int windowId) { 1620 final IBinder windowToken = getWindowTokenForUserAndWindowIdLocked(userId, windowId); 1621 if (traceWMEnabled()) { 1622 logTraceWM("getDisplayIdForWindow", "token=" + windowToken); 1623 } 1624 final int displayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken); 1625 return displayId; 1626 } 1627 1628 /** 1629 * Returns the display list including all displays which are tracking windows. 1630 * 1631 * @return The display list. 1632 */ getDisplayListLocked()1633 public ArrayList<Integer> getDisplayListLocked() { 1634 final ArrayList<Integer> displayList = new ArrayList<>(); 1635 final int count = mDisplayWindowsObservers.size(); 1636 for (int i = 0; i < count; i++) { 1637 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); 1638 if (observer != null) { 1639 displayList.add(observer.mDisplayId); 1640 } 1641 } 1642 return displayList; 1643 } 1644 1645 /** 1646 * Gets current input focused window token from window manager, and returns its windowId. 1647 * 1648 * @param userId The userId 1649 * @return The input focused windowId, or -1 if not found 1650 */ findFocusedWindowId(int userId)1651 private int findFocusedWindowId(int userId) { 1652 if (traceWMEnabled()) { 1653 logTraceWM("getFocusedWindowToken", ""); 1654 } 1655 final IBinder token = mWindowManagerInternal.getFocusedWindowToken(); 1656 synchronized (mLock) { 1657 return findWindowIdLocked(userId, token); 1658 } 1659 } 1660 isValidUserForInteractionConnectionsLocked(int userId)1661 private boolean isValidUserForInteractionConnectionsLocked(int userId) { 1662 return mInteractionConnections.indexOfKey(userId) >= 0; 1663 } 1664 isValidUserForWindowTokensLocked(int userId)1665 private boolean isValidUserForWindowTokensLocked(int userId) { 1666 return mWindowTokens.indexOfKey(userId) >= 0; 1667 } 1668 getInteractionConnectionsForUserLocked( int userId)1669 private SparseArray<RemoteAccessibilityConnection> getInteractionConnectionsForUserLocked( 1670 int userId) { 1671 SparseArray<RemoteAccessibilityConnection> connection = mInteractionConnections.get( 1672 userId); 1673 if (connection == null) { 1674 connection = new SparseArray<>(); 1675 mInteractionConnections.put(userId, connection); 1676 } 1677 return connection; 1678 } 1679 getWindowTokensForUserLocked(int userId)1680 private SparseArray<IBinder> getWindowTokensForUserLocked(int userId) { 1681 SparseArray<IBinder> windowTokens = mWindowTokens.get(userId); 1682 if (windowTokens == null) { 1683 windowTokens = new SparseArray<>(); 1684 mWindowTokens.put(userId, windowTokens); 1685 } 1686 return windowTokens; 1687 } 1688 clearAccessibilityFocusLocked(int windowId)1689 private void clearAccessibilityFocusLocked(int windowId) { 1690 mHandler.sendMessage(obtainMessage( 1691 AccessibilityWindowManager::clearAccessibilityFocusMainThread, 1692 AccessibilityWindowManager.this, 1693 mAccessibilityUserManager.getCurrentUserIdLocked(), windowId)); 1694 } 1695 clearAccessibilityFocusMainThread(int userId, int windowId)1696 private void clearAccessibilityFocusMainThread(int userId, int windowId) { 1697 final RemoteAccessibilityConnection connection; 1698 synchronized (mLock) { 1699 connection = getConnectionLocked(userId, windowId); 1700 if (connection == null) { 1701 return; 1702 } 1703 } 1704 if (traceIntConnEnabled()) { 1705 logTraceIntConn("notifyOutsideTouch"); 1706 } 1707 try { 1708 connection.getRemote().clearAccessibilityFocus(); 1709 } catch (RemoteException re) { 1710 if (DEBUG) { 1711 Slog.e(LOG_TAG, "Error calling clearAccessibilityFocus()"); 1712 } 1713 } 1714 } 1715 getDisplayWindowObserverByWindowIdLocked(int windowId)1716 private DisplayWindowsObserver getDisplayWindowObserverByWindowIdLocked(int windowId) { 1717 final int count = mDisplayWindowsObservers.size(); 1718 for (int i = 0; i < count; i++) { 1719 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); 1720 if (observer != null) { 1721 if (observer.findWindowInfoByIdLocked(windowId) != null) { 1722 return mDisplayWindowsObservers.get(observer.mDisplayId); 1723 } 1724 } 1725 } 1726 return null; 1727 } 1728 traceWMEnabled()1729 private boolean traceWMEnabled() { 1730 return mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL); 1731 } 1732 logTraceWM(String methodName, String params)1733 private void logTraceWM(String methodName, String params) { 1734 mTraceManager.logTrace("WindowManagerInternal." + methodName, 1735 FLAGS_WINDOW_MANAGER_INTERNAL, params); 1736 } 1737 traceIntConnEnabled()1738 private boolean traceIntConnEnabled() { 1739 return mTraceManager.isA11yTracingEnabledForTypes( 1740 FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION); 1741 } 1742 logTraceIntConn(String methodName)1743 private void logTraceIntConn(String methodName) { 1744 mTraceManager.logTrace( 1745 LOG_TAG + "." + methodName, FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION); 1746 } 1747 1748 /** 1749 * Associate the token of the embedded view hierarchy to the host view hierarchy. 1750 * 1751 * @param embedded The leash token from the view root of embedded hierarchy 1752 * @param host The leash token from the view root of host hierarchy 1753 */ associateLocked(IBinder embedded, IBinder host)1754 void associateLocked(IBinder embedded, IBinder host) { 1755 mHostEmbeddedMap.put(embedded, host); 1756 } 1757 1758 /** 1759 * Clear the relationship of given token. 1760 * 1761 * @param token The leash token 1762 */ disassociateLocked(IBinder token)1763 void disassociateLocked(IBinder token) { 1764 mHostEmbeddedMap.remove(token); 1765 for (int i = mHostEmbeddedMap.size() - 1; i >= 0; i--) { 1766 if (mHostEmbeddedMap.valueAt(i).equals(token)) { 1767 mHostEmbeddedMap.removeAt(i); 1768 } 1769 } 1770 } 1771 1772 /** 1773 * Register the leash token with its windowId. 1774 * 1775 * @param token The token. 1776 * @param windowId The windowID. 1777 */ registerIdLocked(IBinder token, int windowId)1778 void registerIdLocked(IBinder token, int windowId) { 1779 mWindowIdMap.put(windowId, token); 1780 } 1781 1782 /** 1783 * Unregister the windowId and also disassociate its token. 1784 * 1785 * @param windowId The windowID 1786 */ unregisterIdLocked(int windowId)1787 void unregisterIdLocked(int windowId) { 1788 final IBinder token = mWindowIdMap.get(windowId); 1789 if (token == null) { 1790 return; 1791 } 1792 disassociateLocked(token); 1793 mWindowIdMap.remove(windowId); 1794 } 1795 1796 /** 1797 * Get the leash token by given windowID. 1798 * 1799 * @param windowId The windowID. 1800 * @return The token, or {@code NULL} if this windowID doesn't exist 1801 */ getTokenLocked(int windowId)1802 IBinder getTokenLocked(int windowId) { 1803 return mWindowIdMap.get(windowId); 1804 } 1805 1806 /** 1807 * Get the windowId by given leash token. 1808 * 1809 * @param token The token 1810 * @return The windowID, or -1 if the token doesn't exist 1811 */ getWindowIdLocked(IBinder token)1812 int getWindowIdLocked(IBinder token) { 1813 final int index = mWindowIdMap.indexOfValue(token); 1814 if (index == -1) { 1815 return index; 1816 } 1817 return mWindowIdMap.keyAt(index); 1818 } 1819 1820 /** 1821 * Get the leash token of the host hierarchy by given token. 1822 * 1823 * @param token The token 1824 * @return The token of host hierarchy, or {@code NULL} if no host exists 1825 */ getHostTokenLocked(IBinder token)1826 IBinder getHostTokenLocked(IBinder token) { 1827 return mHostEmbeddedMap.get(token); 1828 } 1829 1830 /** 1831 * Dumps all {@link AccessibilityWindowInfo}s here. 1832 */ dump(FileDescriptor fd, final PrintWriter pw, String[] args)1833 public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { 1834 final int count = mDisplayWindowsObservers.size(); 1835 for (int i = 0; i < count; i++) { 1836 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i); 1837 if (observer != null) { 1838 observer.dumpLocked(fd, pw, args); 1839 } 1840 } 1841 } 1842 } 1843