Supporting windows updated per display [Part I]

1. Making WindowsForAccessibilityObserver class to be plural for
supporting multi-display.
2. Adding the display information when WindowManagerService informs the
window changes to Accessibility Controller.

Bug: 132854721
Test: a11y CTS & unit tests
Change-Id: I0efba7d924b24fcab85c6bb333687cc4cefa890f
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 8abfde2..26ca975 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -85,7 +85,8 @@
 
     private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
 
-    private WindowsForAccessibilityObserver mWindowsForAccessibilityObserver;
+    private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
+            new SparseArray<>();
 
     public boolean setMagnificationCallbacksLocked(int displayId,
             MagnificationCallbacks callbacks) {
@@ -115,27 +116,52 @@
         return result;
     }
 
-    public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
+    public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
+            WindowsForAccessibilityCallback callback) {
         if (callback != null) {
-            if (mWindowsForAccessibilityObserver != null) {
-                throw new IllegalStateException(
-                        "Windows for accessibility callback already set!");
+            final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+            if (dc == null) {
+                return false;
             }
-            mWindowsForAccessibilityObserver = new WindowsForAccessibilityObserver(
-                    mService, callback);
+
+            final Display display = dc.getDisplay();
+            if (mWindowsForAccessibilityObserver.get(displayId) != null) {
+                if (display.getType() == Display.TYPE_VIRTUAL && dc.getParentWindow() != null) {
+                    // The window observer of this embedded display had been set from
+                    // window manager after setting its parent window
+                    return true;
+                } else {
+                    throw new IllegalStateException(
+                            "Windows for accessibility callback of display "
+                                    + displayId + " already set!");
+                }
+            }
+            if (display.getType() == Display.TYPE_OVERLAY) {
+                return false;
+            }
+            mWindowsForAccessibilityObserver.put(displayId,
+                    new WindowsForAccessibilityObserver(mService, displayId, callback));
         } else {
-            if (mWindowsForAccessibilityObserver == null) {
+            final WindowsForAccessibilityObserver windowsForA11yObserver =
+                    mWindowsForAccessibilityObserver.get(displayId);
+            if  (windowsForA11yObserver == null) {
                 throw new IllegalStateException(
-                        "Windows for accessibility callback already cleared!");
+                        "Windows for accessibility callback of display " + displayId
+                                + " already cleared!");
             }
-            mWindowsForAccessibilityObserver = null;
+            mWindowsForAccessibilityObserver.remove(displayId);
         }
+        return true;
     }
 
-    public void performComputeChangedWindowsNotLocked(boolean forceSend) {
+    public void performComputeChangedWindowsNotLocked(int displayId, boolean forceSend) {
         WindowsForAccessibilityObserver observer = null;
         synchronized (mService) {
-            observer = mWindowsForAccessibilityObserver;
+            final WindowsForAccessibilityObserver windowsForA11yObserver =
+                    mWindowsForAccessibilityObserver.get(displayId);
+            if (windowsForA11yObserver != null) {
+                observer = windowsForA11yObserver;
+            }
         }
         if (observer != null) {
             observer.performComputeChangedWindowsNotLocked(forceSend);
@@ -147,9 +173,10 @@
         if (displayMagnifier != null) {
             displayMagnifier.setMagnificationSpecLocked(spec);
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -173,9 +200,10 @@
         if (displayMagnifier != null) {
             displayMagnifier.onWindowLayersChangedLocked();
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -185,9 +213,10 @@
         if (displayMagnifier != null) {
             displayMagnifier.onRotationChangedLocked(displayContent);
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -206,29 +235,36 @@
         if (displayMagnifier != null) {
             displayMagnifier.onWindowTransitionLocked(windowState, transition);
         }
-        // TODO: support multi-display for windows observer
-        if (mWindowsForAccessibilityObserver != null && displayId == Display.DEFAULT_DISPLAY) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
-    public void onWindowFocusChangedNotLocked() {
+    public void onWindowFocusChangedNotLocked(int displayId) {
         // Not relevant for the display magnifier.
 
         WindowsForAccessibilityObserver observer = null;
         synchronized (mService) {
-            observer = mWindowsForAccessibilityObserver;
+            final WindowsForAccessibilityObserver windowsForA11yObserver =
+                    mWindowsForAccessibilityObserver.get(displayId);
+            if (windowsForA11yObserver != null) {
+                observer = windowsForA11yObserver;
+            }
         }
         if (observer != null) {
             observer.performComputeChangedWindowsNotLocked(false);
         }
     }
 
-    public void onSomeWindowResizedOrMovedLocked() {
+    public void onSomeWindowResizedOrMovedLocked(int displayId) {
         // Not relevant for the display magnifier.
 
-        if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(displayId);
+        if (windowsForA11yObserver != null) {
+            windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -264,6 +300,29 @@
         }
     }
 
+    public void handleWindowObserverOfEmbeddedDisplayLocked(int embeddedDisplayId,
+            WindowState parentWindow) {
+        if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
+            return;
+        }
+        // Finds the parent display of this embedded display
+        final int parentDisplayId;
+        WindowState candidate = parentWindow;
+        while (candidate != null) {
+            parentWindow = candidate;
+            candidate = parentWindow.getDisplayContent().getParentWindow();
+        }
+        parentDisplayId = parentWindow.getDisplayId();
+        // Uses the observer of parent display
+        final WindowsForAccessibilityObserver windowsForA11yObserver =
+                mWindowsForAccessibilityObserver.get(parentDisplayId);
+
+        if (windowsForA11yObserver != null) {
+            // Replaces the observer of embedded display to the one of parent display
+            mWindowsForAccessibilityObserver.put(embeddedDisplayId, windowsForA11yObserver);
+        }
+    }
+
     private static void populateTransformationMatrixLocked(WindowState windowState,
             Matrix outMatrix) {
         windowState.getTransformationMatrix(sTempFloats, outMatrix);
@@ -1059,13 +1118,17 @@
 
         private final WindowsForAccessibilityCallback mCallback;
 
+        private final int mDisplayId;
+
         private final long mRecurringAccessibilityEventsIntervalMillis;
 
         public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
+                int displayId,
                 WindowsForAccessibilityCallback callback) {
             mContext = windowManagerService.mContext;
             mService = windowManagerService;
             mCallback = callback;
+            mDisplayId = displayId;
             mHandler = new MyHandler(mService.mH.getLooper());
             mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
                     .getSendRecurringAccessibilityEventsInterval();
@@ -1100,14 +1163,17 @@
                 // Do not send the windows if there is no current focus as
                 // the window manager is still looking for where to put it.
                 // We will do the work when we get a focus change callback.
-                // TODO(b/112273690): Support multiple displays
+                // TODO [Multi-Display] : only checks top focused window
                 if (!isCurrentFocusWindowOnDefaultDisplay()) {
                     return;
                 }
 
-                WindowManager windowManager = (WindowManager)
-                        mContext.getSystemService(Context.WINDOW_SERVICE);
-                windowManager.getDefaultDisplay().getRealSize(mTempPoint);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+                if (dc == null) {
+                    return;
+                }
+                final Display display = dc.getDisplay();
+                display.getRealSize(mTempPoint);
                 final int screenWidth = mTempPoint.x;
                 final int screenHeight = mTempPoint.y;
 
@@ -1305,7 +1371,11 @@
 
         private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
             final List<WindowState> tempWindowStatesList = new ArrayList<>();
-            final DisplayContent dc = mService.getDefaultDisplayContentLocked();
+            final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+            if (dc == null) {
+                return;
+            }
+
             dc.forAllWindows(w -> {
                 if (w.isVisibleLw()) {
                     tempWindowStatesList.add(w);
@@ -1319,8 +1389,7 @@
                     return;
                 }
 
-                if (w.isVisibleLw() && parentWindow.getDisplayContent().isDefaultDisplay
-                        && tempWindowStatesList.contains(parentWindow)) {
+                if (w.isVisibleLw() && tempWindowStatesList.contains(parentWindow)) {
                     tempWindowStatesList.add(tempWindowStatesList.lastIndexOf(parentWindow), w);
                 }
             }, false /* traverseTopToBottom */);
@@ -1341,7 +1410,7 @@
             }
             return displayParentWindow;
         }
-
+        // TODO [Multi-Display] : only checks top focused window
         private boolean isCurrentFocusWindowOnDefaultDisplay() {
             final WindowState focusedWindow =
                     mService.mRoot.getTopFocusedDisplayContent().mCurrentFocus;