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