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