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