Add new API to find smallest/largest screen size.

Change-Id: I790801fceaf84ee2e3b1c9d32828285ad3231d0e
diff --git a/api/current.txt b/api/current.txt
index 6d8e9a0..82905a0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22537,6 +22537,7 @@
   }
 
   public class Display {
+    method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
     method public int getDisplayId();
     method public deprecated int getHeight();
     method public void getMetrics(android.util.DisplayMetrics);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index ad2283e..bda8016 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -143,6 +143,49 @@
     }
 
     /**
+     * Return the range of display sizes an application can expect to encounter
+     * under normal operation, as long as there is no physical change in screen
+     * size.  This is basically the sizes you will see as the orientation
+     * changes, taking into account whatever screen decoration there is in
+     * each rotation.  For example, the status bar is always at the top of the
+     * screen, so it will reduce the height both in landscape and portrait, and
+     * the smallest height returned here will be the smaller of the two.
+     *
+     * This is intended for applications to get an idea of the range of sizes
+     * they will encounter while going through device rotations, to provide a
+     * stable UI through rotation.  The sizes here take into account all standard
+     * system decorations that reduce the size actually available to the
+     * application: the status bar, navigation bar, system bar, etc.  It does
+     * <em>not</em> take into account more transient elements like an IME
+     * soft keyboard.
+     *
+     * @param outSmallestSize Filled in with the smallest width and height
+     * that the application will encounter, in pixels (not dp units).  The x
+     * (width) dimension here directly corresponds to
+     * {@link android.content.res.Configuration#smallestScreenWidthDp
+     * Configuration.smallestScreenWidthDp}, except the value here is in raw
+     * screen pixels rather than dp units.  Your application may of course
+     * still get smaller space yet if, for example, a soft keyboard is
+     * being displayed.
+     * @param outLargestSize Filled in with the largest width and height
+     * that the application will encounter, in pixels (not dp units).  Your
+     * application may of course still get larger space than this if,
+     * for example, screen decorations like the status bar are being hidden.
+     */
+    public void getCurrentSizeRange(Point outSmallestSize, Point outLargestSize) {
+        try {
+            IWindowManager wm = getWindowManager();
+            wm.getCurrentSizeRange(outSmallestSize, outLargestSize);
+        } catch (RemoteException e) {
+            Slog.w("Display", "Unable to get display size range", e);
+            outSmallestSize.x = 0;
+            outSmallestSize.y = 0;
+            outLargestSize.x = 0;
+            outLargestSize.y = 0;
+        }
+    }
+
+    /**
      * Return the maximum screen size dimension that will happen.  This is
      * mostly for wallpapers.
      * @hide
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b70d7b5..e1f01db 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -58,6 +58,7 @@
     void getDisplaySize(out Point size);
     void getRealDisplaySize(out Point size);
     int getMaximumSizeDimension();
+    void getCurrentSizeRange(out Point smallestSize, out Point largestSize);
 
     void setForcedDisplaySize(int longDimen, int shortDimen);
     void clearForcedDisplaySize();
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b4a458f..f698fbc 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -461,6 +461,10 @@
     int mCurDisplayHeight = 0;
     int mAppDisplayWidth = 0;
     int mAppDisplayHeight = 0;
+    int mSmallestDisplayWidth = 0;
+    int mSmallestDisplayHeight = 0;
+    int mLargestDisplayWidth = 0;
+    int mLargestDisplayHeight = 0;
 
     int mRotation = 0;
     int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -6068,12 +6072,21 @@
         return config;
     }
 
-    private int reduceConfigWidthSize(int curSize, int rotation, float density, int dw, int dh) {
-        int size = (int)(mPolicy.getConfigDisplayWidth(dw, dh, rotation) / density);
-        if (size < curSize) {
-            curSize = size;
+    private void adjustDisplaySizeRanges(int rotation, int dw, int dh) {
+        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
+        if (width < mSmallestDisplayWidth) {
+            mSmallestDisplayWidth = width;
         }
-        return curSize;
+        if (width > mLargestDisplayWidth) {
+            mLargestDisplayWidth = width;
+        }
+        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
+        if (height < mSmallestDisplayHeight) {
+            mSmallestDisplayHeight = height;
+        }
+        if (height > mLargestDisplayHeight) {
+            mLargestDisplayHeight = height;
+        }
     }
 
     private int reduceConfigLayout(int curLayout, int rotation, float density,
@@ -6155,7 +6168,7 @@
         return curLayout;
     }
 
-    private void computeSmallestWidthAndScreenLayout(boolean rotated, int dw, int dh,
+    private void computeSizeRangesAndScreenLayout(boolean rotated, int dw, int dh,
             float density, Configuration outConfig) {
         // We need to determine the smallest width that will occur under normal
         // operation.  To this, start with the base screen size and compute the
@@ -6169,17 +6182,21 @@
             unrotDw = dw;
             unrotDh = dh;
         }
-        int sw = reduceConfigWidthSize(unrotDw, Surface.ROTATION_0, density, unrotDw, unrotDh);
-        sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDh, unrotDw);
-        sw = reduceConfigWidthSize(sw, Surface.ROTATION_180, density, unrotDw, unrotDh);
-        sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDh, unrotDw);
+        mSmallestDisplayWidth = 1<<30;
+        mSmallestDisplayHeight = 1<<30;
+        mLargestDisplayWidth = 0;
+        mLargestDisplayHeight = 0;
+        adjustDisplaySizeRanges(Surface.ROTATION_0, unrotDw, unrotDh);
+        adjustDisplaySizeRanges(Surface.ROTATION_90, unrotDh, unrotDw);
+        adjustDisplaySizeRanges(Surface.ROTATION_180, unrotDw, unrotDh);
+        adjustDisplaySizeRanges(Surface.ROTATION_270, unrotDh, unrotDw);
         int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE
                 | Configuration.SCREENLAYOUT_LONG_YES;
         sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
         sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
         sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
         sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
-        outConfig.smallestScreenWidthDp = sw;
+        outConfig.smallestScreenWidthDp = (int)(mSmallestDisplayWidth / density);
         outConfig.screenLayout = sl;
     }
 
@@ -6289,7 +6306,7 @@
                     / dm.density);
             config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
                     / dm.density);
-            computeSmallestWidthAndScreenLayout(rotated, dw, dh, dm.density, config);
+            computeSizeRangesAndScreenLayout(rotated, dw, dh, dm.density, config);
 
             config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
             config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
@@ -7199,6 +7216,15 @@
         }
     }
 
+    public void getCurrentSizeRange(Point smallestSize, Point largestSize) {
+        synchronized(mDisplaySizeLock) {
+            smallestSize.x = mSmallestDisplayWidth;
+            smallestSize.y = mSmallestDisplayHeight;
+            largestSize.x = mLargestDisplayWidth;
+            largestSize.y = mLargestDisplayHeight;
+        }
+    }
+
     public void setForcedDisplaySize(int longDimen, int shortDimen) {
         synchronized(mWindowMap) {
             int width, height;
@@ -9391,14 +9417,25 @@
         pw.println();
         if (mDisplay != null) {
             pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
-                    pw.print(mInitialDisplayHeight); pw.print(" base=");
-                    pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+                    pw.print(mInitialDisplayHeight);
+                    if (mInitialDisplayWidth != mBaseDisplayWidth
+                            || mInitialDisplayHeight != mBaseDisplayHeight) {
+                        pw.print(" base=");
+                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+                    }
+                    final int rawWidth = mDisplay.getRawWidth();
+                    final int rawHeight = mDisplay.getRawHeight();
+                    if (rawWidth != mCurDisplayWidth || rawHeight != mCurDisplayHeight) {
+                        pw.print(" raw="); pw.print(rawWidth); pw.print("x"); pw.print(rawHeight);
+                    }
                     pw.print(" cur=");
                     pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
                     pw.print(" app=");
                     pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
-                    pw.print(" raw="); pw.print(mDisplay.getRawWidth());
-                    pw.print("x"); pw.println(mDisplay.getRawHeight());
+                    pw.print(" rng="); pw.print(mSmallestDisplayWidth);
+                    pw.print("x"); pw.print(mSmallestDisplayHeight);
+                    pw.print("-"); pw.print(mLargestDisplayWidth);
+                    pw.print("x"); pw.println(mLargestDisplayHeight);
         } else {
             pw.println("  NO DISPLAY");
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 44d28fa..85b67d5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -78,6 +78,10 @@
     }
 
     @Override
+    public void getCurrentSizeRange(Point smallestSize, Point largestSize) {
+    }
+
+    @Override
     public void getDisplaySize(Point arg0) throws RemoteException {
     }