Merge "Make display manager tell input system about viewports." into jb-mr1-dev
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 6d63998..513dc13 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -203,34 +203,18 @@
 
 // --- InputReaderConfiguration ---
 
-bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external,
-        int32_t* width, int32_t* height, int32_t* orientation) const {
-    if (displayId == 0) {
-        const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
-        if (info.width > 0 && info.height > 0) {
-            if (width) {
-                *width = info.width;
-            }
-            if (height) {
-                *height = info.height;
-            }
-            if (orientation) {
-                *orientation = info.orientation;
-            }
-            return true;
-        }
+bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
+    const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
+    if (viewport.displayId >= 0) {
+        *outViewport = viewport;
+        return true;
     }
     return false;
 }
 
-void InputReaderConfiguration::setDisplayInfo(int32_t displayId, bool external,
-        int32_t width, int32_t height, int32_t orientation) {
-    if (displayId == 0) {
-        DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
-        info.width = width;
-        info.height = height;
-        info.orientation = orientation;
-    }
+void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
+    DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
+    v = viewport;
 }
 
 
@@ -2001,9 +1985,11 @@
     }
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
-            if (!config->getDisplayInfo(mParameters.associatedDisplayId,
-                        false /*external*/, NULL, NULL, &mOrientation)) {
+        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
+            DisplayViewport v;
+            if (config->getDisplayInfo(false /*external*/, &v)) {
+                mOrientation = v.orientation;
+            } else {
                 mOrientation = DISPLAY_ORIENTATION_0;
             }
         } else {
@@ -2017,16 +2003,16 @@
     getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = -1;
+    mParameters.hasAssociatedDisplay = false;
     if (mParameters.orientationAware) {
-        mParameters.associatedDisplayId = 0;
+        mParameters.hasAssociatedDisplay = true;
     }
 }
 
 void KeyboardInputMapper::dumpParameters(String8& dump) {
     dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
-            mParameters.associatedDisplayId);
+    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+            toString(mParameters.hasAssociatedDisplay));
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
@@ -2086,7 +2072,7 @@
 
     if (down) {
         // Rotate key codes according to orientation if needed.
-        if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
+        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
             keyCode = rotateKeyCode(keyCode, mOrientation);
         }
 
@@ -2317,9 +2303,11 @@
     }
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
-            if (!config->getDisplayInfo(mParameters.associatedDisplayId,
-                        false /*external*/, NULL, NULL, &mOrientation)) {
+        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
+            DisplayViewport v;
+            if (config->getDisplayInfo(false /*external*/, &v)) {
+                mOrientation = v.orientation;
+            } else {
                 mOrientation = DISPLAY_ORIENTATION_0;
             }
         } else {
@@ -2344,16 +2332,16 @@
     getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = -1;
+    mParameters.hasAssociatedDisplay = false;
     if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
-        mParameters.associatedDisplayId = 0;
+        mParameters.hasAssociatedDisplay = true;
     }
 }
 
 void CursorInputMapper::dumpParameters(String8& dump) {
     dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
-            mParameters.associatedDisplayId);
+    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+            toString(mParameters.hasAssociatedDisplay));
 
     switch (mParameters.mode) {
     case Parameters::MODE_POINTER:
@@ -2420,7 +2408,7 @@
     bool moved = deltaX != 0 || deltaY != 0;
 
     // Rotate delta according to orientation if needed.
-    if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
+    if (mParameters.orientationAware && mParameters.hasAssociatedDisplay
             && (deltaX != 0.0f || deltaY != 0.0f)) {
         rotateDelta(mOrientation, &deltaX, &deltaY);
     }
@@ -2782,15 +2770,15 @@
     getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = -1;
+    mParameters.hasAssociatedDisplay = false;
     mParameters.associatedDisplayIsExternal = false;
     if (mParameters.orientationAware
             || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
             || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+        mParameters.hasAssociatedDisplay = true;
         mParameters.associatedDisplayIsExternal =
                 mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
                         && getDevice()->isExternal();
-        mParameters.associatedDisplayId = 0;
     }
 }
 
@@ -2822,8 +2810,9 @@
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(INDENT4 "AssociatedDisplay: id=%d, isExternal=%s\n",
-            mParameters.associatedDisplayId, toString(mParameters.associatedDisplayIsExternal));
+    dump.appendFormat(INDENT4 "AssociatedDisplay: present=%s, isExternal=%s\n",
+            toString(mParameters.hasAssociatedDisplay),
+            toString(mParameters.associatedDisplayIsExternal));
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
@@ -2861,7 +2850,7 @@
             mSource |= AINPUT_SOURCE_STYLUS;
         }
     } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-            && mParameters.associatedDisplayId >= 0) {
+            && mParameters.hasAssociatedDisplay) {
         mSource = AINPUT_SOURCE_TOUCHSCREEN;
         mDeviceMode = DEVICE_MODE_DIRECT;
         if (hasStylus()) {
@@ -2881,15 +2870,13 @@
     }
 
     // Get associated display dimensions.
-    if (mParameters.associatedDisplayId >= 0) {
-        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId,
-                mParameters.associatedDisplayIsExternal,
-                &mAssociatedDisplayWidth, &mAssociatedDisplayHeight,
-                &mAssociatedDisplayOrientation)) {
+    if (mParameters.hasAssociatedDisplay) {
+        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal,
+                &mAssociatedDisplayViewport)) {
             ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
-                    "display %d.  The device will be inoperable until the display size "
+                    "display.  The device will be inoperable until the display size "
                     "becomes available.",
-                    getDeviceName().string(), mParameters.associatedDisplayId);
+                    getDeviceName().string());
             mDeviceMode = DEVICE_MODE_DISABLED;
             return;
         }
@@ -2898,10 +2885,16 @@
     // Configure dimensions.
     int32_t width, height, orientation;
     if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
-        width = mAssociatedDisplayWidth;
-        height = mAssociatedDisplayHeight;
+        width = mAssociatedDisplayViewport.logicalRight - mAssociatedDisplayViewport.logicalLeft;
+        height = mAssociatedDisplayViewport.logicalBottom - mAssociatedDisplayViewport.logicalTop;
+        if (mAssociatedDisplayViewport.orientation == DISPLAY_ORIENTATION_90
+                || mAssociatedDisplayViewport.orientation == DISPLAY_ORIENTATION_270) {
+            int32_t temp = height;
+            height = width;
+            width = temp;
+        }
         orientation = mParameters.orientationAware ?
-                mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0;
+                mAssociatedDisplayViewport.orientation : DISPLAY_ORIENTATION_0;
     } else {
         width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
         height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
@@ -3163,8 +3156,7 @@
             int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
             int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
             float rawDiagonal = hypotf(rawWidth, rawHeight);
-            float displayDiagonal = hypotf(mAssociatedDisplayWidth,
-                    mAssociatedDisplayHeight);
+            float displayDiagonal = hypotf(width, height);
 
             // Scale movements such that one whole swipe of the touch pad covers a
             // given area relative to the diagonal size of the display when no acceleration
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 6c06986..e345a5fb 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -24,7 +24,6 @@
 #include <androidfw/Input.h>
 #include <androidfw/VelocityControl.h>
 #include <androidfw/VelocityTracker.h>
-#include <ui/DisplayInfo.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
@@ -48,6 +47,45 @@
 class InputDevice;
 class InputMapper;
 
+/*
+ * Describes how coordinates are mapped on a physical display.
+ * See com.android.server.display.DisplayViewport.
+ */
+struct DisplayViewport {
+    int32_t displayId; // -1 if invalid
+    int32_t orientation;
+    int32_t logicalLeft;
+    int32_t logicalTop;
+    int32_t logicalRight;
+    int32_t logicalBottom;
+    int32_t physicalLeft;
+    int32_t physicalTop;
+    int32_t physicalRight;
+    int32_t physicalBottom;
+
+    DisplayViewport() :
+            displayId(-1), orientation(DISPLAY_ORIENTATION_0),
+            logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
+            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0) {
+    }
+
+    bool operator==(const DisplayViewport& other) const {
+        return displayId == other.displayId
+                && orientation == other.orientation
+                && logicalLeft == other.logicalLeft
+                && logicalTop == other.logicalTop
+                && logicalRight == other.logicalRight
+                && logicalBottom == other.logicalBottom
+                && physicalLeft == other.physicalLeft
+                && physicalTop == other.physicalTop
+                && physicalRight == other.physicalRight
+                && physicalBottom == other.physicalBottom;
+    }
+
+    bool operator!=(const DisplayViewport& other) const {
+        return !(*this == other);
+    }
+};
 
 /*
  * Input reader configuration.
@@ -180,25 +218,12 @@
             pointerGestureZoomSpeedRatio(0.3f),
             showTouches(false) { }
 
-    bool getDisplayInfo(int32_t displayId, bool external,
-            int32_t* width, int32_t* height, int32_t* orientation) const;
-
-    void setDisplayInfo(int32_t displayId, bool external,
-            int32_t width, int32_t height, int32_t orientation);
+    bool getDisplayInfo(bool external, DisplayViewport* outViewport) const;
+    void setDisplayInfo(bool external, const DisplayViewport& viewport);
 
 private:
-    struct DisplayInfo {
-        int32_t width;
-        int32_t height;
-        int32_t orientation;
-
-        DisplayInfo() :
-            width(-1), height(-1), orientation(DISPLAY_ORIENTATION_0) {
-        }
-    };
-
-    DisplayInfo mInternalDisplay;
-    DisplayInfo mExternalDisplay;
+    DisplayViewport mInternalDisplay;
+    DisplayViewport mExternalDisplay;
 };
 
 
@@ -992,7 +1017,7 @@
 
     // Immutable configuration parameters.
     struct Parameters {
-        int32_t associatedDisplayId;
+        bool hasAssociatedDisplay;
         bool orientationAware;
     } mParameters;
 
@@ -1042,7 +1067,7 @@
         };
 
         Mode mode;
-        int32_t associatedDisplayId;
+        bool hasAssociatedDisplay;
         bool orientationAware;
     } mParameters;
 
@@ -1143,7 +1168,7 @@
         };
 
         DeviceType deviceType;
-        int32_t associatedDisplayId;
+        bool hasAssociatedDisplay;
         bool associatedDisplayIsExternal;
         bool orientationAware;
 
@@ -1277,10 +1302,8 @@
     int32_t mSurfaceWidth;
     int32_t mSurfaceHeight;
 
-    // The associated display orientation and width and height set by configureSurface().
-    int32_t mAssociatedDisplayOrientation;
-    int32_t mAssociatedDisplayWidth;
-    int32_t mAssociatedDisplayHeight;
+    // The associated display viewport set by configureSurface().
+    DisplayViewport mAssociatedDisplayViewport;
 
     // Translation and scaling factors, orientation-independent.
     float mXScale;
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index fc828a6..9af521b 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -307,9 +307,17 @@
     }
 }
 
-void PointerController::setDisplaySize(int32_t width, int32_t height) {
+void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
     AutoMutex _l(mLock);
 
+    // Adjust to use the display's unrotated coordinate frame.
+    if (orientation == DISPLAY_ORIENTATION_90
+            || orientation == DISPLAY_ORIENTATION_270) {
+        int32_t temp = height;
+        height = width;
+        width = temp;
+    }
+
     if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
         mLocked.displayWidth = width;
         mLocked.displayHeight = height;
@@ -324,12 +332,7 @@
         }
 
         fadeOutAndReleaseAllSpotsLocked();
-        updatePointerLocked();
     }
-}
-
-void PointerController::setDisplayOrientation(int32_t orientation) {
-    AutoMutex _l(mLock);
 
     if (mLocked.displayOrientation != orientation) {
         // Apply offsets to convert from the pixel top-left corner position to the pixel center.
@@ -380,9 +383,9 @@
         mLocked.pointerX = x - 0.5f;
         mLocked.pointerY = y - 0.5f;
         mLocked.displayOrientation = orientation;
-
-        updatePointerLocked();
     }
+
+    updatePointerLocked();
 }
 
 void PointerController::setPointerIcon(const SpriteIcon& icon) {
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index 4c307c4..fd68b61 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -170,8 +170,7 @@
             const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
     virtual void clearSpots();
 
-    void setDisplaySize(int32_t width, int32_t height);
-    void setDisplayOrientation(int32_t orientation);
+    void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
     void setPointerIcon(const SpriteIcon& icon);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
 
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index abda10b..03516af 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -138,8 +138,21 @@
 
     void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) {
         // Set the size of both the internal and external display at the same time.
-        mConfig.setDisplayInfo(displayId, false /*external*/, width, height, orientation);
-        mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation);
+        bool isRotated = (orientation == DISPLAY_ORIENTATION_90
+                || orientation == DISPLAY_ORIENTATION_270);
+        DisplayViewport v;
+        v.displayId = displayId;
+        v.orientation = orientation;
+        v.logicalLeft = 0;
+        v.logicalTop = 0;
+        v.logicalRight = isRotated ? height : width;
+        v.logicalBottom = isRotated ? width : height;
+        v.physicalLeft = 0;
+        v.physicalTop = 0;
+        v.physicalRight = isRotated ? height : width;
+        v.physicalBottom = isRotated ? width : height;
+        mConfig.setDisplayInfo(false /*external*/, v);
+        mConfig.setDisplayInfo(true /*external*/, v);
     }
 
     void addExcludedDeviceName(const String8& deviceName) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1aad9b3..c28afb2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -304,6 +304,7 @@
 
             ActivityManagerService.self().setWindowManager(wm);
             display.setWindowManager(wm);
+            display.setInputManager(inputManager);
 
             // Skip Bluetooth if we have an emulator kernel
             // TODO: Use a more reliable check to see if this product should
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index 995c553..8eeefb4 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -132,14 +132,17 @@
                 || mCurrentDisplayRect == null
                 || !mCurrentDisplayRect.equals(displayRect)) {
             mCurrentOrientation = orientation;
+
             if (mCurrentLayerStackRect == null) {
                 mCurrentLayerStackRect = new Rect();
             }
             mCurrentLayerStackRect.set(layerStackRect);
+
             if (mCurrentDisplayRect == null) {
                 mCurrentDisplayRect = new Rect();
             }
             mCurrentDisplayRect.set(displayRect);
+
             Surface.setDisplayProjection(mDisplayToken,
                     orientation, layerStackRect, displayRect);
         }
@@ -156,6 +159,26 @@
     }
 
     /**
+     * Populates the specified viewport object with orientation,
+     * physical and logical rects based on the display's current projection.
+     */
+    public final void populateViewportLocked(DisplayViewport viewport) {
+        viewport.orientation = mCurrentOrientation;
+
+        if (mCurrentLayerStackRect != null) {
+            viewport.logicalFrame.set(mCurrentLayerStackRect);
+        } else {
+            viewport.logicalFrame.setEmpty();
+        }
+
+        if (mCurrentDisplayRect != null) {
+            viewport.physicalFrame.set(mCurrentDisplayRect);
+        } else {
+            viewport.physicalFrame.setEmpty();
+        }
+    }
+
+    /**
      * Dumps the local state of the display device.
      * Does not need to dump the display device info because that is already dumped elsewhere.
      */
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index c90a1c6..7c57694 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -43,6 +43,21 @@
     public static final int FLAG_SUPPORTS_ROTATION = 1 << 2;
 
     /**
+     * Touch attachment: Display does not receive touch.
+     */
+    public static final int TOUCH_NONE = 0;
+
+    /**
+     * Touch attachment: Touch input is via the internal interface.
+     */
+    public static final int TOUCH_INTERNAL = 1;
+
+    /**
+     * Touch attachment: Touch input is via an external interface, such as USB.
+     */
+    public static final int TOUCH_EXTERNAL = 2;
+
+    /**
      * Gets the name of the display device, which may be derived from
      * EDID or other sources.  The name may be displayed to the user.
      */
@@ -90,6 +105,11 @@
      */
     public int flags;
 
+    /**
+     * The touch attachment, per {@link DisplayViewport#touch}.
+     */
+    public int touch;
+
     public void setAssumedDensityForExternalDisplay(int width, int height) {
         densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
         // Technically, these values should be smaller than the apparent density
@@ -112,7 +132,8 @@
                 && densityDpi == other.densityDpi
                 && xDpi == other.xDpi
                 && yDpi == other.yDpi
-                && flags == other.flags;
+                && flags == other.flags
+                && touch == other.touch;
     }
 
     @Override
@@ -129,6 +150,7 @@
         xDpi = other.xDpi;
         yDpi = other.yDpi;
         flags = other.flags;
+        touch = other.touch;
     }
 
     // For debugging purposes
@@ -136,7 +158,20 @@
     public String toString() {
         return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, "
                 + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"
-                + flagsToString(flags) + "}";
+                + ", touch " + touchToString(touch) + flagsToString(flags) + "}";
+    }
+
+    private static String touchToString(int touch) {
+        switch (touch) {
+            case TOUCH_NONE:
+                return "NONE";
+            case TOUCH_INTERNAL:
+                return "INTERNAL";
+            case TOUCH_EXTERNAL:
+                return "EXTERNAL";
+            default:
+                return Integer.toString(touch);
+        }
     }
 
     private static String flagsToString(int flags) {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 41a0c09..e11d454 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -96,6 +96,7 @@
     private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
     private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
     private static final int MSG_REQUEST_TRAVERSAL = 4;
+    private static final int MSG_UPDATE_VIEWPORT = 5;
 
     private final Context mContext;
     private final boolean mHeadless;
@@ -103,6 +104,7 @@
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
     private WindowManagerFuncs mWindowManagerFuncs;
+    private InputManagerFuncs mInputManagerFuncs;
 
     // The synchronization root for the display manager.
     // This lock guards most of the display manager's state.
@@ -141,6 +143,11 @@
     // The Wifi display adapter, or null if not registered.
     private WifiDisplayAdapter mWifiDisplayAdapter;
 
+    // Viewports of the default display and the display that should receive touch
+    // input from an external source.  Used by the input system.
+    private final DisplayViewport mDefaultViewport = new DisplayViewport();
+    private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+
     // Temporary callback list, used when sending display events to applications.
     // May be used outside of the lock but only on the handler thread.
     private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
@@ -148,6 +155,11 @@
     // Temporary display info, used for comparing display configurations.
     private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
 
+    // Temporary viewports, used when sending new viewport information to the
+    // input system.  May be used outside of the lock but only on the handler thread.
+    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
+    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
+
     public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
         mContext = context;
         mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
@@ -183,7 +195,7 @@
     }
 
     /**
-     * Called during initialization to associated the display manager with the
+     * Called during initialization to associate the display manager with the
      * window manager.
      */
     public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
@@ -194,6 +206,17 @@
     }
 
     /**
+     * Called during initialization to associate the display manager with the
+     * input manager.
+     */
+    public void setInputManager(InputManagerFuncs inputManagerFuncs) {
+        synchronized (mSyncRoot) {
+            mInputManagerFuncs = inputManagerFuncs;
+            scheduleTraversalLocked();
+        }
+    }
+
+    /**
      * Called when the system is ready to go.
      */
     public void systemReady(boolean safeMode, boolean onlyCore) {
@@ -487,7 +510,7 @@
         final int displayId = assignDisplayIdLocked(isDefault);
         final int layerStack = assignLayerStackLocked(displayId);
 
-        LogicalDisplay display = new LogicalDisplay(layerStack, device);
+        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
         display.updateLocked(mDisplayDevices);
         if (!display.isValidLocked()) {
             // This should never happen currently.
@@ -548,6 +571,10 @@
         }
         mRemovedDisplayDevices.clear();
 
+        // Clear all viewports before configuring displays so that we can keep
+        // track of which ones we have configured.
+        clearViewportsLocked();
+
         // Configure each display device.
         final int count = mDisplayDevices.size();
         for (int i = 0; i < count; i++) {
@@ -555,6 +582,11 @@
             configureDisplayInTransactionLocked(device);
             device.performTraversalInTransactionLocked();
         }
+
+        // Tell the input system about these new viewports.
+        if (mInputManagerFuncs != null) {
+            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
+        }
     }
 
     /**
@@ -577,7 +609,11 @@
                 scheduleTraversalLocked();
             }
         }
+    }
 
+    private void clearViewportsLocked() {
+        mDefaultViewport.valid = false;
+        mExternalTouchViewport.valid = false;
     }
 
     private void configureDisplayInTransactionLocked(DisplayDevice device) {
@@ -593,11 +629,30 @@
         // Apply the logical display configuration to the display device.
         if (display == null) {
             // TODO: no logical display for the device, blank it
-            Slog.d(TAG, "Missing logical display to use for physical display device: "
+            Slog.w(TAG, "Missing logical display to use for physical display device: "
                     + device.getDisplayDeviceInfoLocked());
+            return;
         } else {
             display.configureDisplayInTransactionLocked(device);
         }
+
+        // Update the viewports if needed.
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        if (!mDefaultViewport.valid
+                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+            setViewportLocked(mDefaultViewport, display, device);
+        }
+        if (!mExternalTouchViewport.valid
+                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
+            setViewportLocked(mExternalTouchViewport, display, device);
+        }
+    }
+
+    private static void setViewportLocked(DisplayViewport viewport,
+            LogicalDisplay display, DisplayDevice device) {
+        viewport.valid = true;
+        viewport.displayId = display.getDisplayIdLocked();
+        device.populateViewportLocked(viewport);
     }
 
     private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
@@ -690,6 +745,10 @@
                 pw.println("  Display " + displayId + ":");
                 display.dumpLocked(ipw);
             }
+
+            pw.println();
+            pw.println("Default viewport: " + mDefaultViewport);
+            pw.println("External touch viewport: " + mExternalTouchViewport);
         }
     }
 
@@ -714,6 +773,18 @@
         void requestTraversal();
     }
 
+    /**
+     * Private interface to the input manager.
+     */
+    public interface InputManagerFuncs {
+        /**
+         * Sets information about the displays as needed by the input system.
+         * The input system should copy this information if required.
+         */
+        void setDisplayViewports(DisplayViewport defaultViewport,
+                DisplayViewport externalTouchViewport);
+    }
+
     private final class DisplayManagerHandler extends Handler {
         public DisplayManagerHandler(Looper looper) {
             super(looper, null, true /*async*/);
@@ -737,6 +808,16 @@
                 case MSG_REQUEST_TRAVERSAL:
                     mWindowManagerFuncs.requestTraversal();
                     break;
+
+                case MSG_UPDATE_VIEWPORT: {
+                    synchronized (mSyncRoot) {
+                        mTempDefaultViewport.copyFrom(mDefaultViewport);
+                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
+                    }
+                    mInputManagerFuncs.setDisplayViewports(
+                            mTempDefaultViewport, mTempExternalTouchViewport);
+                    break;
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/display/DisplayViewport.java b/services/java/com/android/server/display/DisplayViewport.java
new file mode 100644
index 0000000..ed4016d
--- /dev/null
+++ b/services/java/com/android/server/display/DisplayViewport.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.graphics.Rect;
+
+/**
+ * Describes how the pixels of physical display device reflects the content of
+ * a logical display.
+ * <p>
+ * This information is used by the input system to translate touch input from
+ * physical display coordinates into logical display coordinates.
+ * </p>
+ */
+public final class DisplayViewport {
+    // True if this viewport is valid.
+    public boolean valid;
+
+    // The logical display id.
+    public int displayId;
+
+    // The rotation applied to the physical coordinate system.
+    public int orientation;
+
+    // The portion of the logical display that are presented on this physical display.
+    public final Rect logicalFrame = new Rect();
+
+    // The portion of the (rotated) physical display that shows the logical display contents.
+    // The relation between logical and physical frame defines how the coordinate system
+    // should be scaled or translated after rotation.
+    public final Rect physicalFrame = new Rect();
+
+    public void copyFrom(DisplayViewport viewport) {
+        valid = viewport.valid;
+        displayId = viewport.displayId;
+        orientation = viewport.orientation;
+        logicalFrame.set(viewport.logicalFrame);
+        physicalFrame.set(viewport.physicalFrame);
+    }
+
+    // For debugging purposes.
+    @Override
+    public String toString() {
+        return "DisplayViewport{valid=" + valid
+                + ", displayId=" + displayId
+                + ", orientation=" + orientation
+                + ", logicalFrame=" + logicalFrame
+                + ", physicalFrame=" + physicalFrame
+                + "}";
+    }
+}
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index 3aaacf1..7629db6 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -61,6 +61,7 @@
                 mInfo.yDpi = 160;
                 mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                         | DisplayDeviceInfo.FLAG_SECURE;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
             }
             return mInfo;
         }
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 4962753..80c860b 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -129,10 +129,12 @@
                     mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
                     mInfo.xDpi = mPhys.xDpi;
                     mInfo.yDpi = mPhys.yDpi;
+                    mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
                 } else {
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_hdmi_display_name);
                     mInfo.flags = DisplayDeviceInfo.FLAG_SECURE;
+                    mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
                     mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
                 }
             }
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index e0f63dd..2e75260 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -54,6 +54,7 @@
 final class LogicalDisplay {
     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
 
+    private final int mDisplayId;
     private final int mLayerStack;
     private DisplayInfo mOverrideDisplayInfo; // set by the window manager
     private DisplayInfo mInfo;
@@ -70,12 +71,22 @@
     private final Rect mTempLayerStackRect = new Rect();
     private final Rect mTempDisplayRect = new Rect();
 
-    public LogicalDisplay(int layerStack, DisplayDevice primaryDisplayDevice) {
+    public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
+        mDisplayId = displayId;
         mLayerStack = layerStack;
         mPrimaryDisplayDevice = primaryDisplayDevice;
     }
 
     /**
+     * Gets the logical display id of this logical display.
+     *
+     * @return The logical display id.
+     */
+    public int getDisplayIdLocked() {
+        return mDisplayId;
+    }
+
+    /**
      * Gets the primary display device associated with this logical display.
      *
      * @return The primary display device.
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index e2d3059..9b0e534 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -228,6 +228,7 @@
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
                 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
             }
             return mInfo;
         }
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index abf0d27..ca500c0 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -324,6 +324,7 @@
                 mInfo.height = mHeight;
                 mInfo.refreshRate = mRefreshRate;
                 mInfo.flags = mFlags;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
                 mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
             }
             return mInfo;
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index fd4f5fc..95655a5 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -19,6 +19,8 @@
 import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
 import com.android.server.Watchdog;
+import com.android.server.display.DisplayManagerService;
+import com.android.server.display.DisplayViewport;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -90,7 +92,8 @@
 /*
  * Wraps the C++ InputManager and provides its callbacks.
  */
-public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
+public class InputManagerService extends IInputManager.Stub
+        implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
@@ -143,11 +146,11 @@
     private static native int nativeInit(InputManagerService service,
             Context context, MessageQueue messageQueue);
     private static native void nativeStart(int ptr);
-    private static native void nativeSetDisplaySize(int ptr, int displayId,
-            int width, int height, int externalWidth, int externalHeight);
-    private static native void nativeSetDisplayOrientation(int ptr, int displayId,
-            int rotation, int externalRotation);
-    
+    private static native void nativeSetDisplayViewport(int ptr, boolean external,
+            int displayId, int rotation,
+            int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
+            int physicalLeft, int physicalTop, int physicalRight, int physicalBottom);
+
     private static native int nativeGetScanCodeState(int ptr,
             int deviceId, int sourceMask, int scanCode);
     private static native int nativeGetKeyCodeState(int ptr,
@@ -282,28 +285,27 @@
         nativeReloadDeviceAliases(mPtr);
     }
 
-    public void setDisplaySize(int displayId, int width, int height) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException("Invalid display id or dimensions.");
+    @Override
+    public void setDisplayViewports(DisplayViewport defaultViewport,
+            DisplayViewport externalTouchViewport) {
+        if (defaultViewport.valid) {
+            setDisplayViewport(false, defaultViewport);
         }
-        
-        if (DEBUG) {
-            Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+
+        if (externalTouchViewport.valid) {
+            setDisplayViewport(true, externalTouchViewport);
+        } else if (defaultViewport.valid) {
+            setDisplayViewport(true, defaultViewport);
         }
-        // FIXME: external size is deprecated
-        nativeSetDisplaySize(mPtr, displayId, width, height, 1280, 720);
     }
 
-    public void setDisplayOrientation(int displayId, int rotation) {
-        if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) {
-            throw new IllegalArgumentException("Invalid rotation.");
-        }
-        
-        if (DEBUG) {
-            Slog.d(TAG, "Setting display #" + displayId + " orientation to rotation " + rotation);
-        }
-        // FIXME: external rotation is deprecated
-        nativeSetDisplayOrientation(mPtr, displayId, rotation, Surface.ROTATION_0);
+    private void setDisplayViewport(boolean external, DisplayViewport viewport) {
+        nativeSetDisplayViewport(mPtr, external,
+                viewport.displayId, viewport.orientation,
+                viewport.logicalFrame.left, viewport.logicalFrame.top,
+                viewport.logicalFrame.right, viewport.logicalFrame.bottom,
+                viewport.physicalFrame.left, viewport.physicalFrame.top,
+                viewport.physicalFrame.right, viewport.physicalFrame.bottom);
     }
 
     /**
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 18e793d..cdca8bc 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5947,7 +5947,6 @@
         mWaitingForConfig = true;
         getDefaultDisplayContent().layoutNeeded = true;
         startFreezingDisplayLocked(inTransaction);
-        mInputManager.setDisplayOrientation(0, rotation);
 
         // We need to update our screen size information to match the new
         // rotation.  Note that this is redundant with the later call to
@@ -7121,10 +7120,6 @@
                 displayInfo.appWidth, displayInfo.appHeight);
 
             final DisplayContent displayContent = getDefaultDisplayContent();
-            mInputManager.setDisplaySize(displayContent.getDisplayId(),
-                    displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight);
-            mInputManager.setDisplayOrientation(displayContent.getDisplayId(),
-                    mDefaultDisplay.getRotation());
             mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mInitialDisplayWidth,
                     displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
         }
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 495d4ab..5e36bf8 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -164,9 +164,7 @@
 
     void dump(String8& dump);
 
-    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, int32_t externalOrientation);
+    void setDisplayViewport(bool external, const DisplayViewport& viewport);
 
     status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
             const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
@@ -223,10 +221,8 @@
     Mutex mLock;
     struct Locked {
         // Display size information.
-        int32_t displayWidth, displayHeight; // -1 when not initialized
-        int32_t displayOrientation;
-        int32_t displayExternalWidth, displayExternalHeight; // -1 when not initialized
-        int32_t displayExternalOrientation;
+        DisplayViewport internalViewport;
+        DisplayViewport externalViewport;
 
         // System UI visibility.
         int32_t systemUiVisibility;
@@ -274,13 +270,6 @@
 
     {
         AutoMutex _l(mLock);
-        mLocked.displayWidth = -1;
-        mLocked.displayHeight = -1;
-        mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
-        mLocked.displayExternalWidth = -1;
-        mLocked.displayExternalHeight = -1;
-        mLocked.displayExternalOrientation = DISPLAY_ORIENTATION_0;
-
         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
         mLocked.pointerSpeed = 0;
         mLocked.pointerGesturesEnabled = true;
@@ -316,57 +305,26 @@
     return false;
 }
 
-void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height,
-        int32_t externalWidth, int32_t externalHeight) {
+void NativeInputManager::setDisplayViewport(bool external, const DisplayViewport& viewport) {
     bool changed = false;
-    if (displayId == 0) {
+    {
         AutoMutex _l(mLock);
 
-        if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
+        DisplayViewport& v = external ? mLocked.externalViewport : mLocked.internalViewport;
+        if (v != viewport) {
             changed = true;
-            mLocked.displayWidth = width;
-            mLocked.displayHeight = height;
+            v = viewport;
 
-            sp<PointerController> controller = mLocked.pointerController.promote();
-            if (controller != NULL) {
-                controller->setDisplaySize(width, height);
+            if (!external) {
+                sp<PointerController> controller = mLocked.pointerController.promote();
+                if (controller != NULL) {
+                    controller->setDisplayViewport(
+                            viewport.logicalRight - viewport.logicalLeft,
+                            viewport.logicalBottom - viewport.logicalTop,
+                            viewport.orientation);
+                }
             }
         }
-
-        if (mLocked.displayExternalWidth != externalWidth
-                || mLocked.displayExternalHeight != externalHeight) {
-            changed = true;
-            mLocked.displayExternalWidth = externalWidth;
-            mLocked.displayExternalHeight = externalHeight;
-        }
-    }
-
-    if (changed) {
-        mInputManager->getReader()->requestRefreshConfiguration(
-                InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    }
-}
-
-void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation,
-        int32_t externalOrientation) {
-    bool changed = false;
-    if (displayId == 0) {
-        AutoMutex _l(mLock);
-
-        if (mLocked.displayOrientation != orientation) {
-            changed = true;
-            mLocked.displayOrientation = orientation;
-
-            sp<PointerController> controller = mLocked.pointerController.promote();
-            if (controller != NULL) {
-                controller->setDisplayOrientation(orientation);
-            }
-        }
-
-        if (mLocked.displayExternalOrientation != externalOrientation) {
-            changed = true;
-            mLocked.displayExternalOrientation = externalOrientation;
-        }
     }
 
     if (changed) {
@@ -448,11 +406,8 @@
 
         outConfig->showTouches = mLocked.showTouches;
 
-        outConfig->setDisplayInfo(0, false /*external*/,
-                mLocked.displayWidth, mLocked.displayHeight, mLocked.displayOrientation);
-        outConfig->setDisplayInfo(0, true /*external*/,
-                mLocked.displayExternalWidth, mLocked.displayExternalHeight,
-                mLocked.displayExternalOrientation);
+        outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
+        outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
     } // release lock
 }
 
@@ -466,8 +421,11 @@
         controller = new PointerController(this, mLooper, mLocked.spriteController);
         mLocked.pointerController = controller;
 
-        controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);
-        controller->setDisplayOrientation(mLocked.displayOrientation);
+        DisplayViewport& v = mLocked.internalViewport;
+        controller->setDisplayViewport(
+                v.logicalRight - v.logicalLeft,
+                v.logicalBottom - v.logicalTop,
+                v.orientation);
 
         JNIEnv* env = jniEnv();
         jobject pointerIconObj = env->CallObjectMethod(mServiceObj,
@@ -1032,22 +990,24 @@
     }
 }
 
-static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, jint ptr,
-        jint displayId, jint width, jint height, jint externalWidth, jint externalHeight) {
+static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jint ptr, jboolean external,
+        jint displayId, jint orientation,
+        jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom,
+        jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
-    // XXX we could get this from the SurfaceFlinger directly instead of requiring it
-    // 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
-    im->setDisplaySize(displayId, width, height, externalWidth, externalHeight);
-}
-
-static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
-        jint ptr, jint displayId, jint orientation, jint externalOrientation) {
-    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-
-    im->setDisplayOrientation(displayId, orientation, externalOrientation);
+    DisplayViewport v;
+    v.displayId = displayId;
+    v.orientation = orientation;
+    v.logicalLeft = logicalLeft;
+    v.logicalTop = logicalTop;
+    v.logicalRight = logicalRight;
+    v.logicalBottom = logicalBottom;
+    v.physicalLeft = physicalLeft;
+    v.physicalTop = physicalTop;
+    v.physicalRight = physicalRight;
+    v.physicalBottom = physicalBottom;
+    im->setDisplayViewport(external, v);
 }
 
 static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz,
@@ -1328,10 +1288,8 @@
             (void*) nativeInit },
     { "nativeStart", "(I)V",
             (void*) nativeStart },
-    { "nativeSetDisplaySize", "(IIIIII)V",
-            (void*) nativeSetDisplaySize },
-    { "nativeSetDisplayOrientation", "(IIII)V",
-            (void*) nativeSetDisplayOrientation },
+    { "nativeSetDisplayViewport", "(IZIIIIIIIIII)V",
+            (void*) nativeSetDisplayViewport },
     { "nativeGetScanCodeState", "(IIII)I",
             (void*) nativeGetScanCodeState },
     { "nativeGetKeyCodeState", "(IIII)I",