Ensure all events from a showing window are dispatched.

Accessibility services may opt-in to introspect the interactive
windows on the screen. If window introspection is enabled there
is a case where some events from a showing window are received
before the updated window state from the window manager. Now the
window manager sends over the windows before notifying the app
for the focus change.

bug:18625996

Change-Id: Ic481e01efbe12dc92f090f799feeb236672fc7b3
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 0cbf03a..08754f9 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -159,11 +159,15 @@
         }
     }
 
-    public void onWindowFocusChangedLocked() {
+    public void onWindowFocusChangedNotLocked() {
         // Not relevant for the display magnifier.
 
-        if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
+        WindowsForAccessibilityObserver observer = null;
+        synchronized (mWindowManagerService) {
+            observer = mWindowsForAccessibilityObserver;
+        }
+        if (observer != null) {
+            observer.performComputeChangedWindowsNotLocked();
         }
     }
 
@@ -937,14 +941,13 @@
             computeChangedWindows();
         }
 
+        public void performComputeChangedWindowsNotLocked() {
+            mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
+            computeChangedWindows();
+        }
+
         public void scheduleComputeChangedWindowsLocked() {
-            // If focus changed, compute changed windows immediately as the focused window
-            // is used by the accessibility manager service to determine the active window.
-            if (mWindowManagerService.mCurrentFocus != null
-                    && mWindowManagerService.mCurrentFocus != mWindowManagerService.mLastFocus) {
-                mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
-                computeChangedWindows();
-            } else if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
+            if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
                 mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
                         mRecurringAccessibilityEventsIntervalMillis);
             }
@@ -955,6 +958,9 @@
                 Slog.i(LOG_TAG, "computeChangedWindows()");
             }
 
+            boolean windowsChanged = false;
+            List<WindowInfo> windows = new ArrayList<WindowInfo>();
+
             synchronized (mWindowManagerService.mWindowMap) {
                 // Do not send the windows if there is no current focus as
                 // the window manager is still looking for where to put it.
@@ -975,8 +981,6 @@
                 SparseArray<WindowState> visibleWindows = mTempWindowStates;
                 populateVisibleWindowsOnScreenLocked(visibleWindows);
 
-                List<WindowInfo> windows = new ArrayList<WindowInfo>();
-
                 Set<IBinder> addedWindows = mTempBinderSet;
                 addedWindows.clear();
 
@@ -1074,7 +1078,6 @@
                 addedWindows.clear();
 
                 // We computed the windows and if they changed notify the client.
-                boolean windowsChanged = false;
                 if (mOldWindows.size() != windows.size()) {
                     // Different size means something changed.
                     windowsChanged = true;
@@ -1096,22 +1099,24 @@
                 }
 
                 if (windowsChanged) {
-                    if (DEBUG) {
-                        Log.i(LOG_TAG, "Windows changed:" + windows);
-                    }
-                    // Remember the old windows to detect changes.
                     cacheWindows(windows);
-                    // Announce the change.
-                    mHandler.obtainMessage(MyHandler.MESSAGE_NOTIFY_WINDOWS_CHANGED,
-                            windows).sendToTarget();
-                } else {
-                    if (DEBUG) {
-                        Log.i(LOG_TAG, "No windows changed.");
-                    }
-                    // Recycle the nodes as we do not need them.
-                    clearAndRecycleWindows(windows);
                 }
             }
+
+            // Now we do not hold the lock, so send the windows over.
+            if (windowsChanged) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Windows changed:" + windows);
+                }
+                mCallback.onWindowsForAccessibilityChanged(windows);
+            } else {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "No windows changed.");
+                }
+            }
+
+            // Recycle the windows as we do not need them.
+            clearAndRecycleWindows(windows);
         }
 
         private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
@@ -1217,7 +1222,7 @@
             return false;
         }
 
-        private void clearAndRecycleWindows(List<WindowInfo> windows) {
+        private static void clearAndRecycleWindows(List<WindowInfo> windows) {
             final int windowCount = windows.size();
             for (int i = windowCount - 1; i >= 0; i--) {
                 windows.remove(i).recycle();
@@ -1254,7 +1259,6 @@
 
         private class MyHandler extends Handler {
             public static final int MESSAGE_COMPUTE_CHANGED_WINDOWS = 1;
-            public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 2;
 
             public MyHandler(Looper looper) {
                 super(looper, null, false);
@@ -1267,12 +1271,6 @@
                     case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
                         computeChangedWindows();
                     } break;
-
-                    case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
-                        List<WindowInfo> windows = (List<WindowInfo>) message.obj;
-                        mCallback.onWindowsForAccessibilityChanged(windows);
-                        clearAndRecycleWindows(windows);
-                    } break;
                 }
             }
         }