Merge "Screen magnifier should handle window rebuilds correctly." into jb-mr1-dev
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 00875ae..7d16e14 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -45,13 +45,15 @@
 
     public final Rect touchableRegion = new Rect();
 
-    public int type;
+    public int type = UNDEFINED;
 
-    public float compatibilityScale;
+    public float compatibilityScale = UNDEFINED;
 
     public boolean visible;
 
-    public int displayId;
+    public int displayId = UNDEFINED;
+
+    public int layer = UNDEFINED;
 
     private WindowInfo() {
         /* do nothing - reduce visibility */
@@ -71,6 +73,7 @@
         parcel.writeFloat(compatibilityScale);
         parcel.writeInt(visible ? 1 : 0);
         parcel.writeInt(displayId);
+        parcel.writeInt(layer);
         recycle();
     }
 
@@ -82,6 +85,7 @@
         compatibilityScale = parcel.readFloat();
         visible = (parcel.readInt() == 1);
         displayId = parcel.readInt();
+        layer = parcel.readInt();
     }
 
     public static WindowInfo obtain(WindowInfo other) {
@@ -90,9 +94,10 @@
         info.frame.set(other.frame);
         info.touchableRegion.set(other.touchableRegion);
         info.type = other.type;
-        info.displayId = other.displayId;
         info.compatibilityScale = other.compatibilityScale;
         info.visible = other.visible;
+        info.displayId = other.displayId;
+        info.layer = other.layer;
         return info;
     }
 
@@ -131,8 +136,25 @@
         frame.setEmpty();
         touchableRegion.setEmpty();
         type = UNDEFINED;
-        displayId = UNDEFINED;
+        compatibilityScale = UNDEFINED;
         visible = false;
+        displayId = UNDEFINED;
+        layer = UNDEFINED;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Window [token:").append((token != null) ? token.hashCode() : null);
+        builder.append(", displayId:").append(displayId);
+        builder.append(", type:").append(type);
+        builder.append(", visible:").append(visible);
+        builder.append(", layer:").append(layer);
+        builder.append(", compatibilityScale:").append(compatibilityScale);
+        builder.append(", frame:").append(frame);
+        builder.append(", touchableRegion:").append(touchableRegion);
+        builder.append("]");
+        return builder.toString();
     }
 
     /**
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index 8301211..d6482fa 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -67,6 +67,8 @@
 import com.android.internal.os.SomeArgs;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 
 /**
  * This class handles the screen magnification when accessibility is enabled.
@@ -1020,7 +1022,9 @@
                 }
                 if (info.type == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
                         || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD
-                        || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG) {
+                        || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG
+                        || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD
+                        || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
                     switch (transition) {
                         case WindowManagerPolicy.TRANSIT_ENTER:
                         case WindowManagerPolicy.TRANSIT_SHOW:
@@ -1473,7 +1477,9 @@
 
         private final ArrayList<WindowInfo> mTempWindowInfoList = new ArrayList<WindowInfo>();
 
-        private final Rect mTempRect = new Rect();
+        private final Rect mTempRect1 = new Rect();
+        private final Rect mTempRect2 = new Rect();
+        private final Rect mTempRect3 = new Rect();
 
         private final IWindowManager mWindowManagerService;
         private final DisplayProvider mDisplayProvider;
@@ -1542,31 +1548,83 @@
             recomputeBounds(false);
         }
 
+        private final Comparator<WindowInfo> mWindowInfoInverseComparator =
+                new Comparator<WindowInfo>() {
+            @Override
+            public int compare(WindowInfo lhs, WindowInfo rhs) {
+                if (lhs.layer != rhs.layer) {
+                    return rhs.layer - lhs.layer;
+                }
+                if (lhs.touchableRegion.top != rhs.touchableRegion.top) {
+                    return rhs.touchableRegion.top - lhs.touchableRegion.top;
+                }
+                if (lhs.touchableRegion.left != rhs.touchableRegion.left) {
+                    return rhs.touchableRegion.left - lhs.touchableRegion.left;
+                }
+                if (lhs.touchableRegion.right != rhs.touchableRegion.right) {
+                    return rhs.touchableRegion.right - lhs.touchableRegion.right;
+                }
+                if (lhs.touchableRegion.bottom != rhs.touchableRegion.bottom) {
+                    return rhs.touchableRegion.bottom - lhs.touchableRegion.bottom;
+                }
+                return 0;
+            }
+        };
+
         public void recomputeBounds(boolean animate) {
-            Rect frame = mTempRect;
-            frame.set(0, 0, mDisplayProvider.getDisplayInfo().logicalWidth,
-                    mDisplayProvider.getDisplayInfo().logicalHeight);
+            Rect magnifiedFrame = mTempRect1;
+            magnifiedFrame.set(0, 0, 0, 0);
+
+            Rect notMagnifiedFrame = mTempRect2;
+            notMagnifiedFrame.set(0, 0, 0, 0);
+
             ArrayList<WindowInfo> infos = mTempWindowInfoList;
             infos.clear();
+            int windowCount = 0;
             try {
                 mWindowManagerService.getVisibleWindowsForDisplay(
                         mDisplayProvider.getDisplay().getDisplayId(), infos);
-                final int windowCount = infos.size();
+                Collections.sort(infos, mWindowInfoInverseComparator);
+                windowCount = infos.size();
                 for (int i = 0; i < windowCount; i++) {
                     WindowInfo info = infos.get(i);
-                    if (info.type == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
-                            || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD
-                            || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG) {
-                        subtract(frame, info.touchableRegion);
+                    if (info.type == WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY) {
+                        continue;
                     }
-                    info.recycle();
+                    if (isWindowMagnified(info.type)) {
+                        Rect clippedFrame = mTempRect3;
+                        clippedFrame.set(info.touchableRegion);
+                        subtract(clippedFrame, notMagnifiedFrame);
+                        magnifiedFrame.union(clippedFrame);
+                    } else {
+                        Rect clippedFrame = mTempRect3;
+                        clippedFrame.set(info.touchableRegion);
+                        subtract(clippedFrame, magnifiedFrame);
+                        notMagnifiedFrame.union(clippedFrame);
+                    }
+                    if (magnifiedFrame.bottom >= notMagnifiedFrame.top) {
+                        break;
+                    }
                 }
             } catch (RemoteException re) {
                 /* ignore */
             } finally {
-                infos.clear();
+                for (int i = windowCount - 1; i >= 0; i--) {
+                    infos.remove(i).recycle();
+                }
             }
-            resize(frame, animate);
+
+            final int displayWidth = mDisplayProvider.getDisplayInfo().logicalWidth;
+            final int displayHeight = mDisplayProvider.getDisplayInfo().logicalHeight;
+            magnifiedFrame.intersect(0, 0, displayWidth, displayHeight);
+
+            resize(magnifiedFrame, animate);
+        }
+
+        private boolean isWindowMagnified(int type) {
+            return (type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+                    && type != WindowManager.LayoutParams.TYPE_INPUT_METHOD
+                    && type != WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
         }
 
         public void rotationChanged() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 6951879..b1e4f4b 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3153,6 +3153,7 @@
         info.compatibilityScale = window.mGlobalScale;
         info.visible = window.isVisibleLw()
                 || info.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
+        info.layer = window.mLayer;
         window.getTouchableRegion(mTempRegion);
         mTempRegion.getBounds(info.touchableRegion);
         return info;