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.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
23 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
24 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
25 
26 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
27 import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
28 import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_PROXY;
29 
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 import android.graphics.Point;
33 import android.graphics.Region;
34 import android.os.Binder;
35 import android.os.Handler;
36 import android.os.IBinder;
37 import android.os.Process;
38 import android.os.RemoteException;
39 import android.os.SystemClock;
40 import android.os.UserHandle;
41 import android.text.TextUtils;
42 import android.util.ArrayMap;
43 import android.util.ArraySet;
44 import android.util.Slog;
45 import android.util.SparseArray;
46 import android.view.Display;
47 import android.view.IWindow;
48 import android.view.WindowInfo;
49 import android.view.WindowManager;
50 import android.view.accessibility.AccessibilityEvent;
51 import android.view.accessibility.AccessibilityNodeInfo;
52 import android.view.accessibility.AccessibilityWindowAttributes;
53 import android.view.accessibility.AccessibilityWindowInfo;
54 import android.view.accessibility.IAccessibilityInteractionConnection;
55 
56 import com.android.internal.annotations.VisibleForTesting;
57 import com.android.server.accessibility.AccessibilitySecurityPolicy.AccessibilityUserManager;
58 import com.android.server.utils.Slogf;
59 import com.android.server.wm.AccessibilityWindowsPopulator.AccessibilityWindow;
60 import com.android.server.wm.WindowManagerInternal;
61 
62 import java.io.FileDescriptor;
63 import java.io.PrintWriter;
64 import java.util.ArrayList;
65 import java.util.Arrays;
66 import java.util.Collections;
67 import java.util.List;
68 import java.util.Set;
69 import java.util.stream.Collectors;
70 
71 /**
72  * This class provides APIs for accessibility manager to manage {@link AccessibilityWindowInfo}s and
73  * {@link WindowInfo}s.
74  */
75 public class AccessibilityWindowManager {
76     private static final String LOG_TAG = "AccessibilityWindowManager";
77     private static final boolean DEBUG = false;
78     private static final boolean VERBOSE = false;
79 
80     private static int sNextWindowId;
81 
82     private final Region mTmpRegion = new Region();
83 
84     private final Object mLock;
85     private final Handler mHandler;
86     private final WindowManagerInternal mWindowManagerInternal;
87     private final AccessibilityEventSender mAccessibilityEventSender;
88     private final AccessibilitySecurityPolicy mSecurityPolicy;
89     private final AccessibilityUserManager mAccessibilityUserManager;
90     private final AccessibilityTraceManager mTraceManager;
91 
92     // Connections and window tokens for cross-user windows
93     private final SparseArray<RemoteAccessibilityConnection>
94             mGlobalInteractionConnections = new SparseArray<>();
95     private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
96 
97     // Connections and window tokens for per-user windows, indexed as one sparse array per user
98     private final SparseArray<SparseArray<RemoteAccessibilityConnection>>
99             mInteractionConnections = new SparseArray<>();
100     private final SparseArray<SparseArray<IBinder>> mWindowTokens = new SparseArray<>();
101 
102     private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
103     // There is only one active window in the system. It is updated when the top focused window
104     // of the top focused display changes and when we receive a TYPE_WINDOW_STATE_CHANGED event.
105     private int mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
106     // There is only one top focused window in the system. It is updated when the window manager
107     // updates the window lists.
108     private int mTopFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
109     private int mAccessibilityFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
110     private long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
111     // The top focused display and window token updated with the callback of window lists change.
112     private int mTopFocusedDisplayId;
113     private IBinder mTopFocusedWindowToken;
114 
115     // The non-proxy display that most recently had top focus.
116     private int mLastNonProxyTopFocusedDisplayId;
117     // The display has the accessibility focused window currently.
118     private int mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY;
119 
120     private boolean mTouchInteractionInProgress;
121 
122     private boolean mHasProxy;
123 
124     /** List of Display Windows Observer, mapping from displayId -> DisplayWindowsObserver. */
125     private final SparseArray<DisplayWindowsObserver> mDisplayWindowsObservers =
126             new SparseArray<>();
127 
128     /**
129      * Map of host view and embedded hierarchy, mapping from leash token of its ViewRootImpl.
130      * The key is the token from embedded hierarchy, and the value is the token from its host.
131      */
132     private final ArrayMap<IBinder, IBinder> mHostEmbeddedMap = new ArrayMap<>();
133 
134     /**
135      * Map of window id and view hierarchy.
136      * The key is the window id when the ViewRootImpl register to accessibility, and the value is
137      * its leash token.
138      */
139     private final SparseArray<IBinder> mWindowIdMap = new SparseArray<>();
140 
141     /**
142      * Map of window id and window attribute hierarchy.
143      * The key is the window id when the ViewRootImpl register to accessibility, and the value is
144      * its window attribute .
145      */
146     private final SparseArray<AccessibilityWindowAttributes> mWindowAttributes =
147             new SparseArray<>();
148 
149     /**
150      * Sets the {@link AccessibilityWindowAttributes} to the window associated with the given
151      * window id.
152      *
153      * @param displayId The display id of the window.
154      * @param windowId The id of the window
155      * @param userId The user id.
156      * @param attributes The accessibility window attributes.
157      */
setAccessibilityWindowAttributes(int displayId, int windowId, int userId, AccessibilityWindowAttributes attributes)158     public void setAccessibilityWindowAttributes(int displayId, int windowId, int userId,
159             AccessibilityWindowAttributes attributes) {
160         boolean shouldComputeWindows = false;
161         synchronized (mLock) {
162             final int resolvedUserId =
163                     mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(userId);
164             if (getWindowTokenForUserAndWindowIdLocked(resolvedUserId, windowId) == null) {
165                 return;
166             }
167             mWindowAttributes.put(windowId, attributes);
168             shouldComputeWindows = findWindowInfoByIdLocked(windowId) != null;
169         }
170         if (shouldComputeWindows) {
171             mWindowManagerInternal.computeWindowsForAccessibility(displayId);
172         }
173     }
174 
175     /**
176      * Returns {@code true} if the window belongs to a display of {@code displayTypes}.
177      */
windowIdBelongsToDisplayType(int focusedWindowId, int displayTypes)178     public boolean windowIdBelongsToDisplayType(int focusedWindowId, int displayTypes) {
179         if (!mHasProxy) {
180             return true;
181         }
182         // UIAutomation wants focus from any display type.
183         final int displayTypeMask = DISPLAY_TYPE_PROXY | DISPLAY_TYPE_DEFAULT;
184         if ((displayTypes & displayTypeMask) == displayTypeMask) {
185             return true;
186         }
187         synchronized (mLock) {
188             final int count = mDisplayWindowsObservers.size();
189             for (int i = 0; i < count; i++) {
190                 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
191                 if (observer != null
192                         && observer.findA11yWindowInfoByIdLocked(focusedWindowId) != null) {
193                     return observer.mIsProxy
194                             ? ((displayTypes & DISPLAY_TYPE_PROXY) != 0)
195                             : (displayTypes & DISPLAY_TYPE_DEFAULT) != 0;
196                 }
197             }
198         }
199         return false;
200     }
201 
202     /**
203      * This class implements {@link WindowManagerInternal.WindowsForAccessibilityCallback} to
204      * receive {@link WindowInfo}s from window manager when there's an accessibility change in
205      * window and holds window lists information per display.
206      */
207     private final class DisplayWindowsObserver implements
208             WindowManagerInternal.WindowsForAccessibilityCallback {
209 
210         private final int mDisplayId;
211         private final SparseArray<AccessibilityWindowInfo> mA11yWindowInfoById =
212                 new SparseArray<>();
213         private final SparseArray<WindowInfo> mWindowInfoById = new SparseArray<>();
214         private final List<WindowInfo> mCachedWindowInfos = new ArrayList<>();
215         private List<AccessibilityWindowInfo> mWindows;
216         private boolean mTrackingWindows = false;
217         private boolean mHasWatchOutsideTouchWindow;
218         private int mProxyDisplayAccessibilityFocusedWindow =
219                 AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
220         private boolean mIsProxy;
221 
222         /**
223          * Constructor for DisplayWindowsObserver.
224          */
DisplayWindowsObserver(int displayId)225         DisplayWindowsObserver(int displayId) {
226             if (DEBUG) {
227                 Slogf.d(LOG_TAG, "Creating DisplayWindowsObserver for displayId %d", displayId);
228             }
229             mDisplayId = displayId;
230         }
231 
232         /**
233          * Starts tracking windows changes from window manager by registering callback.
234          */
startTrackingWindowsLocked()235         void startTrackingWindowsLocked() {
236             if (!mTrackingWindows) {
237                 // Turns on the flag before setup the callback.
238                 // In some cases, onWindowsForAccessibilityChanged will be called immediately in
239                 // setWindowsForAccessibilityCallback. We'll lost windows if flag is false.
240                 mTrackingWindows = true;
241                 if (traceWMEnabled()) {
242                     logTraceWM("setWindowsForAccessibilityCallback",
243                             "displayId=" + mDisplayId + ";callback=" + this);
244                 }
245                 mWindowManagerInternal.setWindowsForAccessibilityCallback(
246                         mDisplayId, this);
247             }
248         }
249 
250         /**
251          * Stops tracking windows changes from window manager, and clear all windows info.
252          */
stopTrackingWindowsLocked()253         void stopTrackingWindowsLocked() {
254             if (mTrackingWindows) {
255                 if (traceWMEnabled()) {
256                     logTraceWM("setWindowsForAccessibilityCallback",
257                             "displayId=" + mDisplayId + ";callback=null");
258                 }
259                 mWindowManagerInternal.setWindowsForAccessibilityCallback(
260                         mDisplayId, null);
261                 mTrackingWindows = false;
262                 clearWindowsLocked();
263             }
264         }
265 
266         /**
267          * Returns true if windows changes tracking.
268          *
269          * @return true if windows changes tracking
270          */
isTrackingWindowsLocked()271         boolean isTrackingWindowsLocked() {
272             return mTrackingWindows;
273         }
274 
275         /**
276          * Returns accessibility windows.
277          * @return accessibility windows.
278          */
279         @Nullable
getWindowListLocked()280         List<AccessibilityWindowInfo> getWindowListLocked() {
281             return mWindows;
282         }
283 
284         /**
285          * Returns accessibility window info according to given windowId.
286          *
287          * @param windowId The windowId
288          * @return The accessibility window info
289          */
290         @Nullable
findA11yWindowInfoByIdLocked(int windowId)291         AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) {
292             return mA11yWindowInfoById.get(windowId);
293         }
294 
295         /**
296          * Returns the window info according to given windowId.
297          *
298          * @param windowId The windowId
299          * @return The window info
300          */
301         @Nullable
findWindowInfoByIdLocked(int windowId)302         WindowInfo findWindowInfoByIdLocked(int windowId) {
303             return mWindowInfoById.get(windowId);
304         }
305 
306         /**
307          * Returns {@link AccessibilityWindowInfo} of PIP window.
308          *
309          * @return PIP accessibility window info
310          */
311         @Nullable
getPictureInPictureWindowLocked()312         AccessibilityWindowInfo getPictureInPictureWindowLocked() {
313             if (mWindows != null) {
314                 final int windowCount = mWindows.size();
315                 for (int i = 0; i < windowCount; i++) {
316                     final AccessibilityWindowInfo window = mWindows.get(i);
317                     if (window.isInPictureInPictureMode()) {
318                         return window;
319                     }
320                 }
321             }
322             return null;
323         }
324 
325         /**
326          * Sets the active flag of the window according to given windowId, others set to inactive.
327          *
328          * @param windowId The windowId
329          * @return {@code true} if the window is in this display, {@code false} otherwise.
330          */
setActiveWindowLocked(int windowId)331         boolean setActiveWindowLocked(int windowId) {
332             boolean foundWindow = false;
333             if (mWindows != null) {
334                 final int windowCount = mWindows.size();
335                 for (int i = 0; i < windowCount; i++) {
336                     AccessibilityWindowInfo window = mWindows.get(i);
337                     if (window.getId() == windowId) {
338                         window.setActive(true);
339                         foundWindow = true;
340                     } else {
341                         window.setActive(false);
342                     }
343                 }
344             }
345             return foundWindow;
346         }
347 
348         /**
349          * Sets the window accessibility focused according to given windowId, others set
350          * unfocused.
351          *
352          * @param windowId The windowId
353          * @return {@code true} if the window is in this display, {@code false} otherwise.
354          */
setAccessibilityFocusedWindowLocked(int windowId)355         boolean setAccessibilityFocusedWindowLocked(int windowId) {
356             boolean foundWindow = false;
357             if (mWindows != null) {
358                 final int windowCount = mWindows.size();
359                 for (int i = 0; i < windowCount; i++) {
360                     AccessibilityWindowInfo window = mWindows.get(i);
361                     if (window.getId() == windowId) {
362                         window.setAccessibilityFocused(true);
363                         foundWindow = true;
364                     } else {
365                         window.setAccessibilityFocused(false);
366                     }
367                 }
368             }
369             return foundWindow;
370         }
371 
372         /**
373          * Computes partial interactive region of given windowId.
374          *
375          * @param windowId The windowId
376          * @param forceComputeRegion set outRegion when the windowId matches one on the screen even
377          *                           though the region is not covered by other windows above it.
378          * @param outRegion The output to which to write the bounds.
379          * @return {@code true} if outRegion is not empty.
380          */
computePartialInteractiveRegionForWindowLocked(int windowId, boolean forceComputeRegion, @NonNull Region outRegion)381         boolean computePartialInteractiveRegionForWindowLocked(int windowId,
382                 boolean forceComputeRegion, @NonNull Region outRegion) {
383             if (mWindows == null) {
384                 return false;
385             }
386 
387             // Windows are ordered in z order so start from the bottom and find
388             // the window of interest. After that all windows that cover it should
389             // be subtracted from the resulting region. Note that for accessibility
390             // we are returning only interactive windows.
391             Region windowInteractiveRegion = null;
392             boolean windowInteractiveRegionChanged = false;
393 
394             final int windowCount = mWindows.size();
395             final Region currentWindowRegions = new Region();
396             for (int i = windowCount - 1; i >= 0; i--) {
397                 AccessibilityWindowInfo currentWindow = mWindows.get(i);
398                 if (windowInteractiveRegion == null) {
399                     if (currentWindow.getId() == windowId) {
400                         currentWindow.getRegionInScreen(currentWindowRegions);
401                         outRegion.set(currentWindowRegions);
402                         windowInteractiveRegion = outRegion;
403                         if (forceComputeRegion) {
404                             windowInteractiveRegionChanged = true;
405                         }
406                         continue;
407                     }
408                 } else if (currentWindow.getType()
409                         != AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY) {
410                     currentWindow.getRegionInScreen(currentWindowRegions);
411                     if (windowInteractiveRegion.op(currentWindowRegions, Region.Op.DIFFERENCE)) {
412                         windowInteractiveRegionChanged = true;
413                     }
414                 }
415             }
416 
417             return windowInteractiveRegionChanged;
418         }
419 
getWatchOutsideTouchWindowIdLocked(int targetWindowId)420         List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) {
421             final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
422             if (targetWindow != null && mHasWatchOutsideTouchWindow) {
423                 final List<Integer> outsideWindowsId = new ArrayList<>();
424                 for (int i = 0; i < mWindowInfoById.size(); i++) {
425                     final WindowInfo window = mWindowInfoById.valueAt(i);
426                     if (window != null && window.layer < targetWindow.layer
427                             && window.hasFlagWatchOutsideTouch) {
428                         outsideWindowsId.add(mWindowInfoById.keyAt(i));
429                     }
430                 }
431                 return outsideWindowsId;
432             }
433             return Collections.emptyList();
434         }
435 
436         /**
437          * Callbacks from window manager when there's an accessibility change in windows.
438          *
439          * @param forceSend Send the windows for accessibility even if they haven't changed.
440          * @param topFocusedDisplayId The display Id which has the top focused window.
441          * @param topFocusedWindowToken The window token of top focused window.
442          * @param windows The windows for accessibility.
443          */
444         @Override
onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId, IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows)445         public void onWindowsForAccessibilityChanged(boolean forceSend, int topFocusedDisplayId,
446                 IBinder topFocusedWindowToken, @NonNull List<WindowInfo> windows) {
447             synchronized (mLock) {
448                 if (!Flags.computeWindowChangesOnA11yV2()) {
449                     // If the flag is enabled, it's already done in #createWindowInfoListLocked.
450                     updateWindowsByWindowAttributesLocked(windows);
451                 }
452                 if (DEBUG) {
453                     Slogf.i(LOG_TAG, "mDisplayId=%d, topFocusedDisplayId=%d, currentUserId=%d, "
454                                     + "visibleBgUsers=%s", mDisplayId, topFocusedDisplayId,
455                             mAccessibilityUserManager.getCurrentUserIdLocked(),
456                             mAccessibilityUserManager.getVisibleUserIdsLocked());
457                     if (VERBOSE) {
458                         Slogf.i(LOG_TAG, "%d windows changed: %s ", windows.size(), windows);
459                     } else {
460                         List<String> windowsInfo = windows.stream()
461                                 .map(w -> "{displayId=" + w.displayId + ", title=" + w.title + "}")
462                                 .collect(Collectors.toList());
463                         Slogf.i(LOG_TAG, "%d windows changed: %s", windows.size(), windowsInfo);
464                     }
465                 }
466                 if (shouldUpdateWindowsLocked(forceSend, windows)) {
467                     mTopFocusedDisplayId = topFocusedDisplayId;
468                     if (!isProxyed(topFocusedDisplayId)) {
469                         mLastNonProxyTopFocusedDisplayId = topFocusedDisplayId;
470                     }
471                     mTopFocusedWindowToken = topFocusedWindowToken;
472                     if (DEBUG) {
473                         Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): updating windows for "
474                                         + "display %d and token %s",
475                                 topFocusedDisplayId, topFocusedWindowToken);
476                     }
477                     cacheWindows(windows);
478                     // Lets the policy update the focused and active windows.
479                     updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(),
480                             windows);
481                     // Someone may be waiting for the windows - advertise it.
482                     mLock.notifyAll();
483                 }
484                 else if (DEBUG) {
485                     Slogf.d(LOG_TAG, "onWindowsForAccessibilityChanged(): NOT updating windows for "
486                                     + "display %d and token %s",
487                             topFocusedDisplayId, topFocusedWindowToken);
488                 }
489             }
490         }
491 
492         /**
493          * Called when the windows for accessibility changed. This is called if
494          * {@link com.android.server.accessibility.Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y_V2} is
495          * true.
496          *
497          * @param forceSend             Send the windows for accessibility even if they haven't
498          *                              changed.
499          * @param topFocusedDisplayId   The display Id which has the top focused window.
500          * @param topFocusedWindowToken The window token of top focused window.
501          * @param screenSize            The size of the display that the change happened.
502          * @param windows               The windows for accessibility.
503          */
504         @Override
onAccessibilityWindowsChanged(boolean forceSend, int topFocusedDisplayId, @NonNull IBinder topFocusedWindowToken, @NonNull Point screenSize, @NonNull List<AccessibilityWindow> windows)505         public void onAccessibilityWindowsChanged(boolean forceSend, int topFocusedDisplayId,
506                 @NonNull IBinder topFocusedWindowToken, @NonNull Point screenSize,
507                 @NonNull List<AccessibilityWindow> windows) {
508             synchronized (mLock) {
509                 final List<WindowInfo> windowInfoList =
510                         createWindowInfoListLocked(screenSize, windows);
511                 onWindowsForAccessibilityChanged(forceSend, topFocusedDisplayId,
512                         topFocusedWindowToken, windowInfoList);
513             }
514         }
515 
createWindowInfoListLocked(@onNull Point screenSize, @NonNull List<AccessibilityWindow> visibleWindows)516         private List<WindowInfo> createWindowInfoListLocked(@NonNull Point screenSize,
517                 @NonNull List<AccessibilityWindow> visibleWindows) {
518             final Set<IBinder> addedWindows = new ArraySet<>();
519             final List<WindowInfo> windows = new ArrayList<>();
520 
521             // Avoid allocating Region for each window.
522             final Region regionInWindow = new Region();
523             final Region touchableRegionInScreen = new Region();
524 
525             final int userId = mAccessibilityUserManager.getCurrentUserIdLocked();
526 
527             // Iterate until we figure out what is touchable for the entire screen.
528             boolean focusedWindowAdded = false;
529             final Region unaccountedSpace = new Region(0, 0, screenSize.x, screenSize.y);
530             for (final AccessibilityWindow a11yWindow : visibleWindows) {
531                 a11yWindow.getTouchableRegionInWindow(regionInWindow);
532 
533                 final WindowInfo window = a11yWindow.getWindowInfo();
534                 final int windowId = window.token != null
535                         ? findWindowIdLocked(userId, window.token)
536                         : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
537 
538                 if (windowMattersToAccessibilityLocked(a11yWindow, windowId, regionInWindow,
539                         unaccountedSpace)) {
540                     if (windowId >= 0) {
541                         // Even if token is null, the window will be used in calculating visible
542                         // windows, but is excluded from the accessibility window list.
543                         window.regionInScreen.set(regionInWindow);
544                         window.layer = addedWindows.size();
545                         updateWindowWithWindowAttributes(window, mWindowAttributes.get(windowId));
546 
547                         windows.add(window);
548                         addedWindows.add(window.token);
549                     }
550 
551                     if (windowMattersToUnaccountedSpaceComputation(a11yWindow)) {
552                         // Account for the space this window takes.
553                         a11yWindow.getTouchableRegionInScreen(touchableRegionInScreen);
554                         unaccountedSpace.op(touchableRegionInScreen, unaccountedSpace,
555                                 Region.Op.REVERSE_DIFFERENCE);
556                     }
557 
558                     focusedWindowAdded |= a11yWindow.isFocused();
559                 } else if (a11yWindow.isUntouchableNavigationBar()
560                         && a11yWindow.getSystemBarInsetsFrame() != null) {
561                     // If this widow is navigation bar without touchable region, accounting the
562                     // region of navigation bar inset because all touch events from this region
563                     // would be received by launcher, i.e. this region is a un-touchable one
564                     // for the application.
565                     unaccountedSpace.op(
566                             a11yWindow.getSystemBarInsetsFrame(),
567                             unaccountedSpace,
568                             Region.Op.REVERSE_DIFFERENCE);
569                 }
570 
571                 if (unaccountedSpace.isEmpty() && focusedWindowAdded) {
572                     break;
573                 }
574             }
575 
576             // Remove child/parent references to windows that were not added.
577             for (final WindowInfo window : windows) {
578                 if (!addedWindows.contains(window.parentToken)) {
579                     window.parentToken = null;
580                 }
581                 if (window.childTokens != null) {
582                     final int childTokenCount = window.childTokens.size();
583                     for (int j = childTokenCount - 1; j >= 0; j--) {
584                         if (!addedWindows.contains(window.childTokens.get(j))) {
585                             window.childTokens.remove(j);
586                         }
587                     }
588                     // Leave the child token list if empty.
589                 }
590             }
591 
592             return windows;
593         }
594 
windowMattersToAccessibilityLocked(AccessibilityWindow a11yWindow, int windowId, Region regionInScreen, Region unaccountedSpace)595         private boolean windowMattersToAccessibilityLocked(AccessibilityWindow a11yWindow,
596                 int windowId, Region regionInScreen, Region unaccountedSpace) {
597             if (a11yWindow.ignoreRecentsAnimationForAccessibility()) {
598                 return false;
599             }
600 
601             if (a11yWindow.isFocused()) {
602                 return true;
603             }
604 
605             // Ignore non-touchable windows, except the split-screen divider, which is
606             // occasionally non-touchable but still useful for identifying split-screen
607             // mode and the PIP menu.
608             if (!a11yWindow.isTouchable()
609                     && a11yWindow.getType() != TYPE_DOCK_DIVIDER && !a11yWindow.isPIPMenu()) {
610                 return false;
611             }
612 
613             if (isEmbeddedHierarchyWindowsLocked(windowId)) {
614                 return false;
615             }
616 
617             // If the window is completely covered by other windows - ignore.
618             if (!mTmpRegion.op(unaccountedSpace, regionInScreen, Region.Op.INTERSECT)) {
619                 return false;
620             }
621 
622             // Add windows of certain types not covered by modal windows.
623             if (isReportedWindowType(a11yWindow.getType())) {
624                 return true;
625             }
626 
627             return false;
628         }
629 
isReportedWindowType(int windowType)630         private static boolean isReportedWindowType(int windowType) {
631             return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
632                     && windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
633                     && windowType != WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
634                     && windowType != WindowManager.LayoutParams.TYPE_DRAG
635                     && windowType != WindowManager.LayoutParams.TYPE_INPUT_CONSUMER
636                     && windowType != WindowManager.LayoutParams.TYPE_POINTER
637                     && windowType != TYPE_MAGNIFICATION_OVERLAY
638                     && windowType != WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
639                     && windowType != WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
640                     && windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
641         }
642 
643         // Some windows should be excluded from unaccounted space computation, though they still
644         // should be reported
windowMattersToUnaccountedSpaceComputation( AccessibilityWindow a11yWindow)645         private static boolean windowMattersToUnaccountedSpaceComputation(
646                 AccessibilityWindow a11yWindow) {
647             // Do not account space of trusted non-touchable windows, except the split-screen
648             // divider.
649             // If it's not trusted, touch events are not sent to the windows behind it.
650             if (!a11yWindow.isTouchable()
651                     && (a11yWindow.getType() != TYPE_DOCK_DIVIDER)
652                     && a11yWindow.isTrustedOverlay()) {
653                 return false;
654             }
655 
656             if (a11yWindow.getType() == WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY) {
657                 return false;
658             }
659             return true;
660         }
661 
updateWindowsByWindowAttributesLocked(List<WindowInfo> windows)662         private void updateWindowsByWindowAttributesLocked(List<WindowInfo> windows) {
663             for (int i = windows.size() - 1; i >= 0; i--) {
664                 final WindowInfo windowInfo = windows.get(i);
665                 final IBinder token = windowInfo.token;
666                 final int windowId = findWindowIdLocked(
667                         mAccessibilityUserManager.getCurrentUserIdLocked(), token);
668                 updateWindowWithWindowAttributes(windowInfo, mWindowAttributes.get(windowId));
669             }
670         }
671 
updateWindowWithWindowAttributes(@onNull WindowInfo windowInfo, @Nullable AccessibilityWindowAttributes attributes)672         private void updateWindowWithWindowAttributes(@NonNull WindowInfo windowInfo,
673                 @Nullable AccessibilityWindowAttributes attributes) {
674             if (attributes == null) {
675                 return;
676             }
677             windowInfo.title = attributes.getWindowTitle();
678             windowInfo.locales = attributes.getLocales();
679         }
680 
shouldUpdateWindowsLocked(boolean forceSend, @NonNull List<WindowInfo> windows)681         private boolean shouldUpdateWindowsLocked(boolean forceSend,
682                 @NonNull List<WindowInfo> windows) {
683             if (forceSend) {
684                 return true;
685             }
686 
687             final int windowCount = windows.size();
688             if (VERBOSE) {
689                 Slogf.v(LOG_TAG,
690                         "shouldUpdateWindowsLocked(): mDisplayId=%d, windowCount=%d, "
691                         + "mCachedWindowInfos.size()=%d, windows.size()=%d", mDisplayId,
692                         windowCount, mCachedWindowInfos.size(), windows.size());
693             }
694             // We computed the windows and if they changed notify the client.
695             if (mCachedWindowInfos.size() != windowCount) {
696                 // Different size means something changed.
697                 return true;
698             } else if (!mCachedWindowInfos.isEmpty() || !windows.isEmpty()) {
699                 // Since we always traverse windows from high to low layer
700                 // the old and new windows at the same index should be the
701                 // same, otherwise something changed.
702                 for (int i = 0; i < windowCount; i++) {
703                     WindowInfo oldWindow = mCachedWindowInfos.get(i);
704                     WindowInfo newWindow = windows.get(i);
705                     // We do not care for layer changes given the window
706                     // order does not change. This brings no new information
707                     // to the clients.
708                     if (windowChangedNoLayer(oldWindow, newWindow)) {
709                         return true;
710                     }
711                 }
712             }
713 
714             return false;
715         }
716 
cacheWindows(List<WindowInfo> windows)717         private void cacheWindows(List<WindowInfo> windows) {
718             final int oldWindowCount = mCachedWindowInfos.size();
719             for (int i = oldWindowCount - 1; i >= 0; i--) {
720                 mCachedWindowInfos.remove(i).recycle();
721             }
722             final int newWindowCount = windows.size();
723             for (int i = 0; i < newWindowCount; i++) {
724                 WindowInfo newWindow = windows.get(i);
725                 mCachedWindowInfos.add(WindowInfo.obtain(newWindow));
726             }
727         }
728 
windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow)729         private boolean windowChangedNoLayer(WindowInfo oldWindow, WindowInfo newWindow) {
730             if (oldWindow == newWindow) {
731                 return false;
732             }
733             if (oldWindow == null) {
734                 return true;
735             }
736             if (newWindow == null) {
737                 return true;
738             }
739             if (oldWindow.type != newWindow.type) {
740                 return true;
741             }
742             if (oldWindow.focused != newWindow.focused) {
743                 return true;
744             }
745             if (oldWindow.token == null) {
746                 if (newWindow.token != null) {
747                     return true;
748                 }
749             } else if (!oldWindow.token.equals(newWindow.token)) {
750                 return true;
751             }
752             if (oldWindow.parentToken == null) {
753                 if (newWindow.parentToken != null) {
754                     return true;
755                 }
756             } else if (!oldWindow.parentToken.equals(newWindow.parentToken)) {
757                 return true;
758             }
759             if (oldWindow.activityToken == null) {
760                 if (newWindow.activityToken != null) {
761                     return true;
762                 }
763             } else if (!oldWindow.activityToken.equals(newWindow.activityToken)) {
764                 return true;
765             }
766             if (!oldWindow.regionInScreen.equals(newWindow.regionInScreen)) {
767                 return true;
768             }
769             if (oldWindow.childTokens != null && newWindow.childTokens != null
770                     && !oldWindow.childTokens.equals(newWindow.childTokens)) {
771                 return true;
772             }
773             if (!TextUtils.equals(oldWindow.title, newWindow.title)) {
774                 return true;
775             }
776             if (oldWindow.accessibilityIdOfAnchor != newWindow.accessibilityIdOfAnchor) {
777                 return true;
778             }
779             if (oldWindow.inPictureInPicture != newWindow.inPictureInPicture) {
780                 return true;
781             }
782             if (oldWindow.hasFlagWatchOutsideTouch != newWindow.hasFlagWatchOutsideTouch) {
783                 return true;
784             }
785             if (oldWindow.displayId != newWindow.displayId) {
786                 return true;
787             }
788             if (oldWindow.taskId != newWindow.taskId) {
789                 return true;
790             }
791             if (!Arrays.equals(oldWindow.mTransformMatrix, newWindow.mTransformMatrix)) {
792                 return true;
793             }
794             return false;
795         }
796 
797         /**
798          * Clears all {@link AccessibilityWindowInfo}s and {@link WindowInfo}s.
799          */
clearWindowsLocked()800         private void clearWindowsLocked() {
801             final List<WindowInfo> windows = Collections.emptyList();
802             final int activeWindowId = mActiveWindowId;
803             // UserId is useless in updateWindowsLocked, when we update a empty window list.
804             // Just pass current userId here.
805             updateWindowsLocked(mAccessibilityUserManager.getCurrentUserIdLocked(), windows);
806             // Do not reset mActiveWindowId here. mActiveWindowId will be clear after accessibility
807             // interaction connection removed.
808             mActiveWindowId = activeWindowId;
809             mWindows = null;
810         }
811 
812         /**
813          * Updates windows info according to specified userId and windows.
814          *
815          * @param userId The userId to update
816          * @param windows The windows to update
817          */
updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows)818         private void updateWindowsLocked(int userId, @NonNull List<WindowInfo> windows) {
819             if (mWindows == null) {
820                 mWindows = new ArrayList<>();
821             }
822 
823             final List<AccessibilityWindowInfo> oldWindowList = new ArrayList<>(mWindows);
824             final SparseArray<AccessibilityWindowInfo> oldWindowsById = mA11yWindowInfoById.clone();
825             boolean shouldClearAccessibilityFocus = false;
826 
827             mWindows.clear();
828             mA11yWindowInfoById.clear();
829 
830             for (int i = 0; i < mWindowInfoById.size(); i++) {
831                 mWindowInfoById.valueAt(i).recycle();
832             }
833             mWindowInfoById.clear();
834             mHasWatchOutsideTouchWindow = false;
835 
836             final int windowCount = windows.size();
837             final boolean isTopFocusedDisplay = mDisplayId == mTopFocusedDisplayId;
838             // A proxy with an a11y-focused window is a11y-focused should use the proxy focus id.
839             final boolean isAccessibilityFocusedDisplay =
840                     mDisplayId == mAccessibilityFocusedDisplayId
841                             || (mIsProxy && mProxyDisplayAccessibilityFocusedWindow
842                                     != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
843             // Modifies the value of top focused window, active window and a11y focused window
844             // only if this display is top focused display which has the top focused window.
845             if (isTopFocusedDisplay) {
846                 if (windowCount > 0) {
847                     // Sets the top focus window by top focused window token.
848                     mTopFocusedWindowId = findWindowIdLocked(userId, mTopFocusedWindowToken);
849                 } else {
850                     // Resets the top focus window when stopping tracking window of this display.
851                     mTopFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
852                 }
853                 // The active window doesn't need to be reset if the touch operation is progressing.
854                 if (!mTouchInteractionInProgress) {
855                     mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
856                 }
857             }
858 
859             // If the active window goes away while the user is touch exploring we
860             // reset the active window id and wait for the next hover event from
861             // under the user's finger to determine which one is the new one. It
862             // is possible that the finger is not moving and the input system
863             // filters out such events.
864             boolean activeWindowGone = true;
865 
866             // We'll clear accessibility focus if the window with focus is no longer visible to
867             // accessibility services.
868             int a11yFocusedWindowId = mIsProxy
869                     ? mProxyDisplayAccessibilityFocusedWindow
870                     : mAccessibilityFocusedWindowId;
871             if (isAccessibilityFocusedDisplay) {
872                 shouldClearAccessibilityFocus = a11yFocusedWindowId
873                         != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
874             }
875 
876             boolean hasWindowIgnore = false;
877             if (windowCount > 0) {
878                 for (int i = 0; i < windowCount; i++) {
879                     final WindowInfo windowInfo = windows.get(i);
880                     final AccessibilityWindowInfo window;
881                     if (mTrackingWindows) {
882                         window = populateReportedWindowLocked(userId, windowInfo, oldWindowsById);
883                         if (window == null) {
884                             hasWindowIgnore = true;
885                         }
886                     } else {
887                         window = null;
888                     }
889                     if (window != null) {
890 
891                         // Flip layers in list to be consistent with AccessibilityService#getWindows
892                         window.setLayer(windowCount - 1 - window.getLayer());
893 
894                         final int windowId = window.getId();
895                         if (window.isFocused() && isTopFocusedDisplay) {
896                             if (!mTouchInteractionInProgress) {
897                                 // This display is top one, and sets the focus window
898                                 // as active window.
899                                 mActiveWindowId = windowId;
900                                 window.setActive(true);
901                             } else if (windowId == mActiveWindowId) {
902                                 activeWindowGone = false;
903                             }
904                         }
905                         if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) {
906                             mHasWatchOutsideTouchWindow = true;
907                         }
908                         mWindows.add(window);
909                         mA11yWindowInfoById.put(windowId, window);
910                         mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo));
911                     }
912                 }
913                 final int accessibilityWindowCount = mWindows.size();
914                 // Re-order the window layer of all windows in the windows list because there's
915                 // window not been added into the windows list.
916                 if (hasWindowIgnore) {
917                     for (int i = 0; i < accessibilityWindowCount; i++) {
918                         mWindows.get(i).setLayer(accessibilityWindowCount - 1 - i);
919                     }
920                 }
921                 if (isTopFocusedDisplay) {
922                     if (mTouchInteractionInProgress && activeWindowGone) {
923                         mActiveWindowId = mTopFocusedWindowId;
924                     }
925                     // Focused window may change the active one, so set the
926                     // active window once we decided which it is.
927                     for (int i = 0; i < accessibilityWindowCount; i++) {
928                         final AccessibilityWindowInfo window = mWindows.get(i);
929                         if (window.getId() == mActiveWindowId) {
930                             window.setActive(true);
931                         }
932                     }
933                 }
934                 if (isAccessibilityFocusedDisplay) {
935                     for (int i = 0; i < accessibilityWindowCount; i++) {
936                         final AccessibilityWindowInfo window = mWindows.get(i);
937                         if (window.getId() == a11yFocusedWindowId) {
938                             window.setAccessibilityFocused(true);
939                             shouldClearAccessibilityFocus = false;
940                             break;
941                         }
942                     }
943                 }
944             }
945 
946             sendEventsForChangedWindowsLocked(oldWindowList, oldWindowsById);
947 
948             final int oldWindowCount = oldWindowList.size();
949             for (int i = oldWindowCount - 1; i >= 0; i--) {
950                 oldWindowList.remove(i).recycle();
951             }
952 
953             if (shouldClearAccessibilityFocus) {
954                 clearAccessibilityFocusLocked(a11yFocusedWindowId);
955             }
956         }
957 
sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows, SparseArray<AccessibilityWindowInfo> oldWindowsById)958         private void sendEventsForChangedWindowsLocked(List<AccessibilityWindowInfo> oldWindows,
959                 SparseArray<AccessibilityWindowInfo> oldWindowsById) {
960             List<AccessibilityEvent> events = new ArrayList<>();
961             // Sends events for all removed windows.
962             final int oldWindowsCount = oldWindows.size();
963             for (int i = 0; i < oldWindowsCount; i++) {
964                 final AccessibilityWindowInfo window = oldWindows.get(i);
965                 if (mA11yWindowInfoById.get(window.getId()) == null) {
966                     events.add(AccessibilityEvent.obtainWindowsChangedEvent(
967                             mDisplayId, window.getId(), AccessibilityEvent.WINDOWS_CHANGE_REMOVED));
968                 }
969             }
970 
971             // Looks for other changes.
972             final int newWindowCount = mWindows.size();
973             for (int i = 0; i < newWindowCount; i++) {
974                 final AccessibilityWindowInfo newWindow = mWindows.get(i);
975                 final AccessibilityWindowInfo oldWindow = oldWindowsById.get(newWindow.getId());
976                 if (oldWindow == null) {
977                     events.add(AccessibilityEvent.obtainWindowsChangedEvent(mDisplayId,
978                             newWindow.getId(), AccessibilityEvent.WINDOWS_CHANGE_ADDED));
979                 } else {
980                     int changes = newWindow.differenceFrom(oldWindow);
981                     if (changes !=  0) {
982                         events.add(AccessibilityEvent.obtainWindowsChangedEvent(
983                                 mDisplayId, newWindow.getId(), changes));
984                     }
985                 }
986             }
987 
988             final int numEvents = events.size();
989             for (int i = 0; i < numEvents; i++) {
990                 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(events.get(i));
991             }
992         }
993 
populateReportedWindowLocked(int userId, WindowInfo window, SparseArray<AccessibilityWindowInfo> oldWindowsById)994         private AccessibilityWindowInfo populateReportedWindowLocked(int userId,
995                 WindowInfo window, SparseArray<AccessibilityWindowInfo> oldWindowsById) {
996             final int windowId = findWindowIdLocked(userId, window.token);
997 
998             // With the flag enabled, createWindowInfoListLocked() already removes invalid windows.
999             if (!Flags.computeWindowChangesOnA11yV2()) {
1000                 if (windowId < 0) {
1001                     return null;
1002                 }
1003 
1004                 // Don't need to add the embedded hierarchy windows into the a11y windows list.
1005                 if (isEmbeddedHierarchyWindowsLocked(windowId)) {
1006                     return null;
1007                 }
1008             }
1009 
1010             final AccessibilityWindowInfo reportedWindow = AccessibilityWindowInfo.obtain();
1011 
1012             reportedWindow.setId(windowId);
1013             reportedWindow.setType(getTypeForWindowManagerWindowType(window.type));
1014             reportedWindow.setLayer(window.layer);
1015             reportedWindow.setFocused(window.focused);
1016             reportedWindow.setRegionInScreen(window.regionInScreen);
1017             reportedWindow.setTitle(window.title);
1018             reportedWindow.setAnchorId(window.accessibilityIdOfAnchor);
1019             reportedWindow.setPictureInPicture(window.inPictureInPicture);
1020             reportedWindow.setDisplayId(window.displayId);
1021             reportedWindow.setTaskId(window.taskId);
1022             reportedWindow.setLocales(window.locales);
1023 
1024             final int parentId = findWindowIdLocked(userId, window.parentToken);
1025             if (parentId >= 0) {
1026                 reportedWindow.setParentId(parentId);
1027             }
1028 
1029             if (window.childTokens != null) {
1030                 final int childCount = window.childTokens.size();
1031                 for (int i = 0; i < childCount; i++) {
1032                     final IBinder childToken = window.childTokens.get(i);
1033                     final int childId = findWindowIdLocked(userId, childToken);
1034                     if (childId >= 0) {
1035                         reportedWindow.addChild(childId);
1036                     }
1037                 }
1038             }
1039 
1040             final AccessibilityWindowInfo oldWindowInfo = oldWindowsById.get(windowId);
1041             if (oldWindowInfo == null) {
1042                 reportedWindow.setTransitionTimeMillis(SystemClock.uptimeMillis());
1043             } else {
1044                 final Region oldTouchRegion = new Region();
1045                 oldWindowInfo.getRegionInScreen(oldTouchRegion);
1046                 if (oldTouchRegion.equals(window.regionInScreen)) {
1047                     reportedWindow.setTransitionTimeMillis(oldWindowInfo.getTransitionTimeMillis());
1048                 } else {
1049                     reportedWindow.setTransitionTimeMillis(SystemClock.uptimeMillis());
1050                 }
1051             }
1052             return reportedWindow;
1053         }
1054 
getTypeForWindowManagerWindowType(int windowType)1055         private int getTypeForWindowManagerWindowType(int windowType) {
1056             switch (windowType) {
1057                 case WindowManager.LayoutParams.TYPE_APPLICATION:
1058                 case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
1059                 case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
1060                 case WindowManager.LayoutParams.TYPE_APPLICATION_STARTING:
1061                 case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
1062                 case WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL:
1063                 case WindowManager.LayoutParams.TYPE_BASE_APPLICATION:
1064                 case WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION:
1065                 case WindowManager.LayoutParams.TYPE_PHONE:
1066                 case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
1067                 case WindowManager.LayoutParams.TYPE_TOAST:
1068                 case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
1069                 case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG: {
1070                     return AccessibilityWindowInfo.TYPE_APPLICATION;
1071                 }
1072 
1073                 case WindowManager.LayoutParams.TYPE_INPUT_METHOD: {
1074                     return AccessibilityWindowInfo.TYPE_INPUT_METHOD;
1075                 }
1076 
1077                 case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
1078                 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
1079                 case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
1080                 case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
1081                 case WindowManager.LayoutParams.TYPE_STATUS_BAR:
1082                 case WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE:
1083                 case WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL:
1084                 case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
1085                 case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
1086                 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
1087                 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
1088                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
1089                 case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
1090                 case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
1091                 case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
1092                     return AccessibilityWindowInfo.TYPE_SYSTEM;
1093                 }
1094 
1095                 case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
1096                     return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER;
1097                 }
1098 
1099                 case TYPE_ACCESSIBILITY_OVERLAY: {
1100                     return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
1101                 }
1102 
1103                 case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY: {
1104                     return AccessibilityWindowInfo.TYPE_MAGNIFICATION_OVERLAY;
1105                 }
1106 
1107                 default: {
1108                     return -1;
1109                 }
1110             }
1111         }
1112 
1113         /**
1114          * Dumps all {@link AccessibilityWindowInfo}s here.
1115          */
dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args)1116         void dumpLocked(FileDescriptor fd, final PrintWriter pw, String[] args) {
1117             if (mIsProxy) {
1118                 pw.println("Proxy accessibility focused window = "
1119                         + mProxyDisplayAccessibilityFocusedWindow);
1120                 pw.println();
1121             }
1122             if (mWindows != null) {
1123                 final int windowCount = mWindows.size();
1124                 for (int j = 0; j < windowCount; j++) {
1125                     if (j == 0) {
1126                         pw.append("Display[");
1127                         pw.append(Integer.toString(mDisplayId));
1128                         pw.append("] : ");
1129                         pw.println();
1130                     }
1131                     if (j > 0) {
1132                         pw.append(',');
1133                         pw.println();
1134                     }
1135                     pw.append("A11yWindow[");
1136                     AccessibilityWindowInfo window = mWindows.get(j);
1137                     pw.append(window.toString());
1138                     pw.append(']');
1139                     pw.println();
1140                     final WindowInfo windowInfo = findWindowInfoByIdLocked(window.getId());
1141                     if (windowInfo != null) {
1142                         pw.append("WindowInfo[");
1143                         pw.append(windowInfo.toString());
1144                         pw.append("]");
1145                         pw.println();
1146                     }
1147 
1148                 }
1149                 pw.println();
1150             }
1151         }
1152 
1153     }
1154     /**
1155      * Interface to send {@link AccessibilityEvent}.
1156      */
1157     public interface AccessibilityEventSender {
1158         /**
1159          * Sends {@link AccessibilityEvent} for current user.
1160          */
sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event)1161         void sendAccessibilityEventForCurrentUserLocked(AccessibilityEvent event);
1162     }
1163 
1164     /**
1165      * Wrapper of accessibility interaction connection for window.
1166      */
1167     // In order to avoid using DexmakerShareClassLoaderRule, make this class visible for testing.
1168     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
1169     public final class RemoteAccessibilityConnection implements IBinder.DeathRecipient {
1170         private final int mUid;
1171         private final String mPackageName;
1172         private final int mWindowId;
1173         private final int mUserId;
1174         private final IAccessibilityInteractionConnection mConnection;
1175 
RemoteAccessibilityConnection(int windowId, IAccessibilityInteractionConnection connection, String packageName, int uid, int userId)1176         RemoteAccessibilityConnection(int windowId,
1177                 IAccessibilityInteractionConnection connection,
1178                 String packageName, int uid, int userId) {
1179             mWindowId = windowId;
1180             mPackageName = packageName;
1181             mUid = uid;
1182             mUserId = userId;
1183             mConnection = connection;
1184         }
1185 
getUid()1186         int getUid() {
1187             return  mUid;
1188         }
1189 
getPackageName()1190         String getPackageName() {
1191             return mPackageName;
1192         }
1193 
getRemote()1194         IAccessibilityInteractionConnection getRemote() {
1195             return mConnection;
1196         }
1197 
linkToDeath()1198         void linkToDeath() throws RemoteException {
1199             mConnection.asBinder().linkToDeath(this, 0);
1200         }
1201 
unlinkToDeath()1202         void unlinkToDeath() {
1203             mConnection.asBinder().unlinkToDeath(this, 0);
1204         }
1205 
1206         @Override
binderDied()1207         public void binderDied() {
1208             unlinkToDeath();
1209             synchronized (mLock) {
1210                 removeAccessibilityInteractionConnectionLocked(mWindowId, mUserId);
1211             }
1212         }
1213     }
1214 
1215     /**
1216      * Constructor for AccessibilityWindowManager.
1217      */
AccessibilityWindowManager(@onNull Object lock, @NonNull Handler handler, @NonNull WindowManagerInternal windowManagerInternal, @NonNull AccessibilityEventSender accessibilityEventSender, @NonNull AccessibilitySecurityPolicy securityPolicy, @NonNull AccessibilityUserManager accessibilityUserManager, @NonNull AccessibilityTraceManager traceManager)1218     public AccessibilityWindowManager(@NonNull Object lock, @NonNull Handler handler,
1219             @NonNull WindowManagerInternal windowManagerInternal,
1220             @NonNull AccessibilityEventSender accessibilityEventSender,
1221             @NonNull AccessibilitySecurityPolicy securityPolicy,
1222             @NonNull AccessibilityUserManager accessibilityUserManager,
1223             @NonNull AccessibilityTraceManager traceManager) {
1224         mLock = lock;
1225         mHandler = handler;
1226         mWindowManagerInternal = windowManagerInternal;
1227         mAccessibilityEventSender = accessibilityEventSender;
1228         mSecurityPolicy = securityPolicy;
1229         mAccessibilityUserManager = accessibilityUserManager;
1230         mTraceManager = traceManager;
1231     }
1232 
1233     /**
1234      * Starts tracking windows changes from window manager for specified display.
1235      *
1236      * @param displayId The logical display id.
1237      */
startTrackingWindows(int displayId, boolean proxyed)1238     public void startTrackingWindows(int displayId, boolean proxyed) {
1239         synchronized (mLock) {
1240             DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
1241             if (observer == null) {
1242                 observer = new DisplayWindowsObserver(displayId);
1243             }
1244             if (proxyed && !observer.mIsProxy) {
1245                 observer.mIsProxy = true;
1246                 mHasProxy = true;
1247             }
1248             if (observer.isTrackingWindowsLocked()) {
1249                 return;
1250             }
1251             observer.startTrackingWindowsLocked();
1252             mDisplayWindowsObservers.put(displayId, observer);
1253         }
1254     }
1255 
1256     /**
1257      * Stops tracking windows changes from window manager, and clear all windows info for specified
1258      * display.
1259      *
1260      * @param displayId The logical display id.
1261      */
stopTrackingWindows(int displayId)1262     public void stopTrackingWindows(int displayId) {
1263         synchronized (mLock) {
1264             final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
1265             if (observer != null) {
1266                 observer.stopTrackingWindowsLocked();
1267                 mDisplayWindowsObservers.remove(displayId);
1268             }
1269             resetHasProxyIfNeededLocked();
1270         }
1271     }
1272 
1273     /**
1274      * Stops tracking a display as belonging to a proxy.
1275      * @param displayId
1276      */
stopTrackingDisplayProxy(int displayId)1277     public void stopTrackingDisplayProxy(int displayId) {
1278         synchronized (mLock) {
1279             final DisplayWindowsObserver proxyObserver = mDisplayWindowsObservers.get(displayId);
1280             if (proxyObserver != null) {
1281                 proxyObserver.mIsProxy = false;
1282             }
1283             resetHasProxyIfNeededLocked();
1284         }
1285     }
1286 
resetHasProxyIfNeededLocked()1287     private void resetHasProxyIfNeededLocked() {
1288         boolean hasProxy = false;
1289         final int count = mDisplayWindowsObservers.size();
1290         for (int i = 0; i < count; i++) {
1291             final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
1292             if (observer != null) {
1293                 if (observer.mIsProxy) {
1294                     hasProxy = true;
1295                 }
1296             }
1297         }
1298         mHasProxy = hasProxy;
1299     }
1300 
1301     /**
1302      * Checks if we are tracking windows on any display.
1303      *
1304      * @return {@code true} if the observer is tracking windows on any display,
1305      * {@code false} otherwise.
1306      */
isTrackingWindowsLocked()1307     public boolean isTrackingWindowsLocked() {
1308         final int count = mDisplayWindowsObservers.size();
1309         if (count > 0) {
1310             return true;
1311         }
1312         return false;
1313     }
1314 
isProxyed(int displayId)1315     private boolean isProxyed(int displayId) {
1316         final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
1317         return (observer != null && observer.mIsProxy);
1318     }
1319 
moveNonProxyTopFocusedDisplayToTopIfNeeded()1320     void moveNonProxyTopFocusedDisplayToTopIfNeeded() {
1321         if (mHasProxy
1322                 && (mLastNonProxyTopFocusedDisplayId != mTopFocusedDisplayId)) {
1323             mWindowManagerInternal.moveDisplayToTopIfAllowed(mLastNonProxyTopFocusedDisplayId);
1324         }
1325     }
getLastNonProxyTopFocusedDisplayId()1326     int getLastNonProxyTopFocusedDisplayId() {
1327         return mLastNonProxyTopFocusedDisplayId;
1328     }
1329 
1330     /**
1331      * Checks if we are tracking windows on specified display.
1332      *
1333      * @param displayId The logical display id.
1334      * @return {@code true} if the observer is tracking windows on specified display,
1335      * {@code false} otherwise.
1336      */
isTrackingWindowsLocked(int displayId)1337     public boolean isTrackingWindowsLocked(int displayId) {
1338         final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
1339         if (observer != null) {
1340             return observer.isTrackingWindowsLocked();
1341         }
1342         return false;
1343     }
1344 
1345     /**
1346      * Returns accessibility windows for specified display.
1347      *
1348      * @param displayId The logical display id.
1349      * @return accessibility windows for specified display.
1350      */
1351     @Nullable
getWindowListLocked(int displayId)1352     public List<AccessibilityWindowInfo> getWindowListLocked(int displayId) {
1353         final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
1354         if (observer != null) {
1355             return observer.getWindowListLocked();
1356         }
1357         return null;
1358     }
1359 
1360     /**
1361      * Adds accessibility interaction connection according to given window token, package name and
1362      * window token.
1363      *
1364      * @param window The window token of accessibility interaction connection
1365      * @param leashToken The leash token of accessibility interaction connection
1366      * @param connection The accessibility interaction connection
1367      * @param packageName The package name
1368      * @param userId The userId
1369      * @return The windowId of added connection
1370      * @throws RemoteException
1371      */
addAccessibilityInteractionConnection(@onNull IWindow window, @NonNull IBinder leashToken, @NonNull IAccessibilityInteractionConnection connection, @NonNull String packageName, int userId)1372     public int addAccessibilityInteractionConnection(@NonNull IWindow window,
1373             @NonNull IBinder leashToken, @NonNull IAccessibilityInteractionConnection connection,
1374             @NonNull String packageName, int userId) throws RemoteException {
1375         final int windowId;
1376         boolean shouldComputeWindows = false;
1377         final IBinder token = window.asBinder();
1378         if (traceWMEnabled()) {
1379             logTraceWM("getDisplayIdForWindow", "token=" + token);
1380         }
1381         final int displayId = mWindowManagerInternal.getDisplayIdForWindow(token);
1382         synchronized (mLock) {
1383             // We treat calls from a profile as if made by its parent as profiles
1384             // share the accessibility state of the parent. The call below
1385             // performs the current profile parent resolution.
1386             final int resolvedUserId = mSecurityPolicy
1387                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
1388             final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId());
1389 
1390             // Makes sure the reported package is one the caller has access to.
1391             packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
1392                     packageName, UserHandle.getCallingAppId(), resolvedUserId,
1393                     Binder.getCallingPid());
1394 
1395             windowId = sNextWindowId++;
1396             // If the window is from a process that runs across users such as
1397             // the system UI or the system we add it to the global state that
1398             // is shared across users.
1399             if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
1400                 RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
1401                         windowId, connection, packageName, resolvedUid, UserHandle.USER_ALL);
1402                 wrapper.linkToDeath();
1403                 mGlobalInteractionConnections.put(windowId, wrapper);
1404                 mGlobalWindowTokens.put(windowId, token);
1405                 if (DEBUG) {
1406                     Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
1407                             + " with windowId: " + windowId + " and token: " + token);
1408                 }
1409             } else {
1410                 RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
1411                         windowId, connection, packageName, resolvedUid, resolvedUserId);
1412                 wrapper.linkToDeath();
1413                 getInteractionConnectionsForUserLocked(resolvedUserId).put(windowId, wrapper);
1414                 getWindowTokensForUserLocked(resolvedUserId).put(windowId, token);
1415                 if (DEBUG) {
1416                     Slog.i(LOG_TAG, "Added user connection for pid:" + Binder.getCallingPid()
1417                             + " with windowId: " + windowId + " and  token: " + token);
1418                 }
1419             }
1420 
1421             if (isTrackingWindowsLocked(displayId)) {
1422                 shouldComputeWindows = true;
1423             }
1424             registerIdLocked(leashToken, windowId);
1425         }
1426         if (shouldComputeWindows) {
1427             if (traceWMEnabled()) {
1428                 logTraceWM("computeWindowsForAccessibility", "displayId=" + displayId);
1429             }
1430             mWindowManagerInternal.computeWindowsForAccessibility(displayId);
1431         }
1432         if (traceWMEnabled()) {
1433             logTraceWM("setAccessibilityIdToSurfaceMetadata",
1434                     "token=" + token + ";windowId=" + windowId);
1435         }
1436         mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(token, windowId);
1437         return windowId;
1438     }
1439 
1440     /**
1441      * Removes accessibility interaction connection according to given window token.
1442      *
1443      * @param window The window token of accessibility interaction connection
1444      */
removeAccessibilityInteractionConnection(@onNull IWindow window)1445     public void removeAccessibilityInteractionConnection(@NonNull IWindow window) {
1446         synchronized (mLock) {
1447             // We treat calls from a profile as if made by its parent as profiles
1448             // share the accessibility state of the parent. The call below
1449             // performs the current profile parent resolution.
1450             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
1451                     UserHandle.getCallingUserId());
1452             IBinder token = window.asBinder();
1453             final int removedWindowId = removeAccessibilityInteractionConnectionInternalLocked(
1454                     token, mGlobalWindowTokens, mGlobalInteractionConnections);
1455             if (removedWindowId >= 0) {
1456                 onAccessibilityInteractionConnectionRemovedLocked(removedWindowId, token);
1457                 if (DEBUG) {
1458                     Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
1459                             + " with windowId: " + removedWindowId + " and token: "
1460                             + window.asBinder());
1461                 }
1462                 return;
1463             }
1464             final int userCount = mWindowTokens.size();
1465             for (int i = 0; i < userCount; i++) {
1466                 final int userId = mWindowTokens.keyAt(i);
1467                 final int removedWindowIdForUser =
1468                         removeAccessibilityInteractionConnectionInternalLocked(token,
1469                                 getWindowTokensForUserLocked(userId),
1470                                 getInteractionConnectionsForUserLocked(userId));
1471                 if (removedWindowIdForUser >= 0) {
1472                     onAccessibilityInteractionConnectionRemovedLocked(
1473                             removedWindowIdForUser, token);
1474                     if (DEBUG) {
1475                         Slog.i(LOG_TAG, "Removed user connection for pid:" + Binder.getCallingPid()
1476                                 + " with windowId: " + removedWindowIdForUser + " and userId:"
1477                                 + userId + " and token: " + window.asBinder());
1478                     }
1479                     return;
1480                 }
1481             }
1482         }
1483     }
1484 
1485     /**
1486      * Resolves a connection wrapper for a window id.
1487      *
1488      * @param userId The user id for any user-specific windows
1489      * @param windowId The id of the window of interest
1490      *
1491      * @return a connection to the window
1492      */
1493     @Nullable
getConnectionLocked(int userId, int windowId)1494     public RemoteAccessibilityConnection getConnectionLocked(int userId, int windowId) {
1495         if (VERBOSE) {
1496             Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
1497         }
1498         RemoteAccessibilityConnection connection = mGlobalInteractionConnections.get(windowId);
1499         if (connection == null && isValidUserForInteractionConnectionsLocked(userId)) {
1500             connection = getInteractionConnectionsForUserLocked(userId).get(windowId);
1501         }
1502         if (connection != null && connection.getRemote() != null) {
1503             return connection;
1504         }
1505         if (DEBUG) {
1506             Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
1507         }
1508         return null;
1509     }
1510 
removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken, SparseArray<IBinder> windowTokens, SparseArray<RemoteAccessibilityConnection> interactionConnections)1511     private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
1512             SparseArray<IBinder> windowTokens, SparseArray<RemoteAccessibilityConnection>
1513                     interactionConnections) {
1514         final int count = windowTokens.size();
1515         for (int i = 0; i < count; i++) {
1516             if (windowTokens.valueAt(i) == windowToken) {
1517                 final int windowId = windowTokens.keyAt(i);
1518                 windowTokens.removeAt(i);
1519                 RemoteAccessibilityConnection wrapper = interactionConnections.get(windowId);
1520                 wrapper.unlinkToDeath();
1521                 interactionConnections.remove(windowId);
1522                 return windowId;
1523             }
1524         }
1525         return -1;
1526     }
1527 
1528     /**
1529      * Removes accessibility interaction connection according to given windowId and userId.
1530      *
1531      * @param windowId The windowId of accessibility interaction connection
1532      * @param userId The userId to remove
1533      */
removeAccessibilityInteractionConnectionLocked(int windowId, int userId)1534     private void removeAccessibilityInteractionConnectionLocked(int windowId, int userId) {
1535         IBinder window = null;
1536         if (userId == UserHandle.USER_ALL) {
1537             window = mGlobalWindowTokens.get(windowId);
1538             mGlobalWindowTokens.remove(windowId);
1539             mGlobalInteractionConnections.remove(windowId);
1540         } else {
1541             if (isValidUserForWindowTokensLocked(userId)) {
1542                 window = getWindowTokensForUserLocked(userId).get(windowId);
1543                 getWindowTokensForUserLocked(userId).remove(windowId);
1544             }
1545             if (isValidUserForInteractionConnectionsLocked(userId)) {
1546                 getInteractionConnectionsForUserLocked(userId).remove(windowId);
1547             }
1548         }
1549         onAccessibilityInteractionConnectionRemovedLocked(windowId, window);
1550         if (DEBUG) {
1551             Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId);
1552         }
1553     }
1554 
1555     /**
1556      * Invoked when accessibility interaction connection of window is removed.
1557      *
1558      * @param windowId Removed windowId
1559      * @param binder Removed window token
1560      */
onAccessibilityInteractionConnectionRemovedLocked( int windowId, @Nullable IBinder binder)1561     private void onAccessibilityInteractionConnectionRemovedLocked(
1562             int windowId, @Nullable IBinder binder) {
1563         // Active window will not update, if windows callback is unregistered.
1564         // Update active window to invalid, when its a11y interaction connection is removed.
1565         if (!isTrackingWindowsLocked() && windowId >= 0 && mActiveWindowId == windowId) {
1566             mActiveWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1567         }
1568         if (binder != null) {
1569             if (traceWMEnabled()) {
1570                 logTraceWM("setAccessibilityIdToSurfaceMetadata", "token=" + binder
1571                         + ";windowId=AccessibilityWindowInfo.UNDEFINED_WINDOW_ID");
1572             }
1573             mWindowManagerInternal.setAccessibilityIdToSurfaceMetadata(
1574                     binder, AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
1575         }
1576         unregisterIdLocked(windowId);
1577         mWindowAttributes.remove(windowId);
1578     }
1579 
1580     /**
1581      * Gets window token according to given userId and windowId.
1582      *
1583      * @param userId The userId
1584      * @param windowId The windowId
1585      * @return The window token
1586      */
1587     @Nullable
getWindowTokenForUserAndWindowIdLocked(int userId, int windowId)1588     public IBinder getWindowTokenForUserAndWindowIdLocked(int userId, int windowId) {
1589         IBinder windowToken = mGlobalWindowTokens.get(windowId);
1590         if (windowToken == null && isValidUserForWindowTokensLocked(userId)) {
1591             windowToken = getWindowTokensForUserLocked(userId).get(windowId);
1592         }
1593         return windowToken;
1594     }
1595 
1596     /**
1597      * Returns the userId that owns the given window token, {@link UserHandle#USER_NULL}
1598      * if not found.
1599      *
1600      * @param windowToken The window token
1601      * @return The userId
1602      */
getWindowOwnerUserId(@onNull IBinder windowToken)1603     public int getWindowOwnerUserId(@NonNull IBinder windowToken) {
1604         if (traceWMEnabled()) {
1605             logTraceWM("getWindowOwnerUserId", "token=" + windowToken);
1606         }
1607         return mWindowManagerInternal.getWindowOwnerUserId(windowToken);
1608     }
1609 
1610     /**
1611      * Returns windowId of given userId and window token.
1612      *
1613      * @param userId The userId
1614      * @param token The window token
1615      * @return The windowId
1616      */
findWindowIdLocked(int userId, @NonNull IBinder token)1617     public int findWindowIdLocked(int userId, @NonNull IBinder token) {
1618         final int globalIndex = mGlobalWindowTokens.indexOfValue(token);
1619         if (globalIndex >= 0) {
1620             return mGlobalWindowTokens.keyAt(globalIndex);
1621         }
1622         if (isValidUserForWindowTokensLocked(userId)) {
1623             final int userIndex = getWindowTokensForUserLocked(userId).indexOfValue(token);
1624             if (userIndex >= 0) {
1625                 return getWindowTokensForUserLocked(userId).keyAt(userIndex);
1626             }
1627         }
1628         return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1629     }
1630 
1631     /**
1632      * Establish the relationship between the host and the embedded view hierarchy.
1633      *
1634      * @param host The token of host hierarchy
1635      * @param embedded The token of the embedded hierarchy
1636      */
associateEmbeddedHierarchyLocked(@onNull IBinder host, @NonNull IBinder embedded)1637     public void associateEmbeddedHierarchyLocked(@NonNull IBinder host, @NonNull IBinder embedded) {
1638         // Use embedded window as key, since one host window may have multiple embedded windows.
1639         associateLocked(embedded, host);
1640     }
1641 
1642     /**
1643      * Clear the relationship by given token.
1644      *
1645      * @param token The token
1646      */
disassociateEmbeddedHierarchyLocked(@onNull IBinder token)1647     public void disassociateEmbeddedHierarchyLocked(@NonNull IBinder token) {
1648         disassociateLocked(token);
1649     }
1650 
1651     /**
1652      * Gets the parent windowId of the window according to the specified windowId.
1653      *
1654      * @param windowId The windowId to check
1655      * @return The windowId of the parent window, or self if no parent exists
1656      */
resolveParentWindowIdLocked(int windowId)1657     public int resolveParentWindowIdLocked(int windowId) {
1658         final IBinder token = getLeashTokenLocked(windowId);
1659         if (token == null) {
1660             return windowId;
1661         }
1662         final IBinder resolvedToken = resolveTopParentTokenLocked(token);
1663         final int resolvedWindowId = getWindowIdLocked(resolvedToken);
1664         return resolvedWindowId != -1 ? resolvedWindowId : windowId;
1665     }
1666 
resolveTopParentTokenLocked(IBinder token)1667     private IBinder resolveTopParentTokenLocked(IBinder token) {
1668         final IBinder hostToken = getHostTokenLocked(token);
1669         if (hostToken == null) {
1670             return token;
1671         }
1672         return resolveTopParentTokenLocked(hostToken);
1673     }
1674 
1675     /**
1676      * Computes partial interactive region of given windowId.
1677      *
1678      * @param windowId The windowId
1679      * @param outRegion The output to which to write the bounds.
1680      * @return true if outRegion is not empty.
1681      */
computePartialInteractiveRegionForWindowLocked(int windowId, @NonNull Region outRegion)1682     public boolean computePartialInteractiveRegionForWindowLocked(int windowId,
1683             @NonNull Region outRegion) {
1684         final int parentWindowId = resolveParentWindowIdLocked(windowId);
1685         final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(
1686                 parentWindowId);
1687 
1688         if (observer != null) {
1689             return observer.computePartialInteractiveRegionForWindowLocked(parentWindowId,
1690                     parentWindowId != windowId, outRegion);
1691         }
1692 
1693         return false;
1694     }
1695 
1696     /**
1697      * Updates active windowId and accessibility focused windowId according to given accessibility
1698      * event and action.
1699      *
1700      * @param userId The userId
1701      * @param windowId The windowId of accessibility event
1702      * @param nodeId The accessibility node id of accessibility event
1703      * @param eventType The accessibility event type
1704      * @param eventAction The accessibility event action
1705      */
updateActiveAndAccessibilityFocusedWindowLocked(int userId, int windowId, long nodeId, int eventType, int eventAction)1706     public void updateActiveAndAccessibilityFocusedWindowLocked(int userId, int windowId,
1707             long nodeId, int eventType, int eventAction) {
1708         // The active window is either the window that has input focus or
1709         // the window that the user is currently touching. If the user is
1710         // touching a window that does not have input focus as soon as the
1711         // the user stops touching that window the focused window becomes
1712         // the active one. Here we detect the touched window and make it
1713         // active. In updateWindowsLocked() we update the focused window
1714         // and if the user is not touching the screen, we make the focused
1715         // window the active one.
1716         switch (eventType) {
1717             case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED: {
1718                 // If no service has the capability to introspect screen,
1719                 // we do not register callback in the window manager for
1720                 // window changes, so we have to ask the window manager
1721                 // what the focused window is to update the active one.
1722                 // The active window also determined events from which
1723                 // windows are delivered.
1724                 synchronized (mLock) {
1725                     if (!isTrackingWindowsLocked()) {
1726                         mTopFocusedWindowId = findFocusedWindowId(userId);
1727                         if (windowId == mTopFocusedWindowId) {
1728                             mActiveWindowId = windowId;
1729                         }
1730                     }
1731                 }
1732             } break;
1733 
1734             case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER: {
1735                 // Do not allow delayed hover events to confuse us
1736                 // which the active window is.
1737                 synchronized (mLock) {
1738                     if (mTouchInteractionInProgress && mActiveWindowId != windowId) {
1739                         setActiveWindowLocked(windowId);
1740                     }
1741                 }
1742             } break;
1743 
1744             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
1745                 synchronized (mLock) {
1746                     // If window id belongs to a proxy display, then find the display, update the
1747                     // observer focus and send WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED events.
1748                     if (mHasProxy && setProxyFocusLocked(windowId)) {
1749                         return;
1750                     }
1751                     if (mAccessibilityFocusedWindowId != windowId) {
1752                         clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId);
1753                         setAccessibilityFocusedWindowLocked(windowId);
1754                     }
1755                     mAccessibilityFocusNodeId = nodeId;
1756                 }
1757             } break;
1758 
1759             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
1760                 synchronized (mLock) {
1761                     // If cleared happened on the proxy display, then clear the tracked focus.
1762                     if (mHasProxy && clearProxyFocusLocked(windowId, eventAction)) {
1763                         return;
1764                     }
1765                     if (mAccessibilityFocusNodeId == nodeId) {
1766                         mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
1767                     }
1768                     // Clear the window with focus if it no longer has focus and we aren't
1769                     // just moving focus from one view to the other in the same window.
1770                     if ((mAccessibilityFocusNodeId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID)
1771                             && (mAccessibilityFocusedWindowId == windowId)
1772                             && (eventAction != AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS)) {
1773                         mAccessibilityFocusedWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1774                         mAccessibilityFocusedDisplayId = Display.INVALID_DISPLAY;
1775                     }
1776                 }
1777             } break;
1778         }
1779     }
1780 
1781     /**
1782      * Callbacks from AccessibilityManagerService when touch explorer turn on and
1783      * motion down detected.
1784      */
onTouchInteractionStart()1785     public void onTouchInteractionStart() {
1786         synchronized (mLock) {
1787             mTouchInteractionInProgress = true;
1788         }
1789     }
1790 
1791     /**
1792      * Callbacks from AccessibilityManagerService when touch explorer turn on and
1793      * gesture or motion up detected.
1794      */
onTouchInteractionEnd()1795     public void onTouchInteractionEnd() {
1796         synchronized (mLock) {
1797             mTouchInteractionInProgress = false;
1798             // We want to set the active window to be current immediately
1799             // after the user has stopped touching the screen since if the
1800             // user types with the IME they should get a feedback for the
1801             // letter typed in the text view which is in the input focused
1802             // window. Note that we always deliver hover accessibility events
1803             // (they are a result of user touching the screen) so change of
1804             // the active window before all hover accessibility events from
1805             // the touched window are delivered is fine.
1806             final int oldActiveWindow = mActiveWindowId;
1807             setActiveWindowLocked(mTopFocusedWindowId);
1808             if (oldActiveWindow != mActiveWindowId
1809                     && mAccessibilityFocusedWindowId == oldActiveWindow
1810                     && accessibilityFocusOnlyInActiveWindowLocked()) {
1811                 clearAccessibilityFocusLocked(oldActiveWindow);
1812             }
1813         }
1814     }
1815 
1816     /**
1817      * Gets the id of the current active window.
1818      *
1819      * @return The userId
1820      */
getActiveWindowId(int userId)1821     public int getActiveWindowId(int userId) {
1822         if (mActiveWindowId == AccessibilityWindowInfo.UNDEFINED_WINDOW_ID
1823                 && !mTouchInteractionInProgress) {
1824             mActiveWindowId = findFocusedWindowId(userId);
1825         }
1826         return mActiveWindowId;
1827     }
1828 
setActiveWindowLocked(int windowId)1829     private void setActiveWindowLocked(int windowId) {
1830         if (mActiveWindowId != windowId) {
1831             List<AccessibilityEvent> events = new ArrayList<>(2);
1832             if (mActiveWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
1833                 final DisplayWindowsObserver observer =
1834                         getDisplayWindowObserverByWindowIdLocked(mActiveWindowId);
1835                 if (observer != null) {
1836                     events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
1837                             mActiveWindowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
1838                 }
1839             }
1840 
1841             mActiveWindowId = windowId;
1842             // Goes through all windows for each display.
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 && observer.setActiveWindowLocked(windowId)) {
1847                     events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
1848                             windowId, AccessibilityEvent.WINDOWS_CHANGE_ACTIVE));
1849                 }
1850             }
1851 
1852             for (final AccessibilityEvent event : events) {
1853                 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(event);
1854             }
1855         }
1856     }
1857 
setAccessibilityFocusedWindowLocked(int windowId)1858     private void setAccessibilityFocusedWindowLocked(int windowId) {
1859         if (mAccessibilityFocusedWindowId != windowId) {
1860             List<AccessibilityEvent> events = new ArrayList<>(2);
1861             if (mAccessibilityFocusedDisplayId != Display.INVALID_DISPLAY
1862                     && mAccessibilityFocusedWindowId
1863                     != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
1864                 // Previously focused window -> send a focused event for losing focus
1865                 events.add(AccessibilityEvent.obtainWindowsChangedEvent(
1866                         mAccessibilityFocusedDisplayId, mAccessibilityFocusedWindowId,
1867                         WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
1868             }
1869 
1870             mAccessibilityFocusedWindowId = windowId;
1871             // Goes through all windows for each display.
1872             final int count = mDisplayWindowsObservers.size();
1873             for (int i = 0; i < count; i++) {
1874                 final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
1875                 if (observer != null && observer.setAccessibilityFocusedWindowLocked(windowId)) {
1876                     mAccessibilityFocusedDisplayId = observer.mDisplayId;
1877                     // Newly focused window -> send a focused event for gaining focus
1878                     events.add(AccessibilityEvent.obtainWindowsChangedEvent(observer.mDisplayId,
1879                             windowId, WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
1880                 }
1881             }
1882 
1883             for (final AccessibilityEvent event : events) {
1884                 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(event);
1885             }
1886         }
1887     }
1888 
1889     /**
1890      * Returns accessibility window info according to given windowId.
1891      *
1892      * @param windowId The windowId
1893      * @return The accessibility window info
1894      */
1895     @Nullable
findA11yWindowInfoByIdLocked(int windowId)1896     public AccessibilityWindowInfo findA11yWindowInfoByIdLocked(int windowId) {
1897         windowId = resolveParentWindowIdLocked(windowId);
1898         final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId);
1899         if (observer != null) {
1900             return observer.findA11yWindowInfoByIdLocked(windowId);
1901         }
1902         return null;
1903     }
1904 
1905     /**
1906      * Returns the window info according to given windowId.
1907      *
1908      * @param windowId The windowId
1909      * @return The window info
1910      */
1911     @Nullable
findWindowInfoByIdLocked(int windowId)1912     public WindowInfo findWindowInfoByIdLocked(int windowId) {
1913         windowId = resolveParentWindowIdLocked(windowId);
1914         final DisplayWindowsObserver observer = getDisplayWindowObserverByWindowIdLocked(windowId);
1915         if (observer != null) {
1916             return observer.findWindowInfoByIdLocked(windowId);
1917         }
1918         return null;
1919     }
1920 
1921     /**
1922      * Returns focused windowId or accessibility focused windowId according to given focusType.
1923      *
1924      * @param focusType {@link AccessibilityNodeInfo#FOCUS_INPUT} or
1925      * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}
1926      * @return The focused windowId
1927      */
getFocusedWindowId(int focusType)1928     public int getFocusedWindowId(int focusType) {
1929         return getFocusedWindowId(focusType, Display.INVALID_DISPLAY);
1930     }
1931 
1932     /**
1933      * Returns focused windowId or accessibility focused windowId according to given focusType and
1934      * display id.
1935      * @param focusType {@link AccessibilityNodeInfo#FOCUS_INPUT} or
1936      * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}
1937      * @param displayId the display id to check. If this display is proxy-ed, the proxy's a11y focus
1938      *                  will be returned.
1939      * @return The focused windowId
1940      */
getFocusedWindowId(int focusType, int displayId)1941     public int getFocusedWindowId(int focusType, int displayId) {
1942         if (displayId == Display.INVALID_DISPLAY || displayId == Display.DEFAULT_DISPLAY
1943                 || !mHasProxy) {
1944             return getDefaultFocus(focusType);
1945         }
1946 
1947         final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(displayId);
1948         if (observer != null && observer.mIsProxy) {
1949             return getProxyFocus(focusType, observer);
1950         } else {
1951             return getDefaultFocus(focusType);
1952         }
1953     }
1954 
getDefaultFocus(int focusType)1955     private int getDefaultFocus(int focusType) {
1956         if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
1957             return mTopFocusedWindowId;
1958         } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
1959             return mAccessibilityFocusedWindowId;
1960         }
1961         return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1962     }
1963 
getProxyFocus(int focusType, DisplayWindowsObserver observer)1964     private int getProxyFocus(int focusType, DisplayWindowsObserver observer) {
1965         if (focusType == AccessibilityNodeInfo.FOCUS_INPUT) {
1966             return mTopFocusedWindowId;
1967         } else if (focusType == AccessibilityNodeInfo.FOCUS_ACCESSIBILITY) {
1968             return observer.mProxyDisplayAccessibilityFocusedWindow;
1969         } else {
1970             return AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
1971         }
1972     }
1973 
1974     /**
1975      * Returns {@link AccessibilityWindowInfo} of PIP window.
1976      *
1977      * @return PIP accessibility window info
1978      */
1979     @Nullable
getPictureInPictureWindowLocked()1980     public AccessibilityWindowInfo getPictureInPictureWindowLocked() {
1981         AccessibilityWindowInfo windowInfo = null;
1982         final int count = mDisplayWindowsObservers.size();
1983         for (int i = 0; i < count; i++) {
1984             final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
1985             if (observer != null) {
1986                 if ((windowInfo = observer.getPictureInPictureWindowLocked()) != null) {
1987                     break;
1988                 }
1989             }
1990         }
1991         return windowInfo;
1992     }
1993 
1994     /**
1995      * Sets an IAccessibilityInteractionConnection to replace the actions of a picture-in-picture
1996      * window.
1997      */
setPictureInPictureActionReplacingConnection( @ullable IAccessibilityInteractionConnection connection)1998     public void setPictureInPictureActionReplacingConnection(
1999             @Nullable IAccessibilityInteractionConnection connection) throws RemoteException {
2000         synchronized (mLock) {
2001             if (mPictureInPictureActionReplacingConnection != null) {
2002                 mPictureInPictureActionReplacingConnection.unlinkToDeath();
2003                 mPictureInPictureActionReplacingConnection = null;
2004             }
2005             if (connection != null) {
2006                 RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
2007                         AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID,
2008                         connection, "foo.bar.baz", Process.SYSTEM_UID, UserHandle.USER_ALL);
2009                 mPictureInPictureActionReplacingConnection = wrapper;
2010                 wrapper.linkToDeath();
2011             }
2012         }
2013     }
2014 
2015     /**
2016      * Returns accessibility interaction connection for picture-in-picture window.
2017      */
2018     @Nullable
getPictureInPictureActionReplacingConnection()2019     public RemoteAccessibilityConnection getPictureInPictureActionReplacingConnection() {
2020         return mPictureInPictureActionReplacingConnection;
2021     }
2022 
2023     /**
2024      * Invokes {@link IAccessibilityInteractionConnection#notifyOutsideTouch()} for windows that
2025      * have watch outside touch flag and its layer is upper than target window.
2026      */
notifyOutsideTouch(int userId, int targetWindowId)2027     public void notifyOutsideTouch(int userId, int targetWindowId) {
2028         final List<Integer> outsideWindowsIds;
2029         final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>();
2030         synchronized (mLock) {
2031             final DisplayWindowsObserver observer =
2032                     getDisplayWindowObserverByWindowIdLocked(targetWindowId);
2033             if (observer != null) {
2034                 outsideWindowsIds = observer.getWatchOutsideTouchWindowIdLocked(targetWindowId);
2035                 for (int i = 0; i < outsideWindowsIds.size(); i++) {
2036                     connectionList.add(getConnectionLocked(userId, outsideWindowsIds.get(i)));
2037                 }
2038             }
2039         }
2040         for (int i = 0; i < connectionList.size(); i++) {
2041             final RemoteAccessibilityConnection connection = connectionList.get(i);
2042             if (connection != null) {
2043                 if (traceIntConnEnabled()) {
2044                     logTraceIntConn("notifyOutsideTouch");
2045                 }
2046 
2047                 try {
2048                     connection.getRemote().notifyOutsideTouch();
2049                 } catch (RemoteException re) {
2050                     if (DEBUG) {
2051                         Slog.e(LOG_TAG, "Error calling notifyOutsideTouch()");
2052                     }
2053                 }
2054             }
2055         }
2056     }
2057 
2058     /**
2059      * Returns the display ID according to given userId and windowId.
2060      *
2061      * @param userId The userId
2062      * @param windowId The windowId
2063      * @return The display ID
2064      */
getDisplayIdByUserIdAndWindowId(int userId, int windowId)2065     public int getDisplayIdByUserIdAndWindowId(int userId, int windowId) {
2066         final IBinder windowToken;
2067         synchronized (mLock) {
2068             windowToken = getWindowTokenForUserAndWindowIdLocked(userId, windowId);
2069         }
2070         if (traceWMEnabled()) {
2071             logTraceWM("getDisplayIdForWindow", "token=" + windowToken);
2072         }
2073         final int displayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
2074         return displayId;
2075     }
2076 
2077     /**
2078      * Returns the display list including all displays which are tracking windows.
2079      *
2080      * @param displayTypes the types of displays to retrieve
2081      * @return The display list.
2082      */
getDisplayListLocked( @bstractAccessibilityServiceConnection.DisplayTypes int displayTypes)2083     public ArrayList<Integer> getDisplayListLocked(
2084             @AbstractAccessibilityServiceConnection.DisplayTypes int displayTypes) {
2085         final ArrayList<Integer> displayList = new ArrayList<>();
2086         final int count = mDisplayWindowsObservers.size();
2087         for (int i = 0; i < count; i++) {
2088             final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
2089             if (observer != null) {
2090                 if (!observer.mIsProxy && (displayTypes & DISPLAY_TYPE_DEFAULT) != 0) {
2091                     displayList.add(observer.mDisplayId);
2092                 } else if (observer.mIsProxy && (displayTypes & DISPLAY_TYPE_PROXY) != 0) {
2093                     displayList.add(observer.mDisplayId);
2094                 }
2095             }
2096         }
2097         return displayList;
2098     }
2099 
2100     // If there is no service that can operate with interactive windows
2101     // then a window loses accessibility focus if it is no longer active.
2102     // This inspection happens when the user interaction is ended.
2103     // Note that to allow a service to work across windows,
2104     // we have to allow accessibility focus stay in any of them.
accessibilityFocusOnlyInActiveWindowLocked()2105     boolean accessibilityFocusOnlyInActiveWindowLocked() {
2106         return !isTrackingWindowsLocked();
2107     }
2108 
2109     /**
2110      * Gets current input focused window token from window manager, and returns its windowId.
2111      *
2112      * @param userId The userId
2113      * @return The input focused windowId, or -1 if not found
2114      */
findFocusedWindowId(int userId)2115     private int findFocusedWindowId(int userId) {
2116         if (traceWMEnabled()) {
2117             logTraceWM("getFocusedWindowToken", "");
2118         }
2119         final IBinder token = mWindowManagerInternal.getFocusedWindowTokenFromWindowStates();
2120         synchronized (mLock) {
2121             return findWindowIdLocked(userId, token);
2122         }
2123     }
2124 
isValidUserForInteractionConnectionsLocked(int userId)2125     private boolean isValidUserForInteractionConnectionsLocked(int userId) {
2126         return mInteractionConnections.indexOfKey(userId) >= 0;
2127     }
2128 
isValidUserForWindowTokensLocked(int userId)2129     private boolean isValidUserForWindowTokensLocked(int userId) {
2130         return mWindowTokens.indexOfKey(userId) >= 0;
2131     }
2132 
getInteractionConnectionsForUserLocked( int userId)2133     private SparseArray<RemoteAccessibilityConnection> getInteractionConnectionsForUserLocked(
2134             int userId) {
2135         SparseArray<RemoteAccessibilityConnection> connection = mInteractionConnections.get(
2136                 userId);
2137         if (connection == null) {
2138             connection = new SparseArray<>();
2139             mInteractionConnections.put(userId, connection);
2140         }
2141         return connection;
2142     }
2143 
getWindowTokensForUserLocked(int userId)2144     private SparseArray<IBinder> getWindowTokensForUserLocked(int userId) {
2145         SparseArray<IBinder> windowTokens = mWindowTokens.get(userId);
2146         if (windowTokens == null) {
2147             windowTokens = new SparseArray<>();
2148             mWindowTokens.put(userId, windowTokens);
2149         }
2150         return windowTokens;
2151     }
2152 
clearAccessibilityFocusLocked(int windowId)2153     private void clearAccessibilityFocusLocked(int windowId) {
2154         mHandler.sendMessage(obtainMessage(
2155                 AccessibilityWindowManager::clearAccessibilityFocusMainThread,
2156                 AccessibilityWindowManager.this,
2157                 mAccessibilityUserManager.getCurrentUserIdLocked(), windowId));
2158     }
2159 
clearAccessibilityFocusMainThread(int userId, int windowId)2160     private void clearAccessibilityFocusMainThread(int userId, int windowId) {
2161         final RemoteAccessibilityConnection connection;
2162         synchronized (mLock) {
2163             connection = getConnectionLocked(userId, windowId);
2164             if (connection == null) {
2165                 return;
2166             }
2167         }
2168         if (traceIntConnEnabled()) {
2169             logTraceIntConn("notifyOutsideTouch");
2170         }
2171         try {
2172             connection.getRemote().clearAccessibilityFocus();
2173         } catch (RemoteException re) {
2174             if (DEBUG) {
2175                 Slog.e(LOG_TAG, "Error calling clearAccessibilityFocus()");
2176             }
2177         }
2178     }
2179 
getDisplayWindowObserverByWindowIdLocked(int windowId)2180     private DisplayWindowsObserver getDisplayWindowObserverByWindowIdLocked(int windowId) {
2181         final int count = mDisplayWindowsObservers.size();
2182         for (int i = 0; i < count; i++) {
2183             final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
2184             if (observer != null) {
2185                 if (observer.findWindowInfoByIdLocked(windowId) != null) {
2186                     return mDisplayWindowsObservers.get(observer.mDisplayId);
2187                 }
2188             }
2189         }
2190         return null;
2191     }
2192 
traceWMEnabled()2193     private boolean traceWMEnabled() {
2194         return mTraceManager.isA11yTracingEnabledForTypes(FLAGS_WINDOW_MANAGER_INTERNAL);
2195     }
2196 
logTraceWM(String methodName, String params)2197     private void logTraceWM(String methodName, String params) {
2198         mTraceManager.logTrace("WindowManagerInternal." + methodName,
2199                     FLAGS_WINDOW_MANAGER_INTERNAL, params);
2200     }
2201 
traceIntConnEnabled()2202     private boolean traceIntConnEnabled() {
2203         return mTraceManager.isA11yTracingEnabledForTypes(
2204                 FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION);
2205     }
2206 
logTraceIntConn(String methodName)2207     private void logTraceIntConn(String methodName) {
2208         mTraceManager.logTrace(
2209                     LOG_TAG + "." + methodName, FLAGS_ACCESSIBILITY_INTERACTION_CONNECTION);
2210     }
2211 
2212     /**
2213      * Associate the token of the embedded view hierarchy to the host view hierarchy.
2214      *
2215      * @param embedded The leash token from the view root of embedded hierarchy
2216      * @param host The leash token from the view root of host hierarchy
2217      */
associateLocked(IBinder embedded, IBinder host)2218     void associateLocked(IBinder embedded, IBinder host) {
2219         mHostEmbeddedMap.put(embedded, host);
2220     }
2221 
2222     /**
2223      * Clear the relationship of given token.
2224      *
2225      * @param token The leash token
2226      */
disassociateLocked(IBinder token)2227     void disassociateLocked(IBinder token) {
2228         mHostEmbeddedMap.remove(token);
2229         for (int i = mHostEmbeddedMap.size() - 1; i >= 0; i--) {
2230             if (mHostEmbeddedMap.valueAt(i).equals(token)) {
2231                 mHostEmbeddedMap.removeAt(i);
2232             }
2233         }
2234     }
2235 
2236     /**
2237      * Register the leash token with its windowId.
2238      *
2239      * @param token The token.
2240      * @param windowId The windowID.
2241      */
registerIdLocked(IBinder token, int windowId)2242     void registerIdLocked(IBinder token, int windowId) {
2243         mWindowIdMap.put(windowId, token);
2244     }
2245 
2246     /**
2247      * Unregister the windowId and also disassociate its token.
2248      *
2249      * @param windowId The windowID
2250      */
unregisterIdLocked(int windowId)2251     void unregisterIdLocked(int windowId) {
2252         final IBinder token = mWindowIdMap.get(windowId);
2253         if (token == null) {
2254             return;
2255         }
2256         disassociateLocked(token);
2257         mWindowIdMap.remove(windowId);
2258     }
2259 
2260     /**
2261      * Get the leash token by given windowID.
2262      *
2263      * @param windowId The windowID.
2264      * @return The token, or {@code NULL} if this windowID doesn't exist
2265      */
getLeashTokenLocked(int windowId)2266     IBinder getLeashTokenLocked(int windowId) {
2267         return mWindowIdMap.get(windowId);
2268     }
2269 
2270     /**
2271      * Get the windowId by given leash token.
2272      *
2273      * @param token The token
2274      * @return The windowID, or -1 if the token doesn't exist
2275      */
getWindowIdLocked(IBinder token)2276     int getWindowIdLocked(IBinder token) {
2277         final int index = mWindowIdMap.indexOfValue(token);
2278         if (index == -1) {
2279             return index;
2280         }
2281         return mWindowIdMap.keyAt(index);
2282     }
2283 
2284     /**
2285      * Get the leash token of the host hierarchy by given token.
2286      *
2287      * @param token The token
2288      * @return The token of host hierarchy, or {@code NULL} if no host exists
2289      */
getHostTokenLocked(IBinder token)2290     IBinder getHostTokenLocked(IBinder token) {
2291         return mHostEmbeddedMap.get(token);
2292     }
2293 
2294     /**
2295      * Checks if the window is embedded into another window so that the window should be excluded
2296      * from the exposed accessibility windows, and the node tree should be embedded in the host.
2297      */
isEmbeddedHierarchyWindowsLocked(int windowId)2298     boolean isEmbeddedHierarchyWindowsLocked(int windowId) {
2299         if (mHostEmbeddedMap.size() == 0) {
2300             return false;
2301         }
2302 
2303         final IBinder leashToken = getLeashTokenLocked(windowId);
2304         if (leashToken == null) {
2305             return false;
2306         }
2307 
2308         return mHostEmbeddedMap.containsKey(leashToken);
2309     }
2310 
2311     /**
2312      * Checks if the window belongs to a proxy display and if so clears the focused window id.
2313      * @param focusClearedWindowId the cleared window id.
2314      * @return true if an observer is proxy-ed and has cleared its focused window id.
2315      */
clearProxyFocusLocked(int focusClearedWindowId, int eventAction)2316     private boolean clearProxyFocusLocked(int focusClearedWindowId, int eventAction) {
2317         // If we are just moving focus from one view to the other in the same window, do nothing.
2318         if (eventAction == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS) {
2319             return false;
2320         }
2321         for (int i = 0; i < mDisplayWindowsObservers.size(); i++) {
2322             final DisplayWindowsObserver observer = mDisplayWindowsObservers.get(i);
2323             if (observer != null && observer.mWindows != null && observer.mIsProxy) {
2324                 final int windowCount = observer.mWindows.size();
2325                 for (int j = 0; j < windowCount; j++) {
2326                     AccessibilityWindowInfo window = observer.mWindows.get(j);
2327                     if (window.getId() == focusClearedWindowId) {
2328                         observer.mProxyDisplayAccessibilityFocusedWindow =
2329                                 AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
2330                         // TODO(268754409): Look into sending a WINDOW_FOCUS_CHANGED event since
2331                         //  window no longer has focus (default window logic doesn't), and
2332                         //  whether the node id needs to be cached (default window logic does).
2333                         return true;
2334                     }
2335                 }
2336             }
2337         }
2338         return false;
2339     }
2340 
2341     /**
2342      * Checks if the window belongs to a proxy display and if so sends
2343      * WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED for that window and the previously focused window.
2344      * @param focusedWindowId the focused window id.
2345      * @return true if an observer is proxy-ed and contains the focused window.
2346      */
setProxyFocusLocked(int focusedWindowId)2347     private boolean setProxyFocusLocked(int focusedWindowId) {
2348         for (int i = 0; i < mDisplayWindowsObservers.size(); i++) {
2349             final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
2350             if (observer != null && observer.mIsProxy
2351                     && observer.setAccessibilityFocusedWindowLocked(focusedWindowId)) {
2352                 final int previouslyFocusedWindowId =
2353                         observer.mProxyDisplayAccessibilityFocusedWindow;
2354 
2355                 if (previouslyFocusedWindowId == focusedWindowId) {
2356                     // Don't send a focus event if the window is already focused.
2357                     return true;
2358                 }
2359 
2360                 // Previously focused window -> Clear focus on UI thread and send a focused event
2361                 // for losing focus
2362                 if (previouslyFocusedWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
2363                     clearAccessibilityFocusLocked(previouslyFocusedWindowId);
2364                     mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
2365                             AccessibilityEvent.obtainWindowsChangedEvent(
2366                                     observer.mDisplayId, previouslyFocusedWindowId,
2367                                     WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
2368                 }
2369                 observer.mProxyDisplayAccessibilityFocusedWindow = focusedWindowId;
2370                 // Newly focused window -> send a focused event for it gaining focus
2371                 mAccessibilityEventSender.sendAccessibilityEventForCurrentUserLocked(
2372                         AccessibilityEvent.obtainWindowsChangedEvent(
2373                                 observer.mDisplayId,
2374                                 observer.mProxyDisplayAccessibilityFocusedWindow,
2375                                 WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED));
2376 
2377                 return true;
2378             }
2379         }
2380         return false;
2381     }
2382 
2383     /**
2384      * Dumps all {@link AccessibilityWindowInfo}s here.
2385      */
dump(FileDescriptor fd, final PrintWriter pw, String[] args)2386     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
2387         pw.append("Global Info [ ");
2388         pw.println("Top focused display Id = " + mTopFocusedDisplayId);
2389         pw.println("     Active Window Id = " + mActiveWindowId);
2390         pw.println("     Top Focused Window Id = " + mTopFocusedWindowId);
2391         pw.println("     Accessibility Focused Window Id = " + mAccessibilityFocusedWindowId
2392                 + " ]");
2393         pw.println();
2394         final int count = mDisplayWindowsObservers.size();
2395         for (int i = 0; i < count; i++) {
2396             final DisplayWindowsObserver observer = mDisplayWindowsObservers.valueAt(i);
2397             if (observer != null) {
2398                 observer.dumpLocked(fd, pw, args);
2399             }
2400         }
2401         pw.println();
2402         pw.append("Window attributes:[");
2403         pw.append(mWindowAttributes.toString());
2404         pw.append("]");
2405         pw.println();
2406     }
2407 }
2408