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