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