Merge "Reducing the click delay while screen magnification is enabled." into jb-mr1-dev
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 216344d..561e33e 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -36,6 +36,7 @@
 import android.os.PowerManager;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -696,12 +697,12 @@
      */
     public void setAirplaneMode(Context context, boolean enableAM) {
         //set the airplane mode
-        Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+        Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
                 enableAM ? 1 : 0);
         // Post the intent
         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         intent.putExtra("state", enableAM);
-        context.sendBroadcast(intent);
+        context.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 
     protected static String convertToQuotedString(String string) {
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index bf188d3..7928822 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -59,8 +59,8 @@
         wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "CMWakeLock");
         wl.acquire();
         // Each test case will start with cellular connection
-        if (Settings.System.getInt(getInstrumentation().getContext().getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON) == 1) {
+        if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON) == 1) {
             log("airplane is not disabled, disable it.");
             cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
         }
@@ -84,8 +84,8 @@
         wl.release();
         cmActivity.removeConfiguredNetworksAndDisableWifi();
         // if airplane mode is set, disable it.
-        if (Settings.System.getInt(getInstrumentation().getContext().getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON) == 1) {
+        if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON) == 1) {
             log("disable airplane mode if it is enabled");
             cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
         }
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index b2075ae..af2a944 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -29,6 +29,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -553,7 +554,7 @@
         int state = enable ? 1 : 0;
 
         // Change the system setting
-        Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
                 state);
 
         String timeoutMessage = "Timed out waiting for airplane mode to be " +
@@ -561,8 +562,8 @@
 
         // wait for airplane mode to change state
         int currentWaitTime = 0;
-        while (Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON, -1) != state) {
+        while (Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, -1) != state) {
             timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, DEFAULT_MAX_WAIT_TIME,
                     timeoutMessage);
         }
@@ -570,7 +571,7 @@
         // Post the intent
         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         intent.putExtra("state", true);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 1868d1c..785842f 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -72,6 +72,8 @@
 
     public final long WAIT_TIME_INCR = 5 * 1000;
 
+    private static final String APP_LIB_DIR_PREFIX = "/data/app-lib/";
+
     private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec/";
 
     private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO;
@@ -433,7 +435,7 @@
                     assertEquals(srcPath, appInstallPath);
                     assertEquals(publicSrcPath, appInstallPath);
                     assertStartsWith("Native library should point to shared lib directory",
-                            dataDir.getPath(),
+                            new File(APP_LIB_DIR_PREFIX, info.packageName).getPath(),
                             info.nativeLibraryDir);
                     assertDirOwnerGroupPerms(
                             "Native library directory should be owned by system:system and 0755",
diff --git a/include/androidfw/Input.h b/include/androidfw/Input.h
index 2c91fab..e88835e 100644
--- a/include/androidfw/Input.h
+++ b/include/androidfw/Input.h
@@ -49,6 +49,15 @@
 };
 
 enum {
+    /* Used when a motion event is not associated with any display.
+     * Typically used for non-pointer events. */
+    ADISPLAY_ID_NONE = -1,
+
+    /* The default display id. */
+    ADISPLAY_ID_DEFAULT = 0,
+};
+
+enum {
     /*
      * Indicates that an input device has switches.
      * This input source flag is hidden from the API because switches are only used by the system
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index f374c11..cad6d57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -32,6 +32,7 @@
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.view.LayoutInflater;
@@ -147,7 +148,7 @@
         // TODO: Sets the view to be "awaiting" if not already awaiting
 
         // Change the system setting
-        Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
                                 enabled ? 1 : 0);
 
         // TODO: Update the UI to reflect system setting
@@ -156,7 +157,7 @@
         // Post the intent
         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         intent.putExtra("state", enabled);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
     }
     // NetworkSignalChanged callback
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
index edad370..3c8276d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AirplaneModeController.java
@@ -74,7 +74,7 @@
 
     private boolean getAirplaneMode() {
         ContentResolver cr = mContext.getContentResolver();
-        return 0 != Settings.System.getInt(cr, Settings.System.AIRPLANE_MODE_ON, 0);
+        return 0 != Settings.Global.getInt(cr, Settings.Global.AIRPLANE_MODE_ON, 0);
     }
 
     // TODO: Fix this racy API by adding something better to TelephonyManager or
@@ -82,9 +82,9 @@
     private void unsafe(final boolean enabled) {
         AsyncTask.execute(new Runnable() {
                 public void run() {
-                    Settings.System.putInt(
+                    Settings.Global.putInt(
                             mContext.getContentResolver(),
-                            Settings.System.AIRPLANE_MODE_ON,
+                            Settings.Global.AIRPLANE_MODE_ON,
                             enabled ? 1 : 0);
                     Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 23f27e7..ea7235d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -509,8 +509,8 @@
     }
 
     private void updateAirplaneMode() {
-        mAirplaneMode = (Settings.System.getInt(mContext.getContentResolver(),
-            Settings.System.AIRPLANE_MODE_ON, 0) == 1);
+        mAirplaneMode = (Settings.Global.getInt(mContext.getContentResolver(),
+            Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
     }
 
     private final void updateTelephonySignalStrength() {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 10f45a5..753b864 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -115,7 +115,7 @@
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
         mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
         mContext.getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.System.AIRPLANE_MODE_ON), true,
+                Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                 mAirplaneModeObserver);
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = vibrator != null && vibrator.hasVibrator();
@@ -849,9 +849,9 @@
         // Let the service state callbacks handle the state.
         if (mHasTelephony) return;
 
-        boolean airplaneModeOn = Settings.System.getInt(
+        boolean airplaneModeOn = Settings.Global.getInt(
                 mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON,
+                Settings.Global.AIRPLANE_MODE_ON,
                 0) == 1;
         mAirplaneState = airplaneModeOn ? ToggleAction.State.On : ToggleAction.State.Off;
         mAirplaneModeOn.updateState(mAirplaneState);
@@ -861,9 +861,9 @@
      * Change the airplane mode system setting
      */
     private void changeAirplaneModeSystemSetting(boolean on) {
-        Settings.System.putInt(
+        Settings.Global.putInt(
                 mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON,
+                Settings.Global.AIRPLANE_MODE_ON,
                 on ? 1 : 0);
         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 8604f95..87a6c1b 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -166,6 +166,10 @@
     return true;
 }
 
+static bool isMainDisplay(int32_t displayId) {
+    return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE;
+}
+
 static void dumpRegion(String8& dump, const SkRegion& region) {
     if (region.isEmpty()) {
         dump.append("<empty>");
@@ -423,11 +427,12 @@
                 && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                 && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
                 && mInputTargetWaitApplicationHandle != NULL) {
+            int32_t displayId = motionEntry->displayId;
             int32_t x = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_X));
             int32_t y = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_Y));
-            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
+            sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
             if (touchedWindowHandle != NULL
                     && touchedWindowHandle->inputApplicationHandle
                             != mInputTargetWaitApplicationHandle) {
@@ -444,28 +449,31 @@
     return needWake;
 }
 
-sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
+sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
+        int32_t x, int32_t y) {
     // Traverse windows from front to back to find touched window.
     size_t numWindows = mWindowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
         sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
         const InputWindowInfo* windowInfo = windowHandle->getInfo();
-        int32_t flags = windowInfo->layoutParamsFlags;
+        if (windowInfo->displayId == displayId) {
+            int32_t flags = windowInfo->layoutParamsFlags;
 
-        if (windowInfo->visible) {
-            if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
-                bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
-                        | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
-                if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
-                    // Found window.
-                    return windowHandle;
+            if (windowInfo->visible) {
+                if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
+                    bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
+                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
+                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
+                        // Found window.
+                        return windowHandle;
+                    }
                 }
             }
-        }
 
-        if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
-            // Error window is on top but not visible, so touch is dropped.
-            return NULL;
+            if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
+                // Error window is on top but not visible, so touch is dropped.
+                return NULL;
+            }
         }
     }
     return NULL;
@@ -826,7 +834,10 @@
         return true;
     }
 
-    addMonitoringTargetsLocked(inputTargets);
+    // TODO: support sending secondary display events to input monitors
+    if (isMainDisplay(entry->displayId)) {
+        addMonitoringTargetsLocked(inputTargets);
+    }
 
     // Dispatch the motion.
     if (conflictingPointerActions) {
@@ -1117,6 +1128,7 @@
     //
     bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
 
+    int32_t displayId = entry->displayId;
     int32_t action = entry->action;
     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
 
@@ -1126,9 +1138,10 @@
     sp<InputWindowHandle> newHoverWindowHandle;
 
     bool isSplit = mTouchState.split;
-    bool switchedDevice = mTouchState.deviceId >= 0
+    bool switchedDevice = mTouchState.deviceId >= 0 && mTouchState.displayId >= 0
             && (mTouchState.deviceId != entry->deviceId
-                    || mTouchState.source != entry->source);
+                    || mTouchState.source != entry->source
+                    || mTouchState.displayId != displayId);
     bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
             || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
             || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
@@ -1152,6 +1165,7 @@
         mTempTouchState.down = down;
         mTempTouchState.deviceId = entry->deviceId;
         mTempTouchState.source = entry->source;
+        mTempTouchState.displayId = displayId;
         isSplit = false;
     } else {
         mTempTouchState.copyFrom(mTouchState);
@@ -1174,8 +1188,11 @@
         for (size_t i = 0; i < numWindows; i++) {
             sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
             const InputWindowInfo* windowInfo = windowHandle->getInfo();
-            int32_t flags = windowInfo->layoutParamsFlags;
+            if (windowInfo->displayId != displayId) {
+                continue; // wrong display
+            }
 
+            int32_t flags = windowInfo->layoutParamsFlags;
             if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) {
                 if (topErrorWindowHandle == NULL) {
                     topErrorWindowHandle = windowHandle;
@@ -1300,7 +1317,8 @@
 
             sp<InputWindowHandle> oldTouchedWindowHandle =
                     mTempTouchState.getFirstForegroundWindowHandle();
-            sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(x, y);
+            sp<InputWindowHandle> newTouchedWindowHandle =
+                    findTouchedWindowAtLocked(displayId, x, y);
             if (oldTouchedWindowHandle != newTouchedWindowHandle
                     && newTouchedWindowHandle != NULL) {
 #if DEBUG_FOCUS
@@ -1438,8 +1456,10 @@
         if (foregroundWindowHandle->getInfo()->hasWallpaper) {
             for (size_t i = 0; i < mWindowHandles.size(); i++) {
                 sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
-                if (windowHandle->getInfo()->layoutParamsType
-                        == InputWindowInfo::TYPE_WALLPAPER) {
+                const InputWindowInfo* info = windowHandle->getInfo();
+                if (info->displayId == displayId
+                        && windowHandle->getInfo()->layoutParamsType
+                                == InputWindowInfo::TYPE_WALLPAPER) {
                     mTempTouchState.addOrUpdateWindow(windowHandle,
                             InputTarget::FLAG_WINDOW_IS_OBSCURED
                                     | InputTarget::FLAG_DISPATCH_AS_IS,
@@ -1495,6 +1515,7 @@
                         || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
                     mTouchState.deviceId = entry->deviceId;
                     mTouchState.source = entry->source;
+                    mTouchState.displayId = displayId;
                 }
             } else if (maskedAction == AMOTION_EVENT_ACTION_UP
                     || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
@@ -1610,6 +1631,7 @@
 
 bool InputDispatcher::isWindowObscuredAtPointLocked(
         const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
+    int32_t displayId = windowHandle->getInfo()->displayId;
     size_t numWindows = mWindowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
         sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
@@ -1618,7 +1640,8 @@
         }
 
         const InputWindowInfo* otherInfo = otherHandle->getInfo();
-        if (otherInfo->visible && ! otherInfo->isTrustedOverlay()
+        if (otherInfo->displayId == displayId
+                && otherInfo->visible && !otherInfo->isTrustedOverlay()
                 && otherInfo->frameContainsPoint(x, y)) {
             return true;
         }
@@ -1845,7 +1868,7 @@
         }
         if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
                 && !connection->inputState.isHovering(
-                        motionEntry->deviceId, motionEntry->source)) {
+                        motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
 #if DEBUG_DISPATCH_CYCLE
         ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
                 connection->getInputChannelName());
@@ -2271,6 +2294,7 @@
             originalMotionEntry->xPrecision,
             originalMotionEntry->yPrecision,
             originalMotionEntry->downTime,
+            originalMotionEntry->displayId,
             splitPointerCount, splitPointerProperties, splitPointerCoords);
 
     if (originalMotionEntry->injectionState) {
@@ -2351,7 +2375,7 @@
     { // acquire lock
         mLock.lock();
 
-        if (mInputFilterEnabled) {
+        if (shouldSendKeyToInputFilterLocked(args)) {
             mLock.unlock();
 
             policyFlags |= POLICY_FLAG_FILTERED;
@@ -2377,6 +2401,10 @@
     }
 }
 
+bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) {
+    return mInputFilterEnabled;
+}
+
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, "
@@ -2415,7 +2443,7 @@
     { // acquire lock
         mLock.lock();
 
-        if (mInputFilterEnabled) {
+        if (shouldSendMotionToInputFilterLocked(args)) {
             mLock.unlock();
 
             MotionEvent event;
@@ -2438,6 +2466,7 @@
                 args->deviceId, args->source, policyFlags,
                 args->action, args->flags, args->metaState, args->buttonState,
                 args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
+                args->displayId,
                 args->pointerCount, args->pointerProperties, args->pointerCoords);
 
         needWake = enqueueInboundEventLocked(newEntry);
@@ -2449,6 +2478,11 @@
     }
 }
 
+bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) {
+    // TODO: support sending secondary display events to input filter
+    return mInputFilterEnabled && isMainDisplay(args->displayId);
+}
+
 void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchCode=%d, switchValue=%d",
@@ -2532,6 +2566,7 @@
 
     case AINPUT_EVENT_TYPE_MOTION: {
         const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
+        int32_t displayId = ADISPLAY_ID_DEFAULT;
         int32_t action = motionEvent->getAction();
         size_t pointerCount = motionEvent->getPointerCount();
         const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
@@ -2553,8 +2588,8 @@
                 motionEvent->getMetaState(), motionEvent->getButtonState(),
                 motionEvent->getEdgeFlags(),
                 motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                motionEvent->getDownTime(), uint32_t(pointerCount),
-                pointerProperties, samplePointerCoords);
+                motionEvent->getDownTime(), displayId,
+                uint32_t(pointerCount), pointerProperties, samplePointerCoords);
         lastInjectedEntry = firstInjectedEntry;
         for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
             sampleEventTimes += 1;
@@ -2565,8 +2600,8 @@
                     motionEvent->getMetaState(), motionEvent->getButtonState(),
                     motionEvent->getEdgeFlags(),
                     motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                    motionEvent->getDownTime(), uint32_t(pointerCount),
-                    pointerProperties, samplePointerCoords);
+                    motionEvent->getDownTime(), displayId,
+                    uint32_t(pointerCount), pointerProperties, samplePointerCoords);
             lastInjectedEntry->next = nextInjectedEntry;
             lastInjectedEntry = nextInjectedEntry;
         }
@@ -2939,6 +2974,12 @@
 #endif
             return true;
         }
+        if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
+#if DEBUG_FOCUS
+            ALOGD("Cannot transfer focus because windows are on different displays.");
+#endif
+            return false;
+        }
 
         bool found = false;
         for (size_t i = 0; i < mTouchState.windows.size(); i++) {
@@ -3040,6 +3081,7 @@
     dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
     dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId);
     dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source);
+    dump.appendFormat(INDENT "TouchDisplayId: %d\n", mTouchState.displayId);
     if (!mTouchState.windows.isEmpty()) {
         dump.append(INDENT "TouchedWindows:\n");
         for (size_t i = 0; i < mTouchState.windows.size(); i++) {
@@ -3059,11 +3101,12 @@
             const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
             const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
-            dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
+            dump.appendFormat(INDENT2 "%d: name='%s', displayId=%d, "
+                    "paused=%s, hasFocus=%s, hasWallpaper=%s, "
                     "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                     "frame=[%d,%d][%d,%d], scale=%f, "
                     "touchableRegion=",
-                    i, windowInfo->name.string(),
+                    i, windowInfo->name.string(), windowInfo->displayId,
                     toString(windowInfo->paused),
                     toString(windowInfo->hasFocus),
                     toString(windowInfo->hasWallpaper),
@@ -3802,14 +3845,14 @@
         int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
         int32_t metaState, int32_t buttonState,
         int32_t edgeFlags, float xPrecision, float yPrecision,
-        nsecs_t downTime, uint32_t pointerCount,
+        nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) :
         EventEntry(TYPE_MOTION, eventTime, policyFlags),
         eventTime(eventTime),
         deviceId(deviceId), source(source), action(action), flags(flags),
         metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
         xPrecision(xPrecision), yPrecision(yPrecision),
-        downTime(downTime), pointerCount(pointerCount) {
+        downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
         this->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -3820,8 +3863,8 @@
 }
 
 void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("MotionEvent(action=%d, deviceId=%d, source=0x%08x)",
-            action, deviceId, source);
+    msg.appendFormat("MotionEvent(action=%d, deviceId=%d, source=0x%08x, displayId=%d)",
+            action, deviceId, source, displayId);
 }
 
 
@@ -3864,11 +3907,13 @@
     return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
 }
 
-bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source) const {
+bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source,
+        int32_t displayId) const {
     for (size_t i = 0; i < mMotionMementos.size(); i++) {
         const MotionMemento& memento = mMotionMementos.itemAt(i);
         if (memento.deviceId == deviceId
                 && memento.source == source
+                && memento.displayId == displayId
                 && memento.hovering) {
             return true;
         }
@@ -4025,6 +4070,7 @@
         const MotionMemento& memento = mMotionMementos.itemAt(i);
         if (memento.deviceId == entry->deviceId
                 && memento.source == entry->source
+                && memento.displayId == entry->displayId
                 && memento.hovering == hovering) {
             return i;
         }
@@ -4055,6 +4101,7 @@
     memento.xPrecision = entry->xPrecision;
     memento.yPrecision = entry->yPrecision;
     memento.downTime = entry->downTime;
+    memento.displayId = entry->displayId;
     memento.setPointers(entry);
     memento.hovering = hovering;
     memento.policyFlags = entry->policyFlags;
@@ -4090,6 +4137,7 @@
                             : AMOTION_EVENT_ACTION_CANCEL,
                     memento.flags, 0, 0, 0,
                     memento.xPrecision, memento.yPrecision, memento.downTime,
+                    memento.displayId,
                     memento.pointerCount, memento.pointerProperties, memento.pointerCoords));
         }
     }
@@ -4108,7 +4156,8 @@
             for (size_t j = 0; j < other.mMotionMementos.size(); ) {
                 const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
                 if (memento.deviceId == otherMemento.deviceId
-                        && memento.source == otherMemento.source) {
+                        && memento.source == otherMemento.source
+                        && memento.displayId == otherMemento.displayId) {
                     other.mMotionMementos.removeAt(j);
                 } else {
                     j += 1;
@@ -4240,7 +4289,7 @@
 // --- InputDispatcher::TouchState ---
 
 InputDispatcher::TouchState::TouchState() :
-    down(false), split(false), deviceId(-1), source(0) {
+    down(false), split(false), deviceId(-1), source(0), displayId(-1) {
 }
 
 InputDispatcher::TouchState::~TouchState() {
@@ -4251,6 +4300,7 @@
     split = false;
     deviceId = -1;
     source = 0;
+    displayId = -1;
     windows.clear();
 }
 
@@ -4259,6 +4309,7 @@
     split = other.split;
     deviceId = other.deviceId;
     source = other.source;
+    displayId = other.displayId;
     windows = other.windows;
 }
 
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index d0824fc..af7ff5e 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -511,15 +511,17 @@
         float xPrecision;
         float yPrecision;
         nsecs_t downTime;
+        int32_t displayId;
         uint32_t pointerCount;
         PointerProperties pointerProperties[MAX_POINTERS];
         PointerCoords pointerCoords[MAX_POINTERS];
 
         MotionEntry(nsecs_t eventTime,
-                int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
-                int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
+                int32_t deviceId, uint32_t source, uint32_t policyFlags,
+                int32_t action, int32_t flags,
+                int32_t metaState, int32_t buttonState, int32_t edgeFlags,
                 float xPrecision, float yPrecision,
-                nsecs_t downTime, uint32_t pointerCount,
+                nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
                 const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
         virtual void appendDescription(String8& msg) const;
 
@@ -696,7 +698,7 @@
 
         // Returns true if the specified source is known to have received a hover enter
         // motion event.
-        bool isHovering(int32_t deviceId, uint32_t source) const;
+        bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const;
 
         // Records tracking information for a key event that has just been published.
         // Returns true if the event should be delivered, false if it is inconsistent
@@ -752,6 +754,7 @@
             float xPrecision;
             float yPrecision;
             nsecs_t downTime;
+            int32_t displayId;
             uint32_t pointerCount;
             PointerProperties pointerProperties[MAX_POINTERS];
             PointerCoords pointerCoords[MAX_POINTERS];
@@ -867,7 +870,7 @@
     // to transfer focus to a new application.
     EventEntry* mNextUnblockedEvent;
 
-    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
+    sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y);
 
     // All registered connections mapped by channel file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByFd;
@@ -899,6 +902,10 @@
     bool runCommandsLockedInterruptible();
     CommandEntry* postCommandLocked(Command command);
 
+    // Input filter processing.
+    bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args);
+    bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args);
+
     // Inbound event processing.
     void drainInboundQueueLocked();
     void releasePendingEventLocked();
@@ -928,6 +935,7 @@
         bool split;
         int32_t deviceId; // id of the device that is currently down, others are rejected
         uint32_t source;  // source of the device that is current down, others are rejected
+        int32_t displayId; // id to the display that currently has a touch, others are rejected
         Vector<TouchedWindow> windows;
 
         TouchState();
diff --git a/services/input/InputListener.cpp b/services/input/InputListener.cpp
index 657a6b9..c2705b0 100644
--- a/services/input/InputListener.cpp
+++ b/services/input/InputListener.cpp
@@ -69,12 +69,12 @@
 NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
         uint32_t policyFlags,
         int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-        int32_t edgeFlags, uint32_t pointerCount,
+        int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime) :
         eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
         action(action), flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), pointerCount(pointerCount),
+        edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -87,7 +87,8 @@
         policyFlags(other.policyFlags),
         action(other.action), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags), pointerCount(other.pointerCount),
+        edgeFlags(other.edgeFlags), displayId(other.displayId),
+        pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(other.pointerProperties[i]);
diff --git a/services/input/InputListener.h b/services/input/InputListener.h
index b1dc0b8..486852b 100644
--- a/services/input/InputListener.h
+++ b/services/input/InputListener.h
@@ -88,6 +88,7 @@
     int32_t metaState;
     int32_t buttonState;
     int32_t edgeFlags;
+    int32_t displayId;
     uint32_t pointerCount;
     PointerProperties pointerProperties[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
@@ -99,7 +100,7 @@
 
     NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
             int32_t action, int32_t flags, int32_t metaState, int32_t buttonState,
-            int32_t edgeFlags, uint32_t pointerCount,
+            int32_t edgeFlags, int32_t displayId, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 513dc13..d56b9a9 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -2431,6 +2431,7 @@
 
     mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
+    int32_t displayId;
     if (mPointerController != NULL) {
         if (moved || scrolled || buttonsChanged) {
             mPointerController->setPresentation(
@@ -2451,9 +2452,11 @@
         mPointerController->getPosition(&x, &y);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+        displayId = ADISPLAY_ID_DEFAULT;
     } else {
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
+        displayId = ADISPLAY_ID_NONE;
     }
 
     pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
@@ -2485,7 +2488,8 @@
 
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 motionEventAction, 0, metaState, currentButtonState, 0,
-                1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime);
+                displayId, 1, &pointerProperties, &pointerCoords,
+                mXPrecision, mYPrecision, downTime);
         getListener()->notifyMotion(&args);
 
         // Send hover move after UP to tell the application that the mouse is hovering now.
@@ -2494,7 +2498,8 @@
             NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
                     metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime);
+                    displayId, 1, &pointerProperties, &pointerCoords,
+                    mXPrecision, mYPrecision, downTime);
             getListener()->notifyMotion(&hoverArgs);
         }
 
@@ -2506,7 +2511,8 @@
             NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
-                    1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime);
+                    displayId, 1, &pointerProperties, &pointerCoords,
+                    mXPrecision, mYPrecision, downTime);
             getListener()->notifyMotion(&scrollArgs);
         }
     }
@@ -2539,7 +2545,8 @@
 TouchInputMapper::TouchInputMapper(InputDevice* device) :
         InputMapper(device),
         mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),
-        mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) {
+        mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
+        mSurfaceOrientation(DISPLAY_ORIENTATION_0) {
 }
 
 TouchInputMapper::~TouchInputMapper() {
@@ -2601,6 +2608,8 @@
     dumpSurface(dump);
 
     dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
+    dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
+    dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
     dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale);
     dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale);
     dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
@@ -2810,7 +2819,7 @@
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(INDENT4 "AssociatedDisplay: present=%s, isExternal=%s\n",
+    dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n",
             toString(mParameters.hasAssociatedDisplay),
             toString(mParameters.associatedDisplayIsExternal));
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
@@ -2869,10 +2878,15 @@
         return;
     }
 
+    // Raw width and height in the natural orientation.
+    int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
+    int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
+
     // Get associated display dimensions.
+    bool viewportChanged = false;
+    DisplayViewport newViewport;
     if (mParameters.hasAssociatedDisplay) {
-        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal,
-                &mAssociatedDisplayViewport)) {
+        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) {
             ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
                     "display.  The device will be inoperable until the display size "
                     "becomes available.",
@@ -2880,25 +2894,77 @@
             mDeviceMode = DEVICE_MODE_DISABLED;
             return;
         }
-    }
-
-    // Configure dimensions.
-    int32_t width, height, orientation;
-    if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
-        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 ?
-                mAssociatedDisplayViewport.orientation : DISPLAY_ORIENTATION_0;
     } else {
-        width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
-        height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
-        orientation = DISPLAY_ORIENTATION_0;
+        newViewport.setNonDisplayViewport(rawWidth, rawHeight);
+    }
+    if (mViewport != newViewport) {
+        mViewport = newViewport;
+        viewportChanged = true;
+
+        if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
+            // Convert rotated viewport to natural surface coordinates.
+            int32_t naturalLogicalWidth, naturalLogicalHeight;
+            int32_t naturalPhysicalWidth, naturalPhysicalHeight;
+            int32_t naturalPhysicalLeft, naturalPhysicalTop;
+            int32_t naturalDeviceWidth, naturalDeviceHeight;
+            switch (mViewport.orientation) {
+            case DISPLAY_ORIENTATION_90:
+                naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
+                naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
+                naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
+                naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
+                naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
+                naturalPhysicalTop = mViewport.physicalLeft;
+                naturalDeviceWidth = mViewport.deviceHeight;
+                naturalDeviceHeight = mViewport.deviceWidth;
+                break;
+            case DISPLAY_ORIENTATION_180:
+                naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
+                naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
+                naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
+                naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
+                naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
+                naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom;
+                naturalDeviceWidth = mViewport.deviceWidth;
+                naturalDeviceHeight = mViewport.deviceHeight;
+                break;
+            case DISPLAY_ORIENTATION_270:
+                naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
+                naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
+                naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
+                naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
+                naturalPhysicalLeft = mViewport.physicalTop;
+                naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
+                naturalDeviceWidth = mViewport.deviceHeight;
+                naturalDeviceHeight = mViewport.deviceWidth;
+                break;
+            case DISPLAY_ORIENTATION_0:
+            default:
+                naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
+                naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
+                naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
+                naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
+                naturalPhysicalLeft = mViewport.physicalLeft;
+                naturalPhysicalTop = mViewport.physicalTop;
+                naturalDeviceWidth = mViewport.deviceWidth;
+                naturalDeviceHeight = mViewport.deviceHeight;
+                break;
+            }
+
+            mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
+            mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
+            mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
+            mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;
+
+            mSurfaceOrientation = mParameters.orientationAware ?
+                    mViewport.orientation : DISPLAY_ORIENTATION_0;
+        } else {
+            mSurfaceWidth = rawWidth;
+            mSurfaceHeight = rawHeight;
+            mSurfaceLeft = 0;
+            mSurfaceTop = 0;
+            mSurfaceOrientation = DISPLAY_ORIENTATION_0;
+        }
     }
 
     // If moving between pointer modes, need to reset some state.
@@ -2918,22 +2984,17 @@
         mPointerController.clear();
     }
 
-    bool orientationChanged = mSurfaceOrientation != orientation;
-    if (orientationChanged) {
-        mSurfaceOrientation = orientation;
-    }
-
-    bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height;
-    if (sizeChanged || deviceModeChanged) {
-        ALOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d, mode is %d",
-                getDeviceId(), getDeviceName().string(), width, height, mDeviceMode);
-
-        mSurfaceWidth = width;
-        mSurfaceHeight = height;
+    if (viewportChanged || deviceModeChanged) {
+        ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
+                "display id %d",
+                getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
+                mSurfaceOrientation, mDeviceMode, mViewport.displayId);
 
         // Configure X and Y factors.
-        mXScale = float(width) / (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1);
-        mYScale = float(height) / (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1);
+        mXScale = float(mSurfaceWidth) / rawWidth;
+        mYScale = float(mSurfaceHeight) / rawHeight;
+        mXTranslate = -mSurfaceLeft;
+        mYTranslate = -mSurfaceTop;
         mXPrecision = 1.0f / mXScale;
         mYPrecision = 1.0f / mYScale;
 
@@ -2950,7 +3011,7 @@
         mGeometricScale = avg(mXScale, mYScale);
 
         // Size of diagonal axis.
-        float diagonalSize = hypotf(width, height);
+        float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight);
 
         // Size factors.
         if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
@@ -3102,50 +3163,38 @@
             mOrientedRanges.distance.fuzz =
                     mRawPointerAxes.distance.fuzz * mDistanceScale;
         }
-    }
 
-    if (orientationChanged || sizeChanged || deviceModeChanged) {
-        // Compute oriented surface dimensions, precision, scales and ranges.
+        // Compute oriented precision, scales and ranges.
         // Note that the maximum value reported is an inclusive maximum value so it is one
         // unit less than the total width or height of surface.
         switch (mSurfaceOrientation) {
         case DISPLAY_ORIENTATION_90:
         case DISPLAY_ORIENTATION_270:
-            mOrientedSurfaceWidth = mSurfaceHeight;
-            mOrientedSurfaceHeight = mSurfaceWidth;
-
             mOrientedXPrecision = mYPrecision;
             mOrientedYPrecision = mXPrecision;
 
-            mOrientedRanges.x.min = 0;
-            mOrientedRanges.x.max = (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue)
-                    * mYScale;
+            mOrientedRanges.x.min = mYTranslate;
+            mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
             mOrientedRanges.x.flat = 0;
             mOrientedRanges.x.fuzz = mYScale;
 
-            mOrientedRanges.y.min = 0;
-            mOrientedRanges.y.max = (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue)
-                    * mXScale;
+            mOrientedRanges.y.min = mXTranslate;
+            mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
             mOrientedRanges.y.flat = 0;
             mOrientedRanges.y.fuzz = mXScale;
             break;
 
         default:
-            mOrientedSurfaceWidth = mSurfaceWidth;
-            mOrientedSurfaceHeight = mSurfaceHeight;
-
             mOrientedXPrecision = mXPrecision;
             mOrientedYPrecision = mYPrecision;
 
-            mOrientedRanges.x.min = 0;
-            mOrientedRanges.x.max = (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue)
-                    * mXScale;
+            mOrientedRanges.x.min = mXTranslate;
+            mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
             mOrientedRanges.x.flat = 0;
             mOrientedRanges.x.fuzz = mXScale;
 
-            mOrientedRanges.y.min = 0;
-            mOrientedRanges.y.max = (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue)
-                    * mYScale;
+            mOrientedRanges.y.min = mYTranslate;
+            mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
             mOrientedRanges.y.flat = 0;
             mOrientedRanges.y.fuzz = mYScale;
             break;
@@ -3153,10 +3202,8 @@
 
         // Compute pointer gesture detection parameters.
         if (mDeviceMode == DEVICE_MODE_POINTER) {
-            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(width, height);
+            float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);
 
             // 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
@@ -3191,8 +3238,21 @@
 }
 
 void TouchInputMapper::dumpSurface(String8& dump) {
+    dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, "
+            "logicalFrame=[%d, %d, %d, %d], "
+            "physicalFrame=[%d, %d, %d, %d], "
+            "deviceSize=[%d, %d]\n",
+            mViewport.displayId, mViewport.orientation,
+            mViewport.logicalLeft, mViewport.logicalTop,
+            mViewport.logicalRight, mViewport.logicalBottom,
+            mViewport.physicalLeft, mViewport.physicalTop,
+            mViewport.physicalRight, mViewport.physicalBottom,
+            mViewport.deviceWidth, mViewport.deviceHeight);
+
     dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
     dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
+    dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
+    dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
     dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
 }
 
@@ -4087,28 +4147,28 @@
         float x, y;
         switch (mSurfaceOrientation) {
         case DISPLAY_ORIENTATION_90:
-            x = float(in.y - mRawPointerAxes.y.minValue) * mYScale;
-            y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale;
+            x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+            y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
             orientation -= M_PI_2;
             if (orientation < - M_PI_2) {
                 orientation += M_PI;
             }
             break;
         case DISPLAY_ORIENTATION_180:
-            x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale;
-            y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale;
+            x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate;
+            y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
             break;
         case DISPLAY_ORIENTATION_270:
-            x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale;
-            y = float(in.x - mRawPointerAxes.x.minValue) * mXScale;
+            x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate;
+            y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
             orientation += M_PI_2;
             if (orientation > M_PI_2) {
                 orientation -= M_PI;
             }
             break;
         default:
-            x = float(in.x - mRawPointerAxes.x.minValue) * mXScale;
-            y = float(in.y - mRawPointerAxes.y.minValue) * mYScale;
+            x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+            y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
             break;
         }
 
@@ -4364,7 +4424,8 @@
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime);
+                mViewport.displayId, 1, &pointerProperties, &pointerCoords,
+                0, 0, mPointerGesture.downTime);
         getListener()->notifyMotion(&args);
     }
 
@@ -5272,6 +5333,7 @@
         // Send up.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                  AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0,
+                 mViewport.displayId,
                  1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                  mOrientedXPrecision, mOrientedYPrecision,
                  mPointerSimple.downTime);
@@ -5284,6 +5346,7 @@
         // Send hover exit.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0,
+                mViewport.displayId,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -5298,6 +5361,7 @@
             // Send down.
             NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0,
+                    mViewport.displayId,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime);
@@ -5307,6 +5371,7 @@
         // Send move.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0,
+                mViewport.displayId,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -5320,6 +5385,7 @@
             // Send hover enter.
             NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0,
+                    mViewport.displayId,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime);
@@ -5329,6 +5395,7 @@
         // Send hover move.
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0,
+                mViewport.displayId,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -5349,6 +5416,7 @@
 
         NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0,
+                mViewport.displayId,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -5410,7 +5478,8 @@
 
     NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
             action, flags, metaState, buttonState, edgeFlags,
-            pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime);
+            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
+            xPrecision, yPrecision, downTime);
     getListener()->notifyMotion(&args);
 }
 
@@ -6213,7 +6282,7 @@
         }
     }
 
-    // Moving a joystick axis should not wake the devide because joysticks can
+    // Moving a joystick axis should not wake the device because joysticks can
     // be fairly noisy even when not in use.  On the other hand, pushing a gamepad
     // button will likely wake the device.
     // TODO: Use the input device configuration to control this behavior more finely.
@@ -6221,7 +6290,7 @@
 
     NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
             AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            1, &pointerProperties, &pointerCoords, 0, 0, 0);
+            ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0);
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index e345a5fb..e1a8dd8 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -62,11 +62,14 @@
     int32_t physicalTop;
     int32_t physicalRight;
     int32_t physicalBottom;
+    int32_t deviceWidth;
+    int32_t deviceHeight;
 
     DisplayViewport() :
-            displayId(-1), orientation(DISPLAY_ORIENTATION_0),
+            displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
             logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
-            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0) {
+            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
+            deviceWidth(0), deviceHeight(0) {
     }
 
     bool operator==(const DisplayViewport& other) const {
@@ -79,12 +82,33 @@
                 && physicalLeft == other.physicalLeft
                 && physicalTop == other.physicalTop
                 && physicalRight == other.physicalRight
-                && physicalBottom == other.physicalBottom;
+                && physicalBottom == other.physicalBottom
+                && deviceWidth == other.deviceWidth
+                && deviceHeight == other.deviceHeight;
     }
 
     bool operator!=(const DisplayViewport& other) const {
         return !(*this == other);
     }
+
+    inline bool isValid() const {
+        return displayId >= 0;
+    }
+
+    void setNonDisplayViewport(int32_t width, int32_t height) {
+        displayId = ADISPLAY_ID_NONE;
+        orientation = DISPLAY_ORIENTATION_0;
+        logicalLeft = 0;
+        logicalTop = 0;
+        logicalRight = width;
+        logicalBottom = height;
+        physicalLeft = 0;
+        physicalTop = 0;
+        physicalRight = width;
+        physicalBottom = height;
+        deviceWidth = width;
+        deviceHeight = height;
+    }
 };
 
 /*
@@ -1297,18 +1321,30 @@
     virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0;
 
 private:
-    // The surface orientation and width and height set by configureSurface().
-    int32_t mSurfaceOrientation;
+    // The current viewport.
+    // The components of the viewport are specified in the display's rotated orientation.
+    DisplayViewport mViewport;
+
+    // The surface orientation, width and height set by configureSurface().
+    // The width and height are derived from the viewport but are specified
+    // in the natural orientation.
+    // The surface origin specifies how the surface coordinates should be translated
+    // to align with the logical display coordinate space.
+    // The orientation may be different from the viewport orientation as it specifies
+    // the rotation of the surface coordinates required to produce the viewport's
+    // requested orientation, so it will depend on whether the device is orientation aware.
     int32_t mSurfaceWidth;
     int32_t mSurfaceHeight;
-
-    // The associated display viewport set by configureSurface().
-    DisplayViewport mAssociatedDisplayViewport;
+    int32_t mSurfaceLeft;
+    int32_t mSurfaceTop;
+    int32_t mSurfaceOrientation;
 
     // Translation and scaling factors, orientation-independent.
+    float mXTranslate;
     float mXScale;
     float mXPrecision;
 
+    float mYTranslate;
     float mYScale;
     float mYPrecision;
 
@@ -1369,8 +1405,6 @@
     } mOrientedRanges;
 
     // Oriented dimensions and precision.
-    float mOrientedSurfaceWidth;
-    float mOrientedSurfaceHeight;
     float mOrientedXPrecision;
     float mOrientedYPrecision;
 
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 824a64b..3118099 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -132,6 +132,7 @@
     int32_t ownerPid;
     int32_t ownerUid;
     int32_t inputFeatures;
+    int32_t displayId;
 
     bool touchableRegionContainsPoint(int32_t x, int32_t y) const;
     bool frameContainsPoint(int32_t x, int32_t y) const;
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 03516af..c6dbbf3 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -151,6 +151,8 @@
         v.physicalTop = 0;
         v.physicalRight = isRotated ? height : width;
         v.physicalBottom = isRotated ? width : height;
+        v.deviceWidth = isRotated ? height : width;
+        v.deviceHeight = isRotated ? width : height;
         mConfig.setDisplayInfo(false /*external*/, v);
         mConfig.setDisplayInfo(true /*external*/, v);
     }
@@ -487,6 +489,7 @@
                 return OK;
             }
         }
+        outAxisInfo->clear();
         return -1;
     }
 
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 9404dce..e68686d 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -75,12 +75,12 @@
 
     private void registerForAirplaneMode(IntentFilter filter) {
         final ContentResolver resolver = mContext.getContentResolver();
-        final String airplaneModeRadios = Settings.System.getString(resolver,
-                Settings.System.AIRPLANE_MODE_RADIOS);
-        final String toggleableRadios = Settings.System.getString(resolver,
-                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        final String airplaneModeRadios = Settings.Global.getString(resolver,
+                Settings.Global.AIRPLANE_MODE_RADIOS);
+        final String toggleableRadios = Settings.Global.getString(resolver,
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
         boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
-                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+                airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
         if (mIsAirplaneSensitive) {
             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         }
@@ -151,8 +151,8 @@
      *  Returns true if airplane mode is currently on
      */
     private final boolean isAirplaneModeOn() {
-        return Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
     }
 
     /**
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 6bc5e10..7ed4f8a 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1179,17 +1179,17 @@
     }
 
     private boolean isAirplaneSensitive() {
-        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_RADIOS);
+        String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_RADIOS);
         return airplaneModeRadios == null
-            || airplaneModeRadios.contains(Settings.System.RADIO_WIFI);
+            || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
     }
 
     private boolean isAirplaneToggleable() {
-        String toggleableRadios = Settings.System.getString(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
         return toggleableRadios != null
-            && toggleableRadios.contains(Settings.System.RADIO_WIFI);
+            && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
     }
 
     /**
@@ -1198,8 +1198,8 @@
      * @return {@code true} if airplane mode is on.
      */
     private boolean isAirplaneModeOn() {
-        return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(),
-                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
+        return isAirplaneSensitive() && Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
     }
 
     @Override
@@ -1213,8 +1213,8 @@
         }
         pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
         pw.println("Stay-awake conditions: " +
-                Settings.System.getInt(mContext.getContentResolver(),
-                                       Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
+                Settings.Global.getInt(mContext.getContentResolver(),
+                                       Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
         pw.println();
 
         pw.println("Internal state:");
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index 8eeefb4..f5aa3d4 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -176,6 +176,12 @@
         } else {
             viewport.physicalFrame.setEmpty();
         }
+
+        boolean isRotated = (mCurrentOrientation == Surface.ROTATION_90
+                || mCurrentOrientation == Surface.ROTATION_270);
+        DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
+        viewport.deviceWidth = isRotated ? info.height : info.width;
+        viewport.deviceHeight = isRotated ? info.width : info.height;
     }
 
     /**
diff --git a/services/java/com/android/server/display/DisplayViewport.java b/services/java/com/android/server/display/DisplayViewport.java
index ed4016d..5080556 100644
--- a/services/java/com/android/server/display/DisplayViewport.java
+++ b/services/java/com/android/server/display/DisplayViewport.java
@@ -44,12 +44,20 @@
     // should be scaled or translated after rotation.
     public final Rect physicalFrame = new Rect();
 
+    // The full width and height of the display device, rotated in the same
+    // manner as physicalFrame.  This expresses the full native size of the display device.
+    // The physical frame should usually fit within this area.
+    public int deviceWidth;
+    public int deviceHeight;
+
     public void copyFrom(DisplayViewport viewport) {
         valid = viewport.valid;
         displayId = viewport.displayId;
         orientation = viewport.orientation;
         logicalFrame.set(viewport.logicalFrame);
         physicalFrame.set(viewport.physicalFrame);
+        deviceWidth = viewport.deviceWidth;
+        deviceHeight = viewport.deviceHeight;
     }
 
     // For debugging purposes.
@@ -60,6 +68,8 @@
                 + ", orientation=" + orientation
                 + ", logicalFrame=" + logicalFrame
                 + ", physicalFrame=" + physicalFrame
+                + ", deviceWidth=" + deviceWidth
+                + ", deviceHeight=" + deviceHeight
                 + "}";
     }
 }
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 95655a5..805818a 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -149,7 +149,8 @@
     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);
+            int physicalLeft, int physicalTop, int physicalRight, int physicalBottom,
+            int deviceWidth, int deviceHeight);
 
     private static native int nativeGetScanCodeState(int ptr,
             int deviceId, int sourceMask, int scanCode);
@@ -305,7 +306,8 @@
                 viewport.logicalFrame.left, viewport.logicalFrame.top,
                 viewport.logicalFrame.right, viewport.logicalFrame.bottom,
                 viewport.physicalFrame.left, viewport.physicalFrame.top,
-                viewport.physicalFrame.right, viewport.physicalFrame.bottom);
+                viewport.physicalFrame.right, viewport.physicalFrame.bottom,
+                viewport.deviceWidth, viewport.deviceHeight);
     }
 
     /**
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
index 1026a0d..354858b 100755
--- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java
+++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java
@@ -384,8 +384,8 @@
     }
 
     protected boolean isAirplaneModeOff() {
-        return Settings.System.getInt(
-                mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 0;
+        return Settings.Global.getInt(
+                mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 0;
     }
 
     /**
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 3329acb..4268ae0 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -359,6 +359,14 @@
         return execute("movefiles");
     }
 
+    /**
+     * Links the native library directory in an application's directory to its
+     * real location.
+     *
+     * @param dataPath data directory where the application is
+     * @param nativeLibPath target native library path
+     * @return -1 on error
+     */
     public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
         if (dataPath == null) {
             Slog.e(TAG, "unlinkNativeLibraryDirectory dataPath is null");
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 4bb6e38..b5ae214 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -25,6 +25,11 @@
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
 import static libcore.io.OsConstants.S_ISLNK;
+import static libcore.io.OsConstants.S_IRWXU;
+import static libcore.io.OsConstants.S_IRGRP;
+import static libcore.io.OsConstants.S_IXGRP;
+import static libcore.io.OsConstants.S_IROTH;
+import static libcore.io.OsConstants.S_IXOTH;
 
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
@@ -147,6 +152,7 @@
 import libcore.io.ErrnoException;
 import libcore.io.IoUtils;
 import libcore.io.Libcore;
+import libcore.io.OsConstants;
 import libcore.io.StructStat;
 
 /**
@@ -276,7 +282,7 @@
     // This is the object monitoring mDrmAppPrivateInstallDir.
     final FileObserver mDrmAppInstallObserver;
 
-    // Used for priviledge escalation.  MUST NOT BE CALLED WITH mPackages
+    // Used for privilege escalation. MUST NOT BE CALLED WITH mPackages
     // LOCK HELD.  Can be called with mInstallLock held.
     final Installer mInstaller;
 
@@ -286,6 +292,12 @@
     final File mAppInstallDir;
     final File mDalvikCacheDir;
 
+    /**
+     * Directory to which applications installed internally have native
+     * libraries copied.
+     */
+    private File mAppLibInstallDir;
+
     // Directory containing the private parts (e.g. code and non-resource assets) of forward-locked
     // apps.
     final File mDrmAppPrivateInstallDir;
@@ -1215,6 +1227,7 @@
             }
 
             mAppInstallDir = new File(dataDir, "app");
+            mAppLibInstallDir = new File(dataDir, "app-lib");
             //look for any incomplete package installations
             ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
             //clean up list
@@ -3607,6 +3620,13 @@
                 res = resInner;
             }
         }
+
+        final File nativeLibraryFile = new File(mAppLibInstallDir, packageName);
+        NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
+        if (!nativeLibraryFile.delete()) {
+            Slog.w(TAG, "Couldn't delete native library directory " + nativeLibraryFile.getPath());
+        }
+
         return res;
     }
 
@@ -4048,9 +4068,7 @@
              */
             if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
                 if (pkgSetting.nativeLibraryPathString == null) {
-                    final String nativeLibraryPath = new File(dataPath, LIB_DIR_NAME).getPath();
-                    pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
-                    pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+                    setInternalAppNativeLibraryPath(pkg, pkgSetting);
                 } else {
                     pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString;
                 }
@@ -4072,7 +4090,7 @@
          */
         if (pkg.applicationInfo.nativeLibraryDir != null) {
             try {
-                final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+                File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
                 final String dataPathString = dataPath.getCanonicalPath();
 
                 if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
@@ -4087,30 +4105,31 @@
                         Log.i(TAG, "removed obsolete native libraries for system package "
                                 + path);
                     }
-                } else if (nativeLibraryDir.getParentFile().getCanonicalPath()
-                        .equals(dataPathString)) {
-                    /*
-                     * Make sure the native library dir isn't a symlink to
-                     * something. If it is, ask installd to remove it and create
-                     * a directory so we can copy to it afterwards.
-                     */
-                    boolean isSymLink;
-                    try {
-                        isSymLink = S_ISLNK(Libcore.os.lstat(nativeLibraryDir.getPath()).st_mode);
-                    } catch (ErrnoException e) {
-                        // This shouldn't happen, but we'll fail-safe.
-                        isSymLink = true;
-                    }
-                    if (isSymLink) {
-                        mInstaller.unlinkNativeLibraryDirectory(dataPathString);
+                } else if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+                    // Update native library dir if it starts with /data/data
+                    if (nativeLibraryDir.getParent().startsWith(dataPathString)) {
+                        setInternalAppNativeLibraryPath(pkg, pkgSetting);
+                        nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
                     }
 
-                    /*
-                     * If this is an internal application or our
-                     * nativeLibraryPath points to our data directory, unpack
-                     * the libraries if necessary.
-                     */
-                    NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
+                    try {
+                        if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
+                            Slog.e(TAG, "Unable to copy native libraries");
+                            mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+                            return null;
+                        }
+                    } catch (IOException e) {
+                        Slog.e(TAG, "Unable to copy native libraries", e);
+                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+                        return null;
+                    }
+
+                    if (mInstaller.linkNativeLibraryDirectory(dataPathString,
+                            pkg.applicationInfo.nativeLibraryDir) == -1) {
+                        Slog.e(TAG, "Unable to link native library directory");
+                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+                        return null;
+                    }
                 } else {
                     Slog.i(TAG, "Linking native library dir for " + path);
                     int ret = mInstaller.linkNativeLibraryDirectory(dataPathString,
@@ -4122,7 +4141,7 @@
                     }
                 }
             } catch (IOException ioe) {
-                Log.e(TAG, "Unable to get canonical file " + ioe.toString());
+                Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
             }
         }
         pkg.mScanPath = path;
@@ -4437,6 +4456,37 @@
         return pkg;
     }
 
+    private void setInternalAppNativeLibraryPath(PackageParser.Package pkg,
+            PackageSetting pkgSetting) {
+        final String apkLibPath = getApkName(pkgSetting.codePathString);
+        final String nativeLibraryPath = new File(mAppLibInstallDir, apkLibPath).getPath();
+        pkg.applicationInfo.nativeLibraryDir = nativeLibraryPath;
+        pkgSetting.nativeLibraryPathString = nativeLibraryPath;
+    }
+
+    private static int copyNativeLibrariesForInternalApp(File scanFile, final File nativeLibraryDir)
+            throws IOException {
+        if (!nativeLibraryDir.isDirectory()) {
+            nativeLibraryDir.delete();
+            if (!nativeLibraryDir.mkdir()) {
+                throw new IOException("Cannot create " + nativeLibraryDir.getPath());
+            }
+            try {
+                Libcore.os.chmod(nativeLibraryDir.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH
+                        | S_IXOTH);
+            } catch (ErrnoException e) {
+                throw new IOException("Cannot chmod native library directory "
+                        + nativeLibraryDir.getPath(), e);
+            }
+        }
+
+        /*
+         * If this is an internal application or our nativeLibraryPath points to
+         * the app-lib directory, unpack the libraries if necessary.
+         */
+        return NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
+    }
+
     private void killApplication(String pkgName, int appId) {
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
@@ -6737,7 +6787,7 @@
             String apkName = getNextCodePath(null, pkgName, ".apk");
             codeFileName = new File(installDir, apkName + ".apk").getPath();
             resourceFileName = getResourcePathFromCodePath();
-            libraryPath = new File(dataDir, LIB_DIR_NAME).getPath();
+            libraryPath = new File(mAppLibInstallDir, pkgName).getPath();
         }
 
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
@@ -6774,6 +6824,7 @@
             installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
             codeFileName = createTempPackageFile(installDir).getPath();
             resourceFileName = getResourcePathFromCodePath();
+            libraryPath = getLibraryPathFromCodePath();
             created = true;
         }
 
@@ -6828,6 +6879,23 @@
                     return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                 }
             }
+
+            final File nativeLibraryFile = new File(getNativeLibraryPath());
+            Slog.i(TAG, "Copying native libraries to " + nativeLibraryFile.getPath());
+            if (nativeLibraryFile.exists()) {
+                NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
+                nativeLibraryFile.delete();
+            }
+            try {
+                int copyRet = copyNativeLibrariesForInternalApp(codeFile, nativeLibraryFile);
+                if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
+                    return copyRet;
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "Copying native libraries failed", e);
+                ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+            }
+
             return ret;
         }
 
@@ -6845,6 +6913,7 @@
             } else {
                 final File oldCodeFile = new File(getCodePath());
                 final File oldResourceFile = new File(getResourcePath());
+                final File oldLibraryFile = new File(getNativeLibraryPath());
 
                 // Rename APK file based on packageName
                 final String apkName = getNextCodePath(oldCodePath, pkgName, ".apk");
@@ -6859,7 +6928,20 @@
                 if (isFwdLocked() && !oldResourceFile.renameTo(newResFile)) {
                     return false;
                 }
-                resourceFileName = getResourcePathFromCodePath();
+                resourceFileName = newResFile.getPath();
+
+                // Rename library path
+                final File newLibraryFile = new File(getLibraryPathFromCodePath());
+                if (newLibraryFile.exists()) {
+                    NativeLibraryHelper.removeNativeBinariesFromDirLI(newLibraryFile);
+                    newLibraryFile.delete();
+                }
+                if (!oldLibraryFile.renameTo(newLibraryFile)) {
+                    Slog.e(TAG, "Cannot rename native library directory "
+                            + oldLibraryFile.getPath() + " to " + newLibraryFile.getPath());
+                    return false;
+                }
+                libraryPath = newLibraryFile.getPath();
 
                 // Attempt to set permissions
                 if (!setPermissions()) {
@@ -6910,8 +6992,15 @@
             }
         }
 
+        private String getLibraryPathFromCodePath() {
+            return new File(mAppLibInstallDir, getApkName(getCodePath())).getPath();
+        }
+
         @Override
         String getNativeLibraryPath() {
+            if (libraryPath == null) {
+                libraryPath = getLibraryPathFromCodePath();
+            }
             return libraryPath;
         }
 
@@ -6937,6 +7026,15 @@
                     publicSourceFile.delete();
                 }
             }
+
+            if (libraryPath != null) {
+                File nativeLibraryFile = new File(libraryPath);
+                NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryFile);
+                if (!nativeLibraryFile.delete()) {
+                    Slog.w(TAG, "Couldn't delete native library directory " + libraryPath);
+                }
+            }
+
             return ret;
         }
 
@@ -9779,31 +9877,26 @@
                                     final String newNativePath = mp.targetArgs
                                             .getNativeLibraryPath();
 
-                                    try {
-                                        final File newNativeDir = new File(newNativePath);
+                                    final File newNativeDir = new File(newNativePath);
 
-                                        final String libParentDir = newNativeDir.getParentFile()
-                                                .getCanonicalPath();
-                                        if (newNativeDir.getParentFile().getCanonicalPath()
-                                                .equals(pkg.applicationInfo.dataDir)) {
-                                            if (mInstaller
-                                                    .unlinkNativeLibraryDirectory(pkg.applicationInfo.dataDir) < 0) {
-                                                returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
-                                            } else {
-                                                NativeLibraryHelper.copyNativeBinariesIfNeededLI(
-                                                        new File(newCodePath), newNativeDir);
-                                            }
-                                        } else {
+                                    if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+                                        synchronized (mInstallLock) {
                                             if (mInstaller.linkNativeLibraryDirectory(
                                                     pkg.applicationInfo.dataDir, newNativePath) < 0) {
                                                 returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
                                             }
                                         }
-                                    } catch (IOException e) {
-                                        returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
+                                        NativeLibraryHelper.copyNativeBinariesIfNeededLI(new File(
+                                                newCodePath), newNativeDir);
+                                    } else {
+                                        synchronized (mInstallLock) {
+                                            if (mInstaller.linkNativeLibraryDirectory(
+                                                    pkg.applicationInfo.dataDir, newNativePath) < 0) {
+                                                returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+                                            }
+                                        }
                                     }
 
-
                                     if (returnCode == PackageManager.MOVE_SUCCEEDED) {
                                         pkg.mPath = newCodePath;
                                         // Move dex files around
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 5ff8a9b..aa18ee4 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -19,11 +19,13 @@
 import com.android.server.input.InputManagerService;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
+import com.android.server.wm.WindowManagerService.AllWindowsIterator;
 
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Slog;
+import android.view.Display;
 import android.view.InputChannel;
 import android.view.KeyEvent;
 import android.view.WindowManager;
@@ -225,10 +227,11 @@
             addInputWindowHandleLw(mService.mFakeWindows.get(i).mWindowHandle);
         }
 
-        // TODO(multidisplay): Input only occurs on the default display.
-        final WindowList windows = mService.getDefaultWindowList();
-        for (int i = windows.size() - 1; i >= 0; i--) {
-            final WindowState child = windows.get(i);
+        // Add all windows on the default display.
+        final AllWindowsIterator iterator = mService.new AllWindowsIterator(
+                WindowManagerService.REVERSE_ITERATOR);
+        while (iterator.hasNext()) {
+            final WindowState child = iterator.next();
             final InputChannel inputChannel = child.mInputChannel;
             final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
             if (inputChannel == null || inputWindowHandle == null || child.mRemoved) {
@@ -243,15 +246,16 @@
             final boolean isVisible = child.isVisibleLw();
             final boolean hasWallpaper = (child == mService.mWallpaperTarget)
                     && (type != WindowManager.LayoutParams.TYPE_KEYGUARD);
+            final boolean onDefaultDisplay = (child.getDisplayId() == Display.DEFAULT_DISPLAY);
 
             // If there's a drag in progress and 'child' is a potential drop target,
             // make sure it's been told about the drag
-            if (inDrag && isVisible) {
+            if (inDrag && isVisible && onDefaultDisplay) {
                 mService.mDragState.sendDragStartedIfNeededLw(child);
             }
 
             if (universeBackground != null && !addedUniverse
-                    && child.mBaseLayer < aboveUniverseLayer) {
+                    && child.mBaseLayer < aboveUniverseLayer && onDefaultDisplay) {
                 final WindowState u = universeBackground.mWin;
                 if (u.mInputChannel != null && u.mInputWindowHandle != null) {
                     addInputWindowHandleLw(u.mInputWindowHandle, u, u.mAttrs.flags,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index cdca8bc..17f4a96 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -434,6 +434,7 @@
 
     final float[] mTmpFloats = new float[9];
 
+    boolean mDisplayReady;
     boolean mSafeMode;
     boolean mDisplayEnabled = false;
     boolean mSystemBooted = false;
@@ -503,8 +504,6 @@
     final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
     final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
 
-    Display mDefaultDisplay;
-
     boolean mIsTouchDevice;
 
     final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -2085,7 +2084,7 @@
         long origId;
 
         synchronized(mWindowMap) {
-            if (mDefaultDisplay == null) {
+            if (!mDisplayReady) {
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
@@ -5604,8 +5603,10 @@
                     ">>> OPEN TRANSACTION showStrictModeViolation");
             Surface.openTransaction();
             try {
+                // TODO(multi-display): support multiple displays
                 if (mStrictModeFlash == null) {
-                    mStrictModeFlash = new StrictModeFlash(mDefaultDisplay, mFxSession);
+                    mStrictModeFlash = new StrictModeFlash(
+                            getDefaultDisplayContent().getDisplay(), mFxSession);
                 }
                 mStrictModeFlash.setVisibility(on);
             } finally {
@@ -5718,7 +5719,7 @@
             }
 
             // The screenshot API does not apply the current screen rotation.
-            rot = mDefaultDisplay.getRotation();
+            rot = getDefaultDisplayContent().getDisplay().getRotation();
             int fw = frame.width();
             int fh = frame.height();
 
@@ -6751,7 +6752,7 @@
     }
 
     boolean computeScreenConfigurationLocked(Configuration config) {
-        if (mDefaultDisplay == null) {
+        if (!mDisplayReady) {
             return false;
         }
 
@@ -6785,13 +6786,8 @@
         }
 
         if (config != null) {
-            int orientation = Configuration.ORIENTATION_SQUARE;
-            if (dw < dh) {
-                orientation = Configuration.ORIENTATION_PORTRAIT;
-            } else if (dw > dh) {
-                orientation = Configuration.ORIENTATION_LANDSCAPE;
-            }
-            config.orientation = orientation;
+            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
+                    Configuration.ORIENTATION_LANDSCAPE;
         }
 
         // Update application display metrics.
@@ -6958,9 +6954,12 @@
             synchronized (mWindowMap) {
                 try {
                     if (mDragState == null) {
+                        // TODO(multi-display): support other displays
+                        final DisplayContent displayContent = getDefaultDisplayContent();
+                        final Display display = displayContent.getDisplay();
                         Surface surface = new Surface(session, "drag surface",
                                 width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-                        surface.setLayerStack(mDefaultDisplay.getLayerStack());
+                        surface.setLayerStack(display.getLayerStack());
                         if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
                                 + surface + ": CREATE");
                         outSurface.copyFrom(surface);
@@ -7102,26 +7101,28 @@
     }
 
     public void displayReady() {
-        WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
-        final Display display = wm.getDefaultDisplay();
-        displayReady(display.getDisplayId());
+        displayReady(Display.DEFAULT_DISPLAY);
 
         synchronized(mWindowMap) {
-            readForcedDisplaySizeAndDensityLocked(getDefaultDisplayContent());
+            final DisplayContent displayContent = getDefaultDisplayContent();
+            final Display display = displayContent.getDisplay();
+            readForcedDisplaySizeAndDensityLocked(displayContent);
 
-            mDefaultDisplay = display;
+            mDisplayReady = true;
             mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_TOUCHSCREEN);
+                    PackageManager.FEATURE_TOUCHSCREEN);
 
             mAnimator.initializeLocked(display.getLayerStack());
 
             final DisplayInfo displayInfo = getDefaultDisplayInfo();
-            mAnimator.setDisplayDimensions(displayInfo.logicalWidth, displayInfo.logicalHeight,
-                displayInfo.appWidth, displayInfo.appHeight);
+            mAnimator.setDisplayDimensions(
+                    displayInfo.logicalWidth, displayInfo.logicalHeight,
+                    displayInfo.appWidth, displayInfo.appHeight);
 
-            final DisplayContent displayContent = getDefaultDisplayContent();
-            mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mInitialDisplayWidth,
-                    displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
+            mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
+                    displayContent.mInitialDisplayWidth,
+                    displayContent.mInitialDisplayHeight,
+                    displayContent.mInitialDisplayDensity);
         }
 
         try {
@@ -7802,6 +7803,7 @@
         }
         // TODO(multidisplay): For now rotations are only main screen.
         final DisplayContent displayContent = getDefaultDisplayContent();
+        final Display display = displayContent.getDisplay();
         if (displayContent.mBaseDisplayWidth < displayContent.mInitialDisplayWidth
                 || displayContent.mBaseDisplayHeight < displayContent.mInitialDisplayHeight) {
             int initW, initH, baseW, baseH;
@@ -7829,7 +7831,7 @@
             Rect inner = new Rect(0, 0, baseW, baseH);
             try {
                 mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER,
-                        mDefaultDisplay.getLayerStack());
+                        display.getLayerStack());
             } catch (Surface.OutOfResourcesException e) {
             }
         }
@@ -7929,8 +7931,10 @@
 
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
         // TODO: Multidisplay: for now only use with default display.
-        mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mBaseDisplayWidth,
-                displayContent.mBaseDisplayHeight, displayContent.mBaseDisplayDensity);
+        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
+                displayContent.mBaseDisplayWidth,
+                displayContent.mBaseDisplayHeight,
+                displayContent.mBaseDisplayDensity);
 
         displayContent.layoutNeeded = true;
 
@@ -8154,7 +8158,7 @@
             return;
         }
         
-        if (mDefaultDisplay == null) {
+        if (!mDisplayReady) {
             // Not yet initialized, nothing to do.
             return;
         }
@@ -8600,11 +8604,14 @@
                 Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
                         mNextAppTransitionThumbnail.getHeight());
                 try {
+                    // TODO(multi-display): support other displays
+                    final DisplayContent displayContent = getDefaultDisplayContent();
+                    final Display display = displayContent.getDisplay();
                     Surface surface = new Surface(mFxSession,
                             "thumbnail anim",
                             dirty.width(), dirty.height(),
                             PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-                    surface.setLayerStack(mDefaultDisplay.getLayerStack());
+                    surface.setLayerStack(display.getLayerStack());
                     topOpeningApp.mAppAnimator.thumbnail = surface;
                     if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
                             + surface + ": CREATE");
@@ -9857,7 +9864,7 @@
             return;
         }
 
-        if (mDefaultDisplay == null || !mPolicy.isScreenOnFully()) {
+        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
             // No need to freeze the screen before the system is ready or if
             // the screen is off.
             return;
@@ -9889,10 +9896,12 @@
             }
 
             // TODO(multidisplay): rotation on main screen only.
-            DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo();
+            final DisplayContent displayContent = getDefaultDisplayContent();
+            final Display display = displayContent.getDisplay();
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
-                    mDefaultDisplay, mFxSession, inTransaction, displayInfo.logicalWidth,
-                    displayInfo.logicalHeight, mDefaultDisplay.getRotation());
+                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
+                    displayInfo.logicalHeight, display.getRotation());
         }
     }
 
@@ -10003,8 +10012,8 @@
             if (line != null) {
                 String[] toks = line.split("%");
                 if (toks != null && toks.length > 0) {
-                    mWatermark =
-                            new Watermark(mDefaultDisplay, mRealDisplayMetrics, mFxSession, toks);
+                    mWatermark = new Watermark(getDefaultDisplayContent().getDisplay(),
+                            mRealDisplayMetrics, mFxSession, toks);
                 }
             }
         } catch (FileNotFoundException e) {
@@ -10372,7 +10381,7 @@
             }
         }
         pw.println();
-        if (mDefaultDisplay != null) {
+        if (mDisplayReady) {
             DisplayContentsIterator dCIterator = new DisplayContentsIterator();
             while (dCIterator.hasNext()) {
                 dCIterator.next().dump(pw);
@@ -10744,7 +10753,7 @@
         }
     }
 
-    boolean REVERSE_ITERATOR = true;
+    final static boolean REVERSE_ITERATOR = true;
     class AllWindowsIterator implements Iterator<WindowState> {
         private DisplayContent mDisplayContent;
         private DisplayContentsIterator mDisplayContentsIterator;
@@ -10804,9 +10813,7 @@
     }
 
     public DisplayContent getDefaultDisplayContent() {
-        final int displayId = mDefaultDisplay == null
-                ? Display.DEFAULT_DISPLAY : mDefaultDisplay.getDisplayId();
-        return getDisplayContent(displayId);
+        return getDisplayContent(Display.DEFAULT_DISPLAY);
     }
 
     public WindowList getDefaultWindowList() {
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 5e36bf8..319cacd 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -993,7 +993,8 @@
 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) {
+        jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom,
+        jint deviceWidth, jint deviceHeight) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     DisplayViewport v;
@@ -1007,6 +1008,8 @@
     v.physicalTop = physicalTop;
     v.physicalRight = physicalRight;
     v.physicalBottom = physicalBottom;
+    v.deviceWidth = deviceWidth;
+    v.deviceHeight = deviceHeight;
     im->setDisplayViewport(external, v);
 }
 
@@ -1288,7 +1291,7 @@
             (void*) nativeInit },
     { "nativeStart", "(I)V",
             (void*) nativeStart },
-    { "nativeSetDisplayViewport", "(IZIIIIIIIIII)V",
+    { "nativeSetDisplayViewport", "(IZIIIIIIIIIIII)V",
             (void*) nativeSetDisplayViewport },
     { "nativeGetScanCodeState", "(IIII)I",
             (void*) nativeGetScanCodeState },
diff --git a/services/jni/com_android_server_input_InputWindowHandle.cpp b/services/jni/com_android_server_input_InputWindowHandle.cpp
index 01fb781..6692994 100644
--- a/services/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_input_InputWindowHandle.cpp
@@ -52,6 +52,7 @@
     jfieldID ownerPid;
     jfieldID ownerUid;
     jfieldID inputFeatures;
+    jfieldID displayId;
 } gInputWindowHandleClassInfo;
 
 static Mutex gHandleMutex;
@@ -151,6 +152,8 @@
             gInputWindowHandleClassInfo.ownerUid);
     mInfo->inputFeatures = env->GetIntField(obj,
             gInputWindowHandleClassInfo.inputFeatures);
+    mInfo->displayId = env->GetIntField(obj,
+            gInputWindowHandleClassInfo.displayId);
 
     env->DeleteLocalRef(obj);
     return true;
@@ -291,6 +294,9 @@
 
     GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
             "inputFeatures", "I");
+
+    GET_FIELD_ID(gInputWindowHandleClassInfo.displayId, clazz,
+            "displayId", "I");
     return 0;
 }