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