Report the external display size to the input reader.

The input reader needs this information so that it knows how to
interpolate touches on an external touch screen.

Changed Display so that it asks the WindowManager what the real
display size is (as opposed to the raw display size).  This means
it now takes into the forced display size set by
adb shell am display-size.

Replaced all calls to getRealWidth() / getRealHeight() /
getRealMetrics() in the WindowManager and replaced them with direct
usages of the mCurDisplayWidth / mCurDisplayHeight so that the WM
doesn't end up making a reentrant Binder call into itself.

Fixed the table status bar HeightReceiver so that it updates the
height on all configuration changes since it is possible that the
display size changed independently of an external HDMI display
being plugged / unplugged.

Improved the Display class documentation to make the distinctions
betweeen the various sizes clearer.

Change-Id: I3f75de559d3ebffed532ab46c4ae52c5e7f1da2b
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5ab2024..d9efe0c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -25,16 +25,18 @@
 import android.util.DisplayMetrics;
 import android.util.Slog;
 
+/**
+ * Provides information about the display size and density.
+ */
 public class Display {
     static final String TAG = "Display";
     static final boolean DEBUG_COMPAT = false;
 
     /**
-     * Specify the default Display
+     * The default Display id.
      */
     public static final int DEFAULT_DISPLAY = 0;
 
-    
     /**
      * Use {@link android.view.WindowManager#getDefaultDisplay()
      * WindowManager.getDefaultDisplay()} to create a Display object.
@@ -55,16 +57,6 @@
         init(display);
     }
 
-    /** @hide */
-    public static void setCompatibilityInfo(CompatibilityInfo compatInfo) {
-        if (compatInfo != null && (compatInfo.isScalingRequired()
-                || !compatInfo.supportsScreen())) {
-            sCompatibilityInfo = compatInfo;
-        } else {
-            sCompatibilityInfo = null;
-        }
-    }
-    
     /**
      * Returns the index of this display.  This is currently undefined; do
      * not use.
@@ -80,25 +72,29 @@
     native static int getDisplayCount();
     
     /**
-     * Returns the raw size of the display, in pixels.  Note that this
-     * should <em>not</em> generally be used for computing layouts, since
-     * a device will typically have screen decoration (such as a status bar)
+     * Gets the size of the display, in pixels.
+     * <p>
+     * Note that this value should <em>not</em> be used for computing layouts,
+     * since a device will typically have screen decoration (such as a status bar)
      * along the edges of the display that reduce the amount of application
-     * space available from the raw size returned here.  This value is
-     * adjusted for you based on the current rotation of the display.
+     * space available from the size returned here.  Layouts should instead use
+     * the window size.
+     * </p><p>
+     * The size is adjusted based on the current rotation of the display.
+     * </p><p>
+     * The size returned by this method does not necessarily represent the
+     * actual raw size (native resolution) of the display.  The returned size may
+     * be adjusted to exclude certain system decor elements that are always visible.
+     * It may also be scaled to provide compatibility with older applications that
+     * were originally designed for smaller displays.
+     * </p>
+     *
+     * @param outSize A {@link Point} object to receive the size information.
      */
     public void getSize(Point outSize) {
         getSizeInternal(outSize, true);
     }
 
-    /**
-     * Returns the raw size of the display, in pixels.  Note that this
-     * should <em>not</em> generally be used for computing layouts, since
-     * a device will typically have screen decoration (such as a status bar)
-     * along the edges of the display that reduce the amount of application
-     * space available from the raw size returned here.  This value is
-     * adjusted for you based on the current rotation of the display.
-     */
     private void getSizeInternal(Point outSize, boolean doCompat) {
         try {
             IWindowManager wm = getWindowManager();
@@ -118,8 +114,8 @@
             } else {
                 // This is just for boot-strapping, initializing the
                 // system process before the window manager is up.
-                outSize.x = getRealWidth();
-                outSize.y = getRealHeight();
+                outSize.x = getRawWidth();
+                outSize.y = getRawHeight();
             }
             if (DEBUG_COMPAT && doCompat) Slog.v(TAG, "Returning display size: " + outSize);
         } catch (RemoteException e) {
@@ -128,7 +124,10 @@
     }
     
     /**
-     * This is just easier for some parts of the framework.
+     * Gets the size of the display as a rectangle, in pixels.
+     *
+     * @param outSize A {@link Rect} object to receive the size information.
+     * @see #getSize(Point)
      */
     public void getRectSize(Rect outSize) {
         synchronized (mTmpPoint) {
@@ -182,14 +181,49 @@
         }
     }
 
-    /** @hide Returns the actual screen size, not including any decor. */
-    native public int getRealWidth();
-    /** @hide Returns the actual screen size, not including any decor. */
-    native public int getRealHeight();
+    /**
+     * Gets the real size of the display without subtracting any window decor or
+     * applying any compatibility scale factors.
+     * <p>
+     * The real size may be smaller than the raw size when the window manager
+     * is emulating a smaller display (using adb shell am display-size).
+     * </p><p>
+     * The size is adjusted based on the current rotation of the display.
+     * </p>
+     * @hide
+     */
+    public void getRealSize(Point outSize) {
+        try {
+            IWindowManager wm = getWindowManager();
+            if (wm != null) {
+                wm.getRealDisplaySize(outSize);
+            } else {
+                // This is just for boot-strapping, initializing the
+                // system process before the window manager is up.
+                outSize.x = getRawWidth();
+                outSize.y = getRawHeight();
+            }
+        } catch (RemoteException e) {
+            Slog.w("Display", "Unable to get real display size", e);
+        }
+    }
 
-    /** @hide special for when we are faking the screen size. */
+    /**
+     * Gets the raw width of the display, in pixels.
+     * <p>
+     * The size is adjusted based on the current rotation of the display.
+     * </p>
+     * @hide
+     */
     native public int getRawWidth();
-    /** @hide special for when we are faking the screen size. */
+
+    /**
+     * Gets the raw height of the display, in pixels.
+     * <p>
+     * The size is adjusted based on the current rotation of the display.
+     * </p>
+     * @hide
+     */
     native public int getRawHeight();
     
     /**
@@ -235,17 +269,24 @@
     }
     
     /**
-     * Initialize a DisplayMetrics object from this display's data.
-     * 
-     * @param outMetrics
+     * Gets display metrics that describe the size and density of this display.
+     * <p>
+     * The size is adjusted based on the current rotation of the display.
+     * </p><p>
+     * The size returned by this method does not necessarily represent the
+     * actual raw size (native resolution) of the display.  The returned size may
+     * be adjusted to exclude certain system decor elements that are always visible.
+     * It may also be scaled to provide compatibility with older applications that
+     * were originally designed for smaller displays.
+     * </p>
+     *
+     * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
      */
     public void getMetrics(DisplayMetrics outMetrics) {
         synchronized (mTmpPoint) {
             getSizeInternal(mTmpPoint, false);
-            outMetrics.widthPixels = mTmpPoint.x;
-            outMetrics.heightPixels = mTmpPoint.y;
+            getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y);
         }
-        getNonSizeMetrics(outMetrics);
 
         CompatibilityInfo ci = mCompatibilityInfo.getIfNeeded();
         if (ci != null) {
@@ -257,22 +298,44 @@
     }
 
     /**
-     * Initialize a DisplayMetrics object from this display's data.
-     *
-     * @param outMetrics
+     * Gets display metrics based on the real size of this display.
      * @hide
      */
     public void getRealMetrics(DisplayMetrics outMetrics) {
-        outMetrics.widthPixels = getRealWidth();
-        outMetrics.heightPixels = getRealHeight();
-        getNonSizeMetrics(outMetrics);
+        synchronized (mTmpPoint) {
+            getRealSize(mTmpPoint);
+            getMetricsWithSize(outMetrics, mTmpPoint.x, mTmpPoint.y);
+        }
     }
 
-    private void getNonSizeMetrics(DisplayMetrics outMetrics) {
+    /**
+     * If the display is mirrored to an external HDMI display, returns the
+     * width of that display.
+     * @hide
+     */
+    public int getRawExternalWidth() {
+        return 1280;
+    }
+
+    /**
+     * If the display is mirrored to an external HDMI display, returns the
+     * height of that display.
+     * @hide
+     */
+    public int getRawExternalHeight() {
+        return 720;
+    }
+
+    /**
+     * Gets display metrics based on an explicit assumed display size.
+     * @hide
+     */
+    public void getMetricsWithSize(DisplayMetrics outMetrics,
+            int width, int height) {
         outMetrics.densityDpi   = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f);
 
-        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels;
-        outMetrics.noncompatHeightPixels = outMetrics.heightPixels;
+        outMetrics.noncompatWidthPixels  = outMetrics.widthPixels = width;
+        outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
 
         outMetrics.density = outMetrics.noncompatDensity = mDensity;
         outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
@@ -315,8 +378,6 @@
     private static boolean sInitialized = false;
     private static IWindowManager sWindowManager;
 
-    private static volatile CompatibilityInfo sCompatibilityInfo;
-
     /**
      * Returns a display object which uses the metric's width/height instead.
      * @hide
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index ad17edf..81cd798 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -55,6 +55,7 @@
     boolean inputMethodClientHasFocus(IInputMethodClient client);
     
     void getDisplaySize(out Point size);
+    void getRealDisplaySize(out Point size);
     int getMaximumSizeDimension();
 
     void setForcedDisplaySize(int longDimen, int shortDimen);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 470493d..71f5a93 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -824,8 +824,10 @@
             if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
                 // NOTE -- system code, won't try to do compat mode.
                 Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
-                desiredWindowWidth = disp.getRealWidth();
-                desiredWindowHeight = disp.getRealHeight();
+                Point size = new Point();
+                disp.getRealSize(size);
+                desiredWindowWidth = size.x;
+                desiredWindowHeight = size.y;
             } else {
                 DisplayMetrics packageMetrics =
                     mView.getContext().getResources().getDisplayMetrics();
@@ -979,8 +981,10 @@
                     if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
                         // NOTE -- system code, won't try to do compat mode.
                         Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
-                        desiredWindowWidth = disp.getRealWidth();
-                        desiredWindowHeight = disp.getRealHeight();
+                        Point size = new Point();
+                        disp.getRealSize(size);
+                        desiredWindowWidth = size.x;
+                        desiredWindowHeight = size.y;
                     } else {
                         DisplayMetrics packageMetrics = res.getDisplayMetrics();
                         desiredWindowWidth = packageMetrics.widthPixels;
diff --git a/core/jni/android_view_Display.cpp b/core/jni/android_view_Display.cpp
index 97f9fc3..5e668b9 100644
--- a/core/jni/android_view_Display.cpp
+++ b/core/jni/android_view_Display.cpp
@@ -45,11 +45,6 @@
 };
 static offsets_t offsets;
 
-static int gShortSize = -1;
-static int gLongSize = -1;
-static int gOldSize = -1;
-static int gNewSize = -1;
-
 // ----------------------------------------------------------------------------
 
 static void android_view_Display_init(
@@ -68,30 +63,6 @@
     env->SetFloatField(clazz, offsets.ydpi,     info.ydpi);
 }
 
-static jint android_view_Display_getWidth(
-        JNIEnv* env, jobject clazz)
-{
-    DisplayID dpy = env->GetIntField(clazz, offsets.display);
-    jint w = SurfaceComposerClient::getDisplayWidth(dpy);
-    if (gShortSize > 0) {
-        jint h = SurfaceComposerClient::getDisplayHeight(dpy);
-        return w < h ? gShortSize : gLongSize;
-    }
-    return w == gOldSize ? gNewSize : w;
-}
-
-static jint android_view_Display_getHeight(
-        JNIEnv* env, jobject clazz)
-{
-    DisplayID dpy = env->GetIntField(clazz, offsets.display);
-    int h = SurfaceComposerClient::getDisplayHeight(dpy);
-    if (gShortSize > 0) {
-        jint w = SurfaceComposerClient::getDisplayWidth(dpy);
-        return h < w ? gShortSize : gLongSize;
-    }
-    return h == gOldSize ? gNewSize : h;
-}
-
 static jint android_view_Display_getRawWidth(
         JNIEnv* env, jobject clazz)
 {
@@ -132,10 +103,6 @@
             (void*)android_view_Display_getDisplayCount },
 	{   "init", "(I)V",
             (void*)android_view_Display_init },
-    {   "getRealWidth", "()I",
-            (void*)android_view_Display_getWidth },
-    {   "getRealHeight", "()I",
-            (void*)android_view_Display_getHeight },
     {   "getRawWidth", "()I",
             (void*)android_view_Display_getRawWidth },
     {   "getRawHeight", "()I",
@@ -156,24 +123,6 @@
 
 int register_android_view_Display(JNIEnv* env)
 {
-    char buf[PROPERTY_VALUE_MAX];
-    int len = property_get("persist.demo.screensizehack", buf, "");
-    if (len > 0) {
-        int temp1, temp2;
-        if (sscanf(buf, "%dx%d", &temp1, &temp2) == 2) {
-            if (temp1 < temp2) {
-                gShortSize = temp1;
-                gLongSize = temp2;
-            } else {
-                gShortSize = temp2;
-                gLongSize = temp1;
-            }
-        } else if (sscanf(buf, "%d=%d", &temp1, &temp2) == 2) {
-            gOldSize = temp1;
-            gNewSize = temp2;
-        }
-    }
-
     return AndroidRuntime::registerNativeMethods(env,
             kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
index 7f4c918..3e9a9d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/HeightReceiver.java
@@ -25,7 +25,7 @@
 import android.content.res.Resources;
 import android.util.DisplayMetrics;
 import android.util.Slog;
-import android.view.View;
+import android.view.Display;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
@@ -41,6 +41,7 @@
     ArrayList<OnBarHeightChangedListener> mListeners = new ArrayList<OnBarHeightChangedListener>();
     WindowManager mWindowManager;
     int mHeight;
+    boolean mPlugged;
 
     public HeightReceiver(Context context) {
         mContext = context;
@@ -71,15 +72,24 @@
     }
 
     private void setPlugged(boolean plugged) {
+        mPlugged = plugged;
+        updateHeight();
+    }
+
+    public void updateHeight() {
         final Resources res = mContext.getResources();
 
         int height = -1;
-        if (plugged) {
+        if (mPlugged) {
             final DisplayMetrics metrics = new DisplayMetrics();
-            mWindowManager.getDefaultDisplay().getRealMetrics(metrics);
-            //Slog.i(TAG, "setPlugged: display metrics=" + metrics);
+            Display display = mWindowManager.getDefaultDisplay();
+            display.getRealMetrics(metrics);
+
+            //Slog.i(TAG, "updateHeight: display metrics=" + metrics);
             final int shortSide = Math.min(metrics.widthPixels, metrics.heightPixels);
-            height = shortSide - 720;
+            final int externalShortSide = Math.min(display.getRawExternalWidth(),
+                    display.getRawExternalHeight());
+            height = shortSide - externalShortSide;
         }
 
         final int minHeight
@@ -87,7 +97,7 @@
         if (height < minHeight) {
             height = minHeight;
         }
-        Slog.i(TAG, "Resizing status bar plugged=" + plugged + " height="
+        Slog.i(TAG, "Resizing status bar plugged=" + mPlugged + " height="
                 + height + " old=" + mHeight);
         mHeight = height;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 13846ed..9d24f5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -34,6 +34,7 @@
 import android.content.res.Resources;
 import android.inputmethodservice.InputMethodService;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.LayerDrawable;
 import android.provider.Settings;
@@ -341,8 +342,9 @@
     private int getNotificationPanelHeight() {
         final Resources res = mContext.getResources();
         final Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
-        return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height),
-                d.getRealHeight());
+        final Point size = new Point();
+        d.getRealSize(size);
+        return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height), size.y);
     }
 
     @Override
@@ -352,6 +354,7 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
+        mHeightReceiver.updateHeight(); // display size may have changed
         loadDimens();
         mNotificationPanelParams.height = getNotificationPanelHeight();
         WindowManagerImpl.getDefault().updateViewLayout(mNotificationPanel,
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 9d69c60..db312ad 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -1505,7 +1505,10 @@
     getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1;
+    mParameters.associatedDisplayId = -1;
+    if (mParameters.orientationAware) {
+        mParameters.associatedDisplayId = 0;
+    }
 }
 
 void KeyboardInputMapper::dumpParameters(String8& dump) {
@@ -1577,7 +1580,7 @@
             if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
                 int32_t orientation;
                 if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
-                        NULL, NULL, & orientation)) {
+                        false /*external*/, NULL, NULL, & orientation)) {
                     orientation = DISPLAY_ORIENTATION_0;
                 }
 
@@ -1830,8 +1833,10 @@
     getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = mParameters.mode == Parameters::MODE_POINTER
-            || mParameters.orientationAware ? 0 : -1;
+    mParameters.associatedDisplayId = -1;
+    if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
+        mParameters.associatedDisplayId = 0;
+    }
 }
 
 void CursorInputMapper::dumpParameters(String8& dump) {
@@ -1943,7 +1948,7 @@
             // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
             int32_t orientation;
             if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
-                    NULL, NULL, & orientation)) {
+                    false /*external*/, NULL, NULL, & orientation)) {
                 orientation = DISPLAY_ORIENTATION_0;
             }
 
@@ -2308,10 +2313,16 @@
     getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = mParameters.orientationAware
+    mParameters.associatedDisplayId = -1;
+    mParameters.associatedDisplayIsExternal = false;
+    if (mParameters.orientationAware
             || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-            || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER
-            ? 0 : -1;
+            || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+        mParameters.associatedDisplayIsExternal =
+                mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
+                        && getDevice()->isExternal();
+        mParameters.associatedDisplayId = 0;
+    }
 }
 
 void TouchInputMapper::dumpParameters(String8& dump) {
@@ -2393,6 +2404,7 @@
     if (mParameters.associatedDisplayId >= 0) {
         // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
         if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+                mParameters.associatedDisplayIsExternal,
                 &mLocked.associatedDisplayWidth, &mLocked.associatedDisplayHeight,
                 &mLocked.associatedDisplayOrientation)) {
             return false;
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index f9750d0..ee6990b 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -180,9 +180,11 @@
     };
 
     /* Gets information about the display with the specified id.
+     * If external is true, returns the size of the external mirrored
+     * counterpart of the specified display.
      * Returns true if the display info is available, false otherwise.
      */
-    virtual bool getDisplayInfo(int32_t displayId,
+    virtual bool getDisplayInfo(int32_t displayId, bool external,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
     /* Gets the input reader configuration. */
@@ -944,6 +946,7 @@
 
         DeviceType deviceType;
         int32_t associatedDisplayId;
+        bool associatedDisplayIsExternal;
         bool orientationAware;
 
         enum GestureMode {
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 7a6af25..8533743 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -157,7 +157,7 @@
     }
 
 private:
-    virtual bool getDisplayInfo(int32_t displayId,
+    virtual bool getDisplayInfo(int32_t displayId, bool external /*currently ignored*/,
             int32_t* width, int32_t* height, int32_t* orientation) {
         ssize_t index = mDisplayInfos.indexOfKey(displayId);
         if (index >= 0) {
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 8146fca..b37d1c2 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -123,8 +123,8 @@
             // The drag window covers the entire display
             mDragWindowHandle.frameLeft = 0;
             mDragWindowHandle.frameTop = 0;
-            mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
-            mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
+            mDragWindowHandle.frameRight = mService.mCurDisplayWidth;
+            mDragWindowHandle.frameBottom = mService.mCurDisplayHeight;
         }
     }
 
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 3133a19..1d0857b 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -64,7 +64,8 @@
     private static native void nativeInit(Context context,
             Callbacks callbacks, MessageQueue messageQueue);
     private static native void nativeStart();
-    private static native void nativeSetDisplaySize(int displayId, int width, int height);
+    private static native void nativeSetDisplaySize(int displayId, int width, int height,
+            int externalWidth, int externalHeight);
     private static native void nativeSetDisplayOrientation(int displayId, int rotation);
     
     private static native int nativeGetScanCodeState(int deviceId, int sourceMask,
@@ -144,15 +145,17 @@
         updatePointerSpeedFromSettings();
     }
     
-    public void setDisplaySize(int displayId, int width, int height) {
-        if (width <= 0 || height <= 0) {
+    public void setDisplaySize(int displayId, int width, int height,
+            int externalWidth, int externalHeight) {
+        if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) {
             throw new IllegalArgumentException("Invalid display id or dimensions.");
         }
         
         if (DEBUG) {
-            Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+            Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height
+                    + " external size " + externalWidth + "x" + externalHeight);
         }
-        nativeSetDisplaySize(displayId, width, height);
+        nativeSetDisplaySize(displayId, width, height, externalWidth, externalHeight);
     }
     
     public void setDisplayOrientation(int displayId, int rotation) {
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 8470918..16af151 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -25,9 +25,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.util.DisplayMetrics;
 import android.util.Slog;
-import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceSession;
 import android.view.animation.Animation;
@@ -41,7 +39,6 @@
     static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
 
     final Context mContext;
-    final Display mDisplay;
     Surface mSurface;
     BlackFrame mBlackFrame;
     int mWidth, mHeight;
@@ -58,18 +55,14 @@
     final Transformation mEnterTransformation = new Transformation();
     boolean mStarted;
 
-    final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     final Matrix mSnapshotInitialMatrix = new Matrix();
     final Matrix mSnapshotFinalMatrix = new Matrix();
     final Matrix mTmpMatrix = new Matrix();
     final float[] mTmpFloats = new float[9];
 
-    public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
-            boolean inTransaction) {
+    public ScreenRotationAnimation(Context context, SurfaceSession session,
+            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
         mContext = context;
-        mDisplay = display;
-
-        display.getRealMetrics(mDisplayMetrics);
 
         Bitmap screenshot = Surface.screenshot(0, 0);
 
@@ -83,9 +76,9 @@
         mWidth = screenshot.getWidth();
         mHeight = screenshot.getHeight();
 
-        mOriginalRotation = display.getRotation();
-        mOriginalWidth = mDisplayMetrics.widthPixels;
-        mOriginalHeight = mDisplayMetrics.heightPixels;
+        mOriginalRotation = originalRotation;
+        mOriginalWidth = originalWidth;
+        mOriginalHeight = originalHeight;
 
         if (!inTransaction) {
             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
@@ -106,7 +99,7 @@
                     WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
                             "  FREEZE " + mSurface + ": CREATE");
 
-            setRotation(display.getRotation());
+            setRotation(originalRotation);
 
             if (mSurface != null) {
                 Rect dirty = new Rect(0, 0, mWidth, mHeight);
@@ -212,7 +205,7 @@
      * Returns true if animating.
      */
     public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
-            float animationScale) {
+            float animationScale, int finalWidth, int finalHeight) {
         if (mSurface == null) {
             // Can't do animation.
             return false;
@@ -248,16 +241,12 @@
                 break;
         }
 
-        mDisplay.getRealMetrics(mDisplayMetrics);
-
         // Initialize the animations.  This is a hack, redefining what "parent"
         // means to allow supplying the last and next size.  In this definition
         // "%p" is the original (let's call it "previous") size, and "%" is the
         // screen's current/new size.
-        mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
-                mOriginalWidth, mOriginalHeight);
-        mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
-                mOriginalWidth, mOriginalHeight);
+        mEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+        mExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
         mStarted = false;
 
         mExitAnimation.restrictDuration(maxAnimationDuration);
@@ -270,10 +259,8 @@
         Surface.openTransaction();
 
         try {
-            final int w = mDisplayMetrics.widthPixels;
-            final int h = mDisplayMetrics.heightPixels;
-            Rect outer = new Rect(-w, -h, w*2, h*2);
-            Rect inner = new Rect(0, 0, w, h);
+            Rect outer = new Rect(-finalWidth, -finalHeight, finalWidth * 2, finalHeight * 2);
+            Rect inner = new Rect(0, 0, finalWidth, finalHeight);
             mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
         } catch (Surface.OutOfResourcesException e) {
             Slog.w(TAG, "Unable to allocate black surface", e);
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java
index 71b5952..768d2db 100644
--- a/services/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/java/com/android/server/wm/StrictModeFlash.java
@@ -38,9 +38,6 @@
     final int mThickness = 20;
 
     public StrictModeFlash(Display display, SurfaceSession session) {
-        final DisplayMetrics dm = new DisplayMetrics();
-        display.getRealMetrics(dm);
-
         try {
             mSurface = new Surface(session, 0, "StrictModeFlash", -1, 1, 1, PixelFormat.TRANSLUCENT, 0);
         } catch (Surface.OutOfResourcesException e) {
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java
index 375abe5..5497eb4 100644
--- a/services/java/com/android/server/wm/Watermark.java
+++ b/services/java/com/android/server/wm/Watermark.java
@@ -50,10 +50,7 @@
     int mLastDH;
     boolean mDrawNeeded;
 
-    Watermark(Display display, SurfaceSession session, String[] tokens) {
-        final DisplayMetrics dm = new DisplayMetrics();
-        display.getRealMetrics(dm);
-
+    Watermark(DisplayMetrics dm, SurfaceSession session, String[] tokens) {
         if (false) {
             Log.i(WindowManagerService.TAG, "*********************** WATERMARK");
             for (int i=0; i<tokens.length; i++) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index be21ac0..f8059f5 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -465,6 +465,7 @@
     Display mDisplay;
 
     final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+    final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
     final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
 
@@ -5642,15 +5643,14 @@
         }
         config.orientation = orientation;
 
-        DisplayMetrics dm = mDisplayMetrics;
-        mDisplay.getRealMetrics(dm);
+        // Update real display metrics.
+        mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
 
-        // Override display width and height with what we are computing,
-        // to be sure they remain consistent.
-        dm.widthPixels = dm.noncompatWidthPixels = mAppDisplayWidth
-                = mPolicy.getNonDecorDisplayWidth(mRotation, dw);
-        dm.heightPixels = dm.noncompatHeightPixels = mAppDisplayHeight
-                = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
+        // Update application display metrics.
+        final DisplayMetrics dm = mDisplayMetrics;
+        mAppDisplayWidth = mPolicy.getNonDecorDisplayWidth(mRotation, dw);
+        mAppDisplayHeight = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
+        mDisplay.getMetricsWithSize(dm, mAppDisplayWidth, mAppDisplayHeight);
 
         mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
                 mCompatDisplayMetrics);
@@ -6086,8 +6086,8 @@
             }
             WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
             mDisplay = wm.getDefaultDisplay();
-            mInitialDisplayWidth = mDisplay.getRealWidth();
-            mInitialDisplayHeight = mDisplay.getRealHeight();
+            mInitialDisplayWidth = mDisplay.getRawWidth();
+            mInitialDisplayHeight = mDisplay.getRawHeight();
             int rot = mDisplay.getRotation();
             if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
                 // If the screen is currently rotated, we need to swap the
@@ -6098,7 +6098,9 @@
             }
             mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
             mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
-            mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight());
+            mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
+                    mDisplay.getRawWidth(), mDisplay.getRawHeight(),
+                    mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
             mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight);
         }
 
@@ -6602,6 +6604,13 @@
         }
     }
 
+    public void getRealDisplaySize(Point size) {
+        synchronized(mWindowMap) {
+            size.x = mCurDisplayWidth;
+            size.y = mCurDisplayHeight;
+        }
+    }
+
     public int getMaximumSizeDimension() {
         synchronized(mWindowMap) {
             // Do this based on the raw screen size, until we are smarter.
@@ -8687,7 +8696,8 @@
             }
             if (mScreenRotationAnimation == null) {
                 mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
-                        mDisplay, mFxSession, inTransaction);
+                        mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
+                        mDisplay.getRotation());
             }
             if (!mScreenRotationAnimation.hasScreenshot()) {
                 Surface.freezeDisplay(0);
@@ -8717,7 +8727,7 @@
         if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
                 && mScreenRotationAnimation.hasScreenshot()) {
             if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
-                    mTransitionAnimationScale)) {
+                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
                 requestAnimationLocked(0);
             } else {
                 mScreenRotationAnimation = null;
@@ -8797,7 +8807,7 @@
             if (line != null) {
                 String[] toks = line.split("%");
                 if (toks != null && toks.length > 0) {
-                    mWatermark = new Watermark(mDisplay, mFxSession, toks);
+                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
                 }
             }
         } catch (FileNotFoundException e) {
@@ -9063,8 +9073,6 @@
                         pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
                         pw.print(" app=");
                         pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
-                        pw.print(" real="); pw.print(mDisplay.getRealWidth());
-                        pw.print("x"); pw.print(mDisplay.getRealHeight());
                         pw.print(" raw="); pw.print(mDisplay.getRawWidth());
                         pw.print("x"); pw.println(mDisplay.getRawHeight());
             } else {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d298ff7..cacb3e7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -497,8 +497,8 @@
         }
 
         if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
-            mService.updateWallpaperOffsetLocked(this, mService.mDisplay.getRealWidth(),
-                    mService.mDisplay.getRealHeight(), false);
+            mService.updateWallpaperOffsetLocked(this,
+                    mService.mAppDisplayWidth, mService.mAppDisplayHeight, false);
         }
 
         if (WindowManagerService.localLOGV) {
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index de9c9d0..3414eea 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -166,7 +166,8 @@
 
     void dump(String8& dump);
 
-    void setDisplaySize(int32_t displayId, int32_t width, int32_t height);
+    void setDisplaySize(int32_t displayId, int32_t width, int32_t height,
+            int32_t externalWidth, int32_t externalHeight);
     void setDisplayOrientation(int32_t displayId, int32_t orientation);
 
     status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
@@ -181,7 +182,7 @@
 
     /* --- InputReaderPolicyInterface implementation --- */
 
-    virtual bool getDisplayInfo(int32_t displayId,
+    virtual bool getDisplayInfo(int32_t displayId, bool external,
             int32_t* width, int32_t* height, int32_t* orientation);
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
@@ -221,7 +222,8 @@
     Mutex mLock;
     struct Locked {
         // Display size information.
-        int32_t displayWidth, displayHeight; // -1 when initialized
+        int32_t displayWidth, displayHeight; // -1 when not initialized
+        int32_t displayExternalWidth, displayExternalHeight; // -1 when not initialized
         int32_t displayOrientation;
 
         // System UI visibility.
@@ -269,6 +271,8 @@
         AutoMutex _l(mLock);
         mLocked.displayWidth = -1;
         mLocked.displayHeight = -1;
+        mLocked.displayExternalWidth = -1;
+        mLocked.displayExternalHeight = -1;
         mLocked.displayOrientation = ROTATION_0;
 
         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
@@ -305,22 +309,24 @@
     return false;
 }
 
-void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height) {
+void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height,
+        int32_t externalWidth, int32_t externalHeight) {
     if (displayId == 0) {
         { // acquire lock
             AutoMutex _l(mLock);
 
-            if (mLocked.displayWidth == width && mLocked.displayHeight == height) {
-                return;
+            if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
+                mLocked.displayWidth = width;
+                mLocked.displayHeight = height;
+
+                sp<PointerController> controller = mLocked.pointerController.promote();
+                if (controller != NULL) {
+                    controller->setDisplaySize(width, height);
+                }
             }
 
-            mLocked.displayWidth = width;
-            mLocked.displayHeight = height;
-
-            sp<PointerController> controller = mLocked.pointerController.promote();
-            if (controller != NULL) {
-                controller->setDisplaySize(width, height);
-            }
+            mLocked.displayExternalWidth = externalWidth;
+            mLocked.displayExternalHeight = externalHeight;
         } // release lock
     }
 }
@@ -352,7 +358,7 @@
     return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
 }
 
-bool NativeInputManager::getDisplayInfo(int32_t displayId,
+bool NativeInputManager::getDisplayInfo(int32_t displayId, bool external,
         int32_t* width, int32_t* height, int32_t* orientation) {
     bool result = false;
     if (displayId == 0) {
@@ -360,10 +366,10 @@
 
         if (mLocked.displayWidth > 0 && mLocked.displayHeight > 0) {
             if (width) {
-                *width = mLocked.displayWidth;
+                *width = external ? mLocked.displayExternalWidth : mLocked.displayWidth;
             }
             if (height) {
-                *height = mLocked.displayHeight;
+                *height = external ? mLocked.displayExternalHeight : mLocked.displayHeight;
             }
             if (orientation) {
                 *orientation = mLocked.displayOrientation;
@@ -952,7 +958,7 @@
 }
 
 static void android_server_InputManager_nativeSetDisplaySize(JNIEnv* env, jclass clazz,
-        jint displayId, jint width, jint height) {
+        jint displayId, jint width, jint height, jint externalWidth, jint externalHeight) {
     if (checkInputManagerUnitialized(env)) {
         return;
     }
@@ -961,7 +967,7 @@
     // to be passed in like this, not sure which is better but leaving it like this
     // keeps the window manager in direct control of when display transitions propagate down
     // to the input dispatcher
-    gNativeInputManager->setDisplaySize(displayId, width, height);
+    gNativeInputManager->setDisplaySize(displayId, width, height, externalWidth, externalHeight);
 }
 
 static void android_server_InputManager_nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
@@ -1291,7 +1297,7 @@
             (void*) android_server_InputManager_nativeInit },
     { "nativeStart", "()V",
             (void*) android_server_InputManager_nativeStart },
-    { "nativeSetDisplaySize", "(III)V",
+    { "nativeSetDisplaySize", "(IIIII)V",
             (void*) android_server_InputManager_nativeSetDisplaySize },
     { "nativeSetDisplayOrientation", "(II)V",
             (void*) android_server_InputManager_nativeSetDisplayOrientation },
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 13cd9ec..d94f369 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
@@ -76,6 +76,9 @@
     public void getDisplaySize(Point arg0) throws RemoteException {
     }
 
+    public void getRealDisplaySize(Point arg0) throws RemoteException {
+    }
+
     // ---- unused implementation of IWindowManager ----
 
     public boolean canStatusBarHide() throws RemoteException {