Merge "Report the external display size to the input reader."
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 35a40fc..54e02a7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -825,8 +825,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();
@@ -980,8 +982,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 1d41ce0..96f6e2f 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;
@@ -360,8 +361,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
@@ -371,6 +373,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 {