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/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 2620c44..cbc8150 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -462,7 +462,9 @@
      * anything behind it, then only the modal window will be reported
      * (assuming it is the top one). For convenience the returned windows
      * are ordered in a descending layer order, which is the windows that
-     * are higher in the Z-order are reported first.
+     * are higher in the Z-order are reported first. Since the user can always
+     * interact with the window that has input focus by typing, the focused
+     * window is always returned (even if covered by a modal window).
      * <p>
      * <strong>Note:</strong> In order to access the windows your service has
      * to declare the capability to retrieve window content by setting the
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 4f9ba59..4edb0c6 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -286,8 +286,8 @@
     /**
      * This flag indicates to the system that the accessibility service wants
      * to access content of all interactive windows. An interactive window is a
-     * window that can be touched by a sighted user when explore by touch is not
-     * enabled. If this flag is not set your service will not receive
+     * window that has input focus or can be touched by a sighted user when explore
+     * by touch is not enabled. If this flag is not set your service will not receive
      * {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOWS_CHANGED}
      * events, calling AccessibilityService{@link AccessibilityService#getWindows()
      * AccessibilityService.getWindows()} will return an empty list, and {@link
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index c32a2c9..fa5bd88 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -46,7 +46,7 @@
     int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             in int viewVisibility, in int layerStackId, out Rect outContentInsets);
     void remove(IWindow window);
-    
+
     /**
      * Change the parameters of a window.  You supply the
      * new parameters, it returns the new frame of the window on screen (the
@@ -109,7 +109,7 @@
      * to optimize compositing of this part of the window.
      */
     void setTransparentRegion(IWindow window, in Region region);
-    
+
     /**
      * Tell the window manager about the content and visible insets of the
      * given window, which can be used to adjust the <var>outContentInsets</var>
@@ -122,20 +122,20 @@
      */
     void setInsets(IWindow window, int touchableInsets, in Rect contentInsets,
             in Rect visibleInsets, in Region touchableRegion);
-    
+
     /**
      * Return the current display size in which the window is being laid out,
      * accounting for screen decorations around it.
      */
     void getDisplayFrame(IWindow window, out Rect outDisplayFrame);
-    
+
     void finishDrawing(IWindow window);
-    
+
     void setInTouchMode(boolean showFocus);
     boolean getInTouchMode();
-    
+
     boolean performHapticFeedback(IWindow window, int effectId, boolean always);
-    
+
     /**
      * Allocate the drag's thumbnail surface.  Also assigns a token that identifies
      * the drag to the OS and passes that as the return value.  A return value of
@@ -150,11 +150,11 @@
     boolean performDrag(IWindow window, IBinder dragToken, float touchX, float touchY,
             float thumbCenterX, float thumbCenterY, in ClipData data);
 
-	/**
-	 * Report the result of a drop action targeted to the given window.
-	 * consumed is 'true' when the drop was accepted by a valid recipient,
-	 * 'false' otherwise.
-	 */
+   /**
+     * Report the result of a drop action targeted to the given window.
+     * consumed is 'true' when the drop was accepted by a valid recipient,
+     * 'false' otherwise.
+     */
 	void reportDropResult(IWindow window, boolean consumed);
 
     /**
@@ -174,12 +174,12 @@
      * how big the increment is from one screen to another.
      */
     void setWallpaperPosition(IBinder windowToken, float x, float y, float xstep, float ystep);
-    
+
     void wallpaperOffsetsComplete(IBinder window);
-    
+
     Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
             int z, in Bundle extras, boolean sync);
-    
+
     void wallpaperCommandComplete(IBinder window, in Bundle result);
 
     void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
@@ -188,7 +188,7 @@
     /**
      * Notifies that a rectangle on the screen has been requested.
      */
-    void onRectangleOnScreenRequested(IBinder token, in Rect rectangle, boolean immediate);
+    void onRectangleOnScreenRequested(IBinder token, in Rect rectangle);
 
     IWindowId getWindowId(IBinder window);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 76d5038..1be0d4e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6215,7 +6215,7 @@
             mTempRect.offset(0, -mCurScrollY);
             mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
             try {
-                mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
+                mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect);
             } catch (RemoteException re) {
                 /* ignore */
             }
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 7f89044..b721074 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -111,6 +111,7 @@
         builder.append("type=").append(type);
         builder.append(", layer=").append(layer);
         builder.append(", token=").append(token);
+        builder.append(", bounds=").append(boundsInScreen);
         builder.append(", parent=").append(parentToken);
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index faa0c57..1be1572 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3302,7 +3302,7 @@
                 for (int i = 0; i < windowCount; i++) {
                     AccessibilityWindowInfo window = mWindows.get(i);
                     if (window.getId() == mActiveWindowId) {
-                       window.setActive(true);
+                        window.setActive(true);
                     }
                 }
             }
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;