Fix backwards compatibility for introspected windows.

1. The APIs for introspecting interactive windows were reporting only
   the touchable windows but were missing the focused window. The user
   can interact with the latter by typing, hence it should always be
   reported. Also this was breaking backwards compatibility as if the
   focused window is covered by a modal one, the focused window was not
   reporeted and this was putting the active window in a bad state as
   the latter is either the focused window or the one the user is touching.

2. Window change events are too frequent as on window transition things
   are chanign a lot. Now we are trottling the windows changed events
   at the standard recurring accessibility event interval.

3. Fixed a wrong flag comparison and removed some unneded code.

buy:15434666
bug:15432989

Change-Id: I825b33067e8cbf26396a4d38642bde4907b6427a
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 95cfa243..6cb6b76 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -44,6 +44,7 @@
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
+import android.view.ViewConfiguration;
 import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.WindowManagerInternal.MagnificationCallbacks;
@@ -113,13 +114,13 @@
             mDisplayMagnifier.setMagnificationSpecLocked(spec);
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
-    public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
         if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle, immediate);
+            mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
         }
         // Not relevant for the window observer.
     }
@@ -129,7 +130,7 @@
             mDisplayMagnifier.onWindowLayersChangedLocked();
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -138,7 +139,7 @@
             mDisplayMagnifier.onRotationChangedLocked(displayContent, rotation);
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -154,7 +155,7 @@
             mDisplayMagnifier.onWindowTransitionLocked(windowState, transition);
         }
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -162,16 +163,16 @@
         // Not relevant for the display magnifier.
 
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
 
-    public void onSomeWindowResizedOrMoved() {
+    public void onSomeWindowResizedOrMovedLocked() {
         // Not relevant for the display magnifier.
 
         if (mWindowsForAccessibilityObserver != null) {
-            mWindowsForAccessibilityObserver.computeChangedWindows();
+            mWindowsForAccessibilityObserver.scheduleComputeChangedWindowsLocked();
         }
     }
 
@@ -256,7 +257,7 @@
             mWindowManagerService.scheduleAnimationLocked();
         }
 
-        public void onRectangleOnScreenRequestedLocked(Rect rectangle, boolean immediate) {
+        public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
             if (DEBUG_RECTANGLE_REQUESTED) {
                 Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
             }
@@ -889,21 +890,45 @@
 
         private final WindowsForAccessibilityCallback mCallback;
 
+        private final long mRecurringAccessibilityEventsIntervalMillis;
+
         public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
                 WindowsForAccessibilityCallback callback) {
             mContext = windowManagerService.mContext;
             mWindowManagerService = windowManagerService;
             mCallback = callback;
             mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
+            mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
+                    .getSendRecurringAccessibilityEventsInterval();
             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)) {
+                mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
+                        mRecurringAccessibilityEventsIntervalMillis);
+            }
+        }
+
         public void computeChangedWindows() {
             if (DEBUG) {
                 Slog.i(LOG_TAG, "computeChangedWindows()");
             }
 
             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.
+                // We will do the work when we get a focus change callback.
+                if (mWindowManagerService.mCurrentFocus == null) {
+                    return;
+                }
+
                 WindowManager windowManager = (WindowManager)
                         mContext.getSystemService(Context.WINDOW_SERVICE);
                 windowManager.getDefaultDisplay().getRealSize(mTempPoint);
@@ -921,37 +946,21 @@
                 Set<IBinder> addedWindows = mTempBinderSet;
                 addedWindows.clear();
 
+                boolean focusedWindowAdded = false;
+
                 final int visibleWindowCount = visibleWindows.size();
                 for (int i = visibleWindowCount - 1; i >= 0; i--) {
                     WindowState windowState = visibleWindows.valueAt(i);
-                    // Compute the window touchable frame as shown on the screen.
 
-                    // Get the touchable frame.
-                    Region touchableRegion = mTempRegion1;
-                    windowState.getTouchableRegion(touchableRegion);
-                    Rect touchableFrame = mTempRect;
-                    touchableRegion.getBounds(touchableFrame);
-
-                    // Move to origin as all transforms are captured by the matrix.
-                    RectF windowFrame = mTempRectF;
-                    windowFrame.set(touchableFrame);
-                    windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
-
-                    // Map the frame to get what appears on the screen.
-                    Matrix matrix = mTempMatrix;
-                    populateTransformationMatrixLocked(windowState, matrix);
-                    matrix.mapRect(windowFrame);
-
-                    // Got the bounds.
+                    // Compute the bounds in the screen.
                     Rect boundsInScreen = mTempRect;
-                    boundsInScreen.set((int) windowFrame.left, (int) windowFrame.top,
-                            (int) windowFrame.right, (int) windowFrame.bottom);
+                    computeWindowBoundsInScreen(windowState, boundsInScreen);
 
                     final int flags = windowState.mAttrs.flags;
 
                     // If the window is not touchable, do not report it but take into account
                     // the space it takes since the content behind it cannot be touched.
-                    if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) == 1) {
+                    if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
                         unaccountedSpace.op(boundsInScreen, unaccountedSpace,
                                 Region.Op.DIFFERENCE);
                         continue;
@@ -965,33 +974,12 @@
                     // Add windows of certain types not covered by modal windows.
                     if (isReportedWindowType(windowState.mAttrs.type)) {
                         // Add the window to the ones to be reported.
-                        WindowInfo window = WindowInfo.obtain();
-                        window.type = windowState.mAttrs.type;
-                        window.layer = windowState.mLayer;
-                        window.token = windowState.mClient.asBinder();
-
+                        WindowInfo window = obtainPopulatedWindowInfo(windowState, boundsInScreen);
                         addedWindows.add(window.token);
-
-                        WindowState attachedWindow = windowState.mAttachedWindow;
-                        if (attachedWindow != null) {
-                            window.parentToken = attachedWindow.mClient.asBinder();
-                        }
-
-                        window.focused = windowState.isFocused();
-                        window.boundsInScreen.set(boundsInScreen);
-
-                        final int childCount = windowState.mChildWindows.size();
-                        if (childCount > 0) {
-                            if (window.childTokens == null) {
-                                window.childTokens = new ArrayList<IBinder>();
-                            }
-                            for (int j = 0; j < childCount; j++) {
-                                WindowState child = windowState.mChildWindows.get(j);
-                                window.childTokens.add(child.mClient.asBinder());
-                            }
-                        }
-
                         windows.add(window);
+                        if (windowState.isFocused()) {
+                            focusedWindowAdded = true;
+                        }
                     }
 
                     // Account for the space this window takes.
@@ -1010,6 +998,25 @@
                     }
                 }
 
+                // Always report the focused window.
+                if (!focusedWindowAdded) {
+                    for (int i = visibleWindowCount - 1; i >= 0; i--) {
+                        WindowState windowState = visibleWindows.valueAt(i);
+                        if (windowState.isFocused()) {
+                            // Compute the bounds in the screen.
+                            Rect boundsInScreen = mTempRect;
+                            computeWindowBoundsInScreen(windowState, boundsInScreen);
+
+                            // Add the window to the ones to be reported.
+                            WindowInfo window = obtainPopulatedWindowInfo(windowState,
+                                    boundsInScreen);
+                            addedWindows.add(window.token);
+                            windows.add(window);
+                            break;
+                        }
+                    }
+                }
+
                 // Remove child/parent references to windows that were not added.
                 final int windowCount = windows.size();
                 for (int i = 0; i < windowCount; i++) {
@@ -1072,6 +1079,57 @@
             }
         }
 
+        private void computeWindowBoundsInScreen(WindowState windowState, Rect outBounds) {
+            // Get the touchable frame.
+            Region touchableRegion = mTempRegion1;
+            windowState.getTouchableRegion(touchableRegion);
+            Rect touchableFrame = mTempRect;
+            touchableRegion.getBounds(touchableFrame);
+
+            // Move to origin as all transforms are captured by the matrix.
+            RectF windowFrame = mTempRectF;
+            windowFrame.set(touchableFrame);
+            windowFrame.offset(-windowState.mFrame.left, -windowState.mFrame.top);
+
+            // Map the frame to get what appears on the screen.
+            Matrix matrix = mTempMatrix;
+            populateTransformationMatrixLocked(windowState, matrix);
+            matrix.mapRect(windowFrame);
+
+            // Got the bounds.
+            outBounds.set((int) windowFrame.left, (int) windowFrame.top,
+                    (int) windowFrame.right, (int) windowFrame.bottom);
+        }
+
+        private static WindowInfo obtainPopulatedWindowInfo(WindowState windowState,
+                Rect boundsInScreen) {
+            WindowInfo window = WindowInfo.obtain();
+            window.type = windowState.mAttrs.type;
+            window.layer = windowState.mLayer;
+            window.token = windowState.mClient.asBinder();
+
+            WindowState attachedWindow = windowState.mAttachedWindow;
+            if (attachedWindow != null) {
+                window.parentToken = attachedWindow.mClient.asBinder();
+            }
+
+            window.focused = windowState.isFocused();
+            window.boundsInScreen.set(boundsInScreen);
+
+            final int childCount = windowState.mChildWindows.size();
+            if (childCount > 0) {
+                if (window.childTokens == null) {
+                    window.childTokens = new ArrayList<IBinder>();
+                }
+                for (int j = 0; j < childCount; j++) {
+                    WindowState child = windowState.mChildWindows.get(j);
+                    window.childTokens.add(child.mClient.asBinder());
+                }
+            }
+
+            return window;
+        }
+
         private void cacheWindows(List<WindowInfo> windows) {
             final int oldWindowCount = mOldWindows.size();
             for (int i = oldWindowCount - 1; i >= 0; i--) {
@@ -1088,10 +1146,10 @@
             if (oldWindow == newWindow) {
                 return false;
             }
-            if (oldWindow == null && newWindow != null) {
+            if (oldWindow == null) {
                 return true;
             }
-            if (oldWindow != null && newWindow == null) {
+            if (newWindow == null) {
                 return true;
             }
             if (oldWindow.type != newWindow.type) {
@@ -1160,7 +1218,8 @@
         }
 
         private class MyHandler extends Handler {
-            public static final int MESSAGE_NOTIFY_WINDOWS_CHANGED = 1;
+            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);
@@ -1170,6 +1229,10 @@
             @SuppressWarnings("unchecked")
             public void handleMessage(Message message) {
                 switch (message.what) {
+                    case MESSAGE_COMPUTE_CHANGED_WINDOWS: {
+                        computeChangedWindows();
+                    } break;
+
                     case MESSAGE_NOTIFY_WINDOWS_CHANGED: {
                         List<WindowInfo> windows = (List<WindowInfo>) message.obj;
                         mCallback.onWindowsForAccessibilityChanged(windows);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 3200b54..b4cf2ae 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -446,11 +446,11 @@
         }
     }
 
-    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized(mService.mWindowMap) {
             final long identity = Binder.clearCallingIdentity();
             try {
-                mService.onRectangleOnScreenRequested(token, rectangle, immediate);
+                mService.onRectangleOnScreenRequested(token, rectangle);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 93a763a..76085fa 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2811,14 +2811,13 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
-    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle) {
         synchronized (mWindowMap) {
             if (mAccessibilityController != null) {
                 WindowState window = mWindowMap.get(token);
                 //TODO (multidisplay): Magnification is supported only for the default display.
                 if (window != null && window.getDisplayId() == Display.DEFAULT_DISPLAY) {
-                    mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle,
-                            immediate);
+                    mAccessibilityController.onRectangleOnScreenRequestedLocked(rectangle);
                 }
             }
         }
@@ -9231,7 +9230,7 @@
                         //TODO (multidisplay): Accessibility supported only for the default display.
                         if (mAccessibilityController != null
                                 && displayId == Display.DEFAULT_DISPLAY) {
-                            mAccessibilityController.onSomeWindowResizedOrMoved();
+                            mAccessibilityController.onSomeWindowResizedOrMovedLocked();
                         }
 
                         try {
@@ -9872,7 +9871,9 @@
             mCurrentFocus = newFocus;
             mLosingFocus.remove(newFocus);
 
-            if (mAccessibilityController != null) {
+            // TODO(multidisplay): Accessibilty supported only of default desiplay.
+            if (mAccessibilityController != null
+                    && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
                 mAccessibilityController.onWindowFocusChangedLocked();
             }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fe771dc..97178bd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1364,7 +1364,7 @@
             //TODO (multidisplay): Accessibility supported only for the default display.
             if (mService.mAccessibilityController != null
                     && getDisplayId() == Display.DEFAULT_DISPLAY) {
-                mService.mAccessibilityController.onSomeWindowResizedOrMoved();
+                mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
             }
 
             mOverscanInsetsChanged = false;