Merge "Import revised translations.  DO NOT MERGE" into honeycomb-mr1
diff --git a/api/current.xml b/api/current.xml
index cbccf93..ace309b 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -94415,6 +94415,17 @@
  visibility="public"
 >
 </method>
+<method name="getDescription"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getManufacturer"
  return="java.lang.String"
  abstract="false"
@@ -94437,7 +94448,7 @@
  visibility="public"
 >
 </method>
-<method name="getType"
+<method name="getUri"
  return="java.lang.String"
  abstract="false"
  native="false"
@@ -211375,8 +211386,8 @@
  visibility="public"
 >
 </method>
-<method name="getMotionAxes"
- return="int[]"
+<method name="getMotionRange"
+ return="android.view.InputDevice.MotionRange"
  abstract="false"
  native="false"
  synchronized="false"
@@ -211385,6 +211396,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="axis" type="int">
+</parameter>
 </method>
 <method name="getMotionRange"
  return="android.view.InputDevice.MotionRange"
@@ -211398,6 +211411,19 @@
 >
 <parameter name="axis" type="int">
 </parameter>
+<parameter name="source" type="int">
+</parameter>
+</method>
+<method name="getMotionRanges"
+ return="java.util.List&lt;android.view.InputDevice.MotionRange&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 </method>
 <method name="getName"
  return="java.lang.String"
@@ -211763,6 +211789,17 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="getAxis"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getFlat"
  return="float"
  abstract="false"
@@ -211818,6 +211855,17 @@
  visibility="public"
 >
 </method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <class name="InputEvent"
  extends="java.lang.Object"
@@ -267390,7 +267438,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 930c6b0..b6581e9 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -74,7 +74,7 @@
     static public int staticGetMemoryClass() {
         // Really brain dead right now -- just take this from the configured
         // vm heap size, and assume it is in megabytes and thus ends with "m".
-        String vmHeapSize = SystemProperties.get("dalvik.vm.growthlimit", "");
+        String vmHeapSize = SystemProperties.get("dalvik.vm.heapgrowthlimit", "");
         if (vmHeapSize != null && !"".equals(vmHeapSize)) {
             return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));
         }
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 7d66caa..cc174d4 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -30,18 +30,21 @@
 
     private final String mManufacturer;
     private final String mModel;
-    private final String mType;
+    private final String mDescription;
     private final String mVersion;
+    private final String mUri;
 
     /**
      * UsbAccessory should only be instantiated by UsbService implementation
      * @hide
      */
-    public UsbAccessory(String manufacturer, String model, String type, String version) {
+    public UsbAccessory(String manufacturer, String model, String description,
+            String version, String uri) {
         mManufacturer = manufacturer;
         mModel = model;
-        mType = type;
+        mDescription = description;
         mVersion = version;
+        mUri = uri;
     }
 
     /**
@@ -51,8 +54,9 @@
     public UsbAccessory(String[] strings) {
         mManufacturer = strings[0];
         mModel = strings[1];
-        mType = strings[2];
+        mDescription = strings[2];
         mVersion = strings[3];
+        mUri = strings[4];
     }
 
     /**
@@ -74,12 +78,12 @@
     }
 
     /**
-     * Returns the type of the accessory.
+     * Returns a user visible description of the accessory.
      *
-     * @return the accessory type
+     * @return the accessory description
      */
-    public String getType() {
-        return mType;
+    public String getDescription() {
+        return mDescription;
     }
 
     /**
@@ -91,6 +95,17 @@
         return mVersion;
     }
 
+    /**
+     * Returns the URI for the accessory.
+     * This is an optional URI that might show information about the accessory
+     * or provide the option to download an application for the accessory
+     *
+     * @return the accessory URI
+     */
+    public String getUri() {
+        return mUri;
+    }
+
     private static boolean compare(String s1, String s2) {
         if (s1 == null) return (s2 == null);
         return s1.equals(s2);
@@ -102,8 +117,9 @@
             UsbAccessory accessory = (UsbAccessory)obj;
             return (compare(mManufacturer, accessory.getManufacturer()) &&
                     compare(mModel, accessory.getModel()) &&
-                    compare(mType, accessory.getType()) &&
-                    compare(mVersion, accessory.getVersion()));
+                    compare(mDescription, accessory.getDescription()) &&
+                    compare(mVersion, accessory.getVersion()) &&
+                    compare(mUri, accessory.getUri()));
         }
         return false;
     }
@@ -112,16 +128,18 @@
     public int hashCode() {
         return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
                 (mModel == null ? 0 : mModel.hashCode()) ^
-                (mType == null ? 0 : mType.hashCode()) ^
-                (mVersion == null ? 0 : mVersion.hashCode()));
+                (mDescription == null ? 0 : mDescription.hashCode()) ^
+                (mVersion == null ? 0 : mVersion.hashCode()) ^
+                (mUri == null ? 0 : mUri.hashCode()));
     }
 
     @Override
     public String toString() {
         return "UsbAccessory[mManufacturer=" + mManufacturer +
                             ", mModel=" + mModel +
-                            ", mType=" + mType +
-                            ", mVersion=" + mVersion + "]";
+                            ", mDescription=" + mDescription +
+                            ", mVersion=" + mVersion +
+                            ", mUri=" + mUri + "]";
     }
 
     public static final Parcelable.Creator<UsbAccessory> CREATOR =
@@ -129,9 +147,10 @@
         public UsbAccessory createFromParcel(Parcel in) {
             String manufacturer = in.readString();
             String model = in.readString();
-            String type = in.readString();
+            String description = in.readString();
             String version = in.readString();
-            return new UsbAccessory(manufacturer, model, type, version);
+            String uri = in.readString();
+            return new UsbAccessory(manufacturer, model, description, version, uri);
         }
 
         public UsbAccessory[] newArray(int size) {
@@ -146,7 +165,8 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mManufacturer);
         parcel.writeString(mModel);
-        parcel.writeString(mType);
+        parcel.writeString(mDescription);
         parcel.writeString(mVersion);
+        parcel.writeString(mUri);
    }
 }
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index def1161..98d4eb9 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -20,7 +20,9 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Describes the capabilities of a particular input device.
@@ -43,8 +45,7 @@
     private int mSources;
     private int mKeyboardType;
 
-    private final SparseArray<MotionRange> mMotionRanges = new SparseArray<MotionRange>();
-    private int[] mMotionAxes;
+    private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
     /**
      * A mask for input source classes.
@@ -354,6 +355,11 @@
 
     /**
      * Gets information about the range of values for a particular {@link MotionEvent} axis.
+     * If the device supports multiple sources, the same axis may have different meanings
+     * for each source.  Returns information about the first axis found for any source.
+     * To obtain information about the axis for a specific source, use
+     * {@link #getMotionRange(int, int)}.
+     *
      * @param axis The axis constant.
      * @return The range of values, or null if the requested axis is not
      * supported by the device.
@@ -363,30 +369,55 @@
      * @see #getSupportedAxes()
      */
     public MotionRange getMotionRange(int axis) {
-        return mMotionRanges.get(axis);
+        final int numRanges = mMotionRanges.size();
+        for (int i = 0; i < numRanges; i++) {
+            final MotionRange range = mMotionRanges.get(i);
+            if (range.mAxis == axis) {
+                return range;
+            }
+        }
+        return null;
     }
 
     /**
-     * Gets the axis ids of all motion axes supported by this device.
-     * @return The axis ids of all motion axes supported by this device.
+     * Gets information about the range of values for a particular {@link MotionEvent} axis
+     * used by a particular source on the device.
+     * If the device supports multiple sources, the same axis may have different meanings
+     * for each source.
      *
-     * @see #getMotionRange(int)
+     * @param axis The axis constant.
+     * @param source The source for which to return information.
+     * @return The range of values, or null if the requested axis is not
+     * supported by the device.
+     *
+     * @see MotionEvent#AXIS_X
+     * @see MotionEvent#AXIS_Y
+     * @see #getSupportedAxes()
      */
-    public int[] getMotionAxes() {
-        synchronized (this) {
-            if (mMotionAxes == null) {
-                final int count = mMotionRanges.size();
-                mMotionAxes = new int[count];
-                for (int i = 0; i < count; i++) {
-                    mMotionAxes[i] = mMotionRanges.keyAt(i);
-                }
+    public MotionRange getMotionRange(int axis, int source) {
+        final int numRanges = mMotionRanges.size();
+        for (int i = 0; i < numRanges; i++) {
+            final MotionRange range = mMotionRanges.get(i);
+            if (range.mAxis == axis && range.mSource == source) {
+                return range;
             }
-            return mMotionAxes;
         }
+        return null;
     }
 
-    private void addMotionRange(int axis, float min, float max, float flat, float fuzz) {
-        mMotionRanges.append(axis, new MotionRange(min, max, flat, fuzz));
+    /**
+     * Gets the ranges for all axes supported by the device.
+     * @return The motion ranges for the device.
+     *
+     * @see #getMotionRange(int, int)
+     */
+    public List<MotionRange> getMotionRanges() {
+        return mMotionRanges;
+    }
+
+    private void addMotionRange(int axis, int source,
+            float min, float max, float flat, float fuzz) {
+        mMotionRanges.add(new MotionRange(axis, source, min, max, flat, fuzz));
     }
 
     /**
@@ -395,12 +426,16 @@
      * @see InputDevice#getMotionRange(int)
      */
     public static final class MotionRange {
+        private int mAxis;
+        private int mSource;
         private float mMin;
         private float mMax;
         private float mFlat;
         private float mFuzz;
 
-        private MotionRange(float min, float max, float flat, float fuzz) {
+        private MotionRange(int axis, int source, float min, float max, float flat, float fuzz) {
+            mAxis = axis;
+            mSource = source;
             mMin = min;
             mMax = max;
             mFlat = flat;
@@ -408,6 +443,22 @@
         }
 
         /**
+         * Gets the axis id.
+         * @return The axis id.
+         */
+        public int getAxis() {
+            return mAxis;
+        }
+
+        /**
+         * Gets the source for which the axis is defined.
+         * @return The source.
+         */
+        public int getSource() {
+            return mSource;
+        }
+
+        /**
          * Gets the inclusive minimum value for the axis.
          * @return The inclusive minimum value.
          */
@@ -480,7 +531,8 @@
             if (axis < 0) {
                 break;
             }
-            addMotionRange(axis, in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
+            addMotionRange(axis, in.readInt(),
+                    in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat());
         }
     }
 
@@ -491,11 +543,11 @@
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
 
-        final int numAxes = mMotionRanges.size();
-        for (int i = 0; i < numAxes; i++) {
-            int axis = mMotionRanges.keyAt(i);
-            MotionRange range = mMotionRanges.valueAt(i);
-            out.writeInt(axis);
+        final int numRanges = mMotionRanges.size();
+        for (int i = 0; i < numRanges; i++) {
+            MotionRange range = mMotionRanges.get(i);
+            out.writeInt(range.mAxis);
+            out.writeInt(range.mSource);
             out.writeFloat(range.mMin);
             out.writeFloat(range.mMax);
             out.writeFloat(range.mFlat);
@@ -528,7 +580,7 @@
         }
         description.append("\n");
 
-        description.append("  Sources: ").append(Integer.toHexString(mSources)).append(" (");
+        description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
         appendSourceDescriptionIfApplicable(description, SOURCE_TOUCHSCREEN, "touchscreen");
@@ -541,10 +593,10 @@
 
         final int numAxes = mMotionRanges.size();
         for (int i = 0; i < numAxes; i++) {
-            int axis = mMotionRanges.keyAt(i);
-            MotionRange range = mMotionRanges.valueAt(i);
-            description.append("    ").append(MotionEvent.axisToString(axis));
-            description.append(": min=").append(range.mMin);
+            MotionRange range = mMotionRanges.get(i);
+            description.append("    ").append(MotionEvent.axisToString(range.mAxis));
+            description.append(": source=0x").append(Integer.toHexString(range.mSource));
+            description.append(" min=").append(range.mMin);
             description.append(" max=").append(range.mMax);
             description.append(" flat=").append(range.mFlat);
             description.append(" fuzz=").append(range.mFuzz);
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 3c39149..a17db5d 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2157,6 +2157,8 @@
      * MotionEvent. For touch events, clients can use this to determine if the
      * user's finger was touching the edge of the display.
      *
+     * This property is only set for {@link #ACTION_DOWN} events.
+     *
      * @see #EDGE_LEFT
      * @see #EDGE_TOP
      * @see #EDGE_RIGHT
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 705eefc..7bf61ab 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1127,10 +1127,13 @@
             protected Set<String> doInBackground(Void... unused) {
                 Set<String> installedPackages = new HashSet<String>();
                 PackageManager pm = mContext.getPackageManager();
-                List<PackageInfo> packages = pm.getInstalledPackages(0);
-                for (PackageInfo p : packages) {
-                    if (sGoogleApps.contains(p.packageName)) {
-                        installedPackages.add(p.packageName);
+                for (String name : sGoogleApps) {
+                    try {
+                        PackageInfo pInfo = pm.getPackageInfo(name,
+                                PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
+                        installedPackages.add(name);
+                    } catch(PackageManager.NameNotFoundException e) {
+                        // package not found
                     }
                 }
                 return installedPackages;
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 1742a51..52f107f 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -535,7 +535,7 @@
             mTextWrapScale = scale;
         }
 
-        if (exceedsMinScaleIncrement(scale, mActualScale) || force) {
+        if (scale != mActualScale || force) {
             float oldScale = mActualScale;
             float oldInvScale = mInvActualScale;
 
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 200c870..fb57ce0 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -564,6 +564,9 @@
             }
         } else {
             int index = (int) (position * count);
+            // Don't overflow
+            if (index > count - 1) index = count - 1;
+
             if (mList instanceof ExpandableListView) {
                 ExpandableListView expList = (ExpandableListView) mList;
                 expList.setSelectionFromTop(expList.getFlatListPosition(
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 5ac903d..076a1cb 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -23,6 +23,7 @@
 import android.graphics.Paint.FontMetricsInt;
 import android.util.Log;
 import android.view.InputDevice;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
@@ -97,7 +98,8 @@
     
     public PointerLocationView(Context c) {
         super(c);
-        setFocusable(true);
+        setFocusableInTouchMode(true);
+
         mVC = ViewConfiguration.get(c);
         mTextPaint = new Paint();
         mTextPaint.setAntiAlias(true);
@@ -505,22 +507,69 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         addPointerEvent(event);
+
+        if (event.getAction() == MotionEvent.ACTION_DOWN && !isFocused()) {
+            requestFocus();
+        }
         return true;
     }
 
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
-        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+        final int source = event.getSource();
+        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
             addPointerEvent(event);
+        } else if ((source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+            Log.i(TAG, "Joystick: " + event);
+        } else if ((source & InputDevice.SOURCE_CLASS_POSITION) != 0) {
+            Log.i(TAG, "Position: " + event);
+        } else {
+            Log.i(TAG, "Generic: " + event);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (shouldLogKey(keyCode)) {
+            final int repeatCount = event.getRepeatCount();
+            if (repeatCount == 0) {
+                Log.i(TAG, "Key Down: " + event);
+            } else {
+                Log.i(TAG, "Key Repeat #" + repeatCount + ": " + event);
+            }
             return true;
         }
-        return super.onGenericMotionEvent(event);
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (shouldLogKey(keyCode)) {
+            Log.i(TAG, "Key Up: " + event);
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    private static boolean shouldLogKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+                return true;
+            default:
+                return KeyEvent.isGamepadButton(keyCode)
+                    || KeyEvent.isModifierKey(keyCode);
+        }
     }
 
     @Override
     public boolean onTrackballEvent(MotionEvent event) {
         Log.i(TAG, "Trackball: " + event);
-        return super.onTrackballEvent(event);
+        return true;
     }
     
     // HACK
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index f89967b..ee3e209 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -91,7 +91,7 @@
         return nullObjectReturn("decoder->buildTileIndex returned false");
     }
 
-    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
+    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, stream, width, height);
 
     return GraphicsJNI::createBitmapRegionDecoder(env, bm);
 }
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 1428b63..68a158e 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -261,6 +261,23 @@
 # key 239 "KEY_KBDILLUMUP"
 # key 240 "KEY_UNKNOWN"
 
+key 256   BUTTON_1
+key 257   BUTTON_2
+key 258   BUTTON_3
+key 259   BUTTON_4
+key 260   BUTTON_5
+key 261   BUTTON_6
+key 262   BUTTON_7
+key 263   BUTTON_8
+key 264   BUTTON_9
+key 265   BUTTON_10
+key 266   BUTTON_11
+key 267   BUTTON_12
+key 268   BUTTON_13
+key 269   BUTTON_14
+key 270   BUTTON_15
+key 271   BUTTON_16
+
 key 288   BUTTON_1
 key 289   BUTTON_2
 key 290   BUTTON_3
diff --git a/docs/html/guide/developing/index.jd b/docs/html/guide/developing/index.jd
index 3a64dbc..4257bf0 100644
--- a/docs/html/guide/developing/index.jd
+++ b/docs/html/guide/developing/index.jd
@@ -23,7 +23,7 @@
       before continuing.</p>
     </li>
 
-    <li>Set up Android Virtual Devices or hardware devices</a>.
+    <li>Set up Android Virtual Devices or hardware devices.
 
       <p>You need to create Android Virtual Devices (AVD) or connect hardware devices on which
       you will install your applications.</p>
@@ -66,8 +66,8 @@
       run tests within an emulator or device.</p>
     </li>
   </ol>
-
-  <h2 id="EssentialTools">Essential command line tools</h2>
+ 
+<h2 id="EssentialTools">Essential command line tools</h2>
 
   <p>When developing in IDEs or editors other than Eclipse, be familiar with
   all of the tools below, because you will have to run them from the command line.</p>
@@ -112,6 +112,43 @@
   Eclipse, such as the <code>adb</code> shell commands. You might also need to call Keytool and Jarsigner to
   sign your applications, but you can set up Eclipse to do this automatically as well.</p>
   
-  <p>For more information on the tools provided with the Android SDK, see the
+<p>For more information on the tools provided with the Android SDK, see the
   <a href="{@docRoot}guide/developing/tools/index.html">Tools</a> section of the documentation.</p>
+  
+<h2 id="ThirdParty">Third-Party Development Tools</h2>
+<p>
+	The tools described in this section are not developed by the Android SDK team. The Android Dev Guide
+	    does not provide documentation for these tools. Please refer to the linked documents in each
+	    section for documentation.
+</p>  
+<h3 id="IntelliJ">Developing in IntelliJ IDEA</h3>
+<div style="float: right">
+<img alt="The IntelliJ graphical user interface" height="500px" src="{@docRoot}images/developing/intellijidea_android_ide.png"/>
+</div>
+<p>
+	IntelliJ IDEA is a powerful Java IDE from JetBrains that provides
+	full-cycle Android development support in both the free Community
+	Edition and the Ultimate edition.
+</p>
+<p>
+	The IDE ensures compatibility with the latest Android SDK and offers a
+	smart code editor with completion, quick navigation between code and
+	resources, a graphical debugger, unit testing support using Android
+	Testing Framework, and the ability to run applications in either the
+	emulator or a USB-connected device.
+</p>
+<p>
+	<strong>Links:</strong>
+</p>
+<ul>
+	<li>
+    	<a href="http://www.jetbrains.com/idea">IntelliJ IDEA official website</a>
+</li>
+	<li>
+    	<a href="http://www.jetbrains.com/idea/features/google_android.html">Android support in IntelliJ IDEA</a>
+</li>
+	<li>
+    	<a href="http://wiki.jetbrains.net/intellij/Android">IntelliJ IDEA Android Tutorials</a>
+	</li>
+</ul> 
 
diff --git a/docs/html/images/developing/intellijidea_android_ide.png b/docs/html/images/developing/intellijidea_android_ide.png
new file mode 100644
index 0000000..b73a4e9
--- /dev/null
+++ b/docs/html/images/developing/intellijidea_android_ide.png
Binary files differ
diff --git a/include/ui/Input.h b/include/ui/Input.h
index e92d7f5..d9d77c4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -144,6 +144,14 @@
 };
 
 /*
+ * Button state.
+ */
+enum {
+    // Primary button pressed (left mouse button).
+    BUTTON_STATE_PRIMARY = 1 << 0,
+};
+
+/*
  * Describes the basic configuration of input devices that are present.
  */
 struct InputConfiguration {
@@ -544,6 +552,8 @@
     ~InputDeviceInfo();
 
     struct MotionRange {
+        int32_t axis;
+        uint32_t source;
         float min;
         float max;
         float flat;
@@ -556,16 +566,17 @@
     inline const String8 getName() const { return mName; }
     inline uint32_t getSources() const { return mSources; }
 
-    const MotionRange* getMotionRange(int32_t axis) const;
+    const MotionRange* getMotionRange(int32_t axis, uint32_t source) const;
 
     void addSource(uint32_t source);
-    void addMotionRange(int32_t axis, float min, float max, float flat, float fuzz);
-    void addMotionRange(int32_t axis, const MotionRange& range);
+    void addMotionRange(int32_t axis, uint32_t source,
+            float min, float max, float flat, float fuzz);
+    void addMotionRange(const MotionRange& range);
 
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
 
-    inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const {
+    inline const Vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
 
@@ -575,7 +586,7 @@
     uint32_t mSources;
     int32_t mKeyboardType;
 
-    KeyedVector<int32_t, MotionRange> mMotionRanges;
+    Vector<MotionRange> mMotionRanges;
 };
 
 /*
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0ed0866..e2e698e 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -657,23 +657,30 @@
     mMotionRanges.clear();
 }
 
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t axis) const {
-    ssize_t index = mMotionRanges.indexOfKey(axis);
-    return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(
+        int32_t axis, uint32_t source) const {
+    size_t numRanges = mMotionRanges.size();
+    for (size_t i = 0; i < numRanges; i++) {
+        const MotionRange& range = mMotionRanges.itemAt(i);
+        if (range.axis == axis && range.source == source) {
+            return &range;
+        }
+    }
+    return NULL;
 }
 
 void InputDeviceInfo::addSource(uint32_t source) {
     mSources |= source;
 }
 
-void InputDeviceInfo::addMotionRange(int32_t axis, float min, float max,
+void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
         float flat, float fuzz) {
-    MotionRange range = { min, max, flat, fuzz };
-    addMotionRange(axis, range);
+    MotionRange range = { axis, source, min, max, flat, fuzz };
+    mMotionRanges.add(range);
 }
 
-void InputDeviceInfo::addMotionRange(int32_t axis, const MotionRange& range) {
-    mMotionRanges.add(axis, range);
+void InputDeviceInfo::addMotionRange(const MotionRange& range) {
+    mMotionRanges.add(range);
 }
 
 } // namespace android
diff --git a/libs/usb/src/com/android/future/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java
index cdd2b73..3d0707f 100644
--- a/libs/usb/src/com/android/future/usb/UsbAccessory.java
+++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java
@@ -23,14 +23,16 @@
 
     private final String mManufacturer;
     private final String mModel;
-    private final String mType;
+    private final String mDescription;
     private final String mVersion;
+    private final String mUri;
 
     /* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
         mManufacturer = accessory.getManufacturer();
         mModel = accessory.getModel();
-        mType = accessory.getType();
+        mDescription = accessory.getDescription();
         mVersion = accessory.getVersion();
+        mUri = accessory.getUri();
     }
 
     /**
@@ -52,12 +54,12 @@
     }
 
     /**
-     * Returns the type of the accessory.
+     * Returns a user visible description of the accessory.
      *
-     * @return the accessory type
+     * @return the accessory description
      */
-    public String getType() {
-        return mType;
+    public String getDescription() {
+        return mDescription;
     }
 
     /**
@@ -69,6 +71,17 @@
         return mVersion;
     }
 
+    /**
+     * Returns the URI for the accessory.
+     * This is an optional URI that might show information about the accessory
+     * or provide the option to download an application for the accessory
+     *
+     * @return the accessory URI
+     */
+    public String getUri() {
+        return mUri;
+    }
+
     private static boolean compare(String s1, String s2) {
         if (s1 == null) return (s2 == null);
         return s1.equals(s2);
@@ -80,17 +93,28 @@
             UsbAccessory accessory = (UsbAccessory)obj;
             return (compare(mManufacturer, accessory.getManufacturer()) &&
                     compare(mModel, accessory.getModel()) &&
-                    compare(mType, accessory.getType()) &&
-                    compare(mVersion, accessory.getVersion()));
+                    compare(mDescription, accessory.getDescription()) &&
+                    compare(mVersion, accessory.getVersion()) &&
+                    compare(mUri, accessory.getUri()));
         }
         return false;
     }
 
     @Override
+    public int hashCode() {
+        return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+                (mModel == null ? 0 : mModel.hashCode()) ^
+                (mDescription == null ? 0 : mDescription.hashCode()) ^
+                (mVersion == null ? 0 : mVersion.hashCode()) ^
+                (mUri == null ? 0 : mUri.hashCode()));
+    }
+
+    @Override
     public String toString() {
         return "UsbAccessory[mManufacturer=" + mManufacturer +
                             ", mModel=" + mModel +
-                            ", mType=" + mType +
-                            ", mVersion=" + mVersion + "]";
+                            ", mDescription=" + mDescription +
+                            ", mVersion=" + mVersion +
+                            ", mUri=" + mUri + "]";
     }
 }
diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java
index 33eb3ee..840e1e3 100644
--- a/libs/usb/src/com/android/future/usb/UsbManager.java
+++ b/libs/usb/src/com/android/future/usb/UsbManager.java
@@ -130,7 +130,7 @@
         try {
             return mService.openAccessory(new android.hardware.usb.UsbAccessory(
                     accessory.getManufacturer(),accessory.getModel(),
-                    accessory.getType(), accessory.getVersion()));
+                    accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in openAccessory" , e);
             return null;
@@ -149,8 +149,8 @@
     public boolean hasPermission(UsbAccessory accessory) {
         try {
             return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
-                        accessory.getManufacturer(),accessory.getModel(),
-                        accessory.getType(), accessory.getVersion()));
+                    accessory.getManufacturer(),accessory.getModel(),
+                    accessory.getDescription(), accessory.getVersion(), accessory.getUri()));
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in hasPermission", e);
             return false;
@@ -173,8 +173,8 @@
     public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
         try {
             mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
-                        accessory.getManufacturer(),accessory.getModel(),
-                        accessory.getType(), accessory.getVersion()),
+                    accessory.getManufacturer(),accessory.getModel(),
+                    accessory.getDescription(), accessory.getVersion(), accessory.getUri()),
                     mContext.getPackageName(), pi);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in requestPermission", e);
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
index 94cc0ce..3c0de69 100644
--- a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
+++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
@@ -133,10 +133,19 @@
         } else {
             printf("Found possible android device - attempting to switch to accessory mode\n");
 
+            uint16_t protocol;
+            ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
+                    ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
+            if (ret == 2)
+                printf("device supports protocol version %d\n", protocol);
+            else
+                fprintf(stderr, "failed to read protocol version\n");
+
             send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
             send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
-            send_string(device, ACCESSORY_STRING_TYPE, "Sample Program");
+            send_string(device, ACCESSORY_STRING_DESCRIPTION, "Sample Program");
             send_string(device, ACCESSORY_STRING_VERSION, "1.0");
+            send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
 
             ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
                     ACCESSORY_START, 0, 0, 0, 0, 0);
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index e37a6b1..e2da740 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -820,8 +820,10 @@
     bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
             || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
                     sizeof_bit_array(KEY_MAX + 1));
-    bool haveGamepadButtons =containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK),
-                sizeof_bit_array(BTN_DIGI));
+    bool haveGamepadButtons = containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_MISC),
+                    sizeof_bit_array(BTN_MOUSE))
+            || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_JOYSTICK),
+                    sizeof_bit_array(BTN_DIGI));
     if (haveKeyboardKeys || haveGamepadButtons) {
         device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
     }
@@ -850,6 +852,16 @@
         device->classes |= INPUT_DEVICE_CLASS_TOUCH;
     }
 
+    // See if this device is a joystick.
+    // Ignore touchscreens because they use the same absolute axes for other purposes.
+    // Assumes that joysticks always have gamepad buttons in order to distinguish them
+    // from other devices such as accelerometers that also have absolute axes.
+    if (haveGamepadButtons
+            && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)
+            && containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
+        device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
+    }
+
     // figure out the switches this device reports
     bool haveSwitches = false;
     for (int i=0; i<EV_SW; i++) {
@@ -874,15 +886,21 @@
         }
     }
 
-    if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
+    // Load the key map.
+    // We need to do this for joysticks too because the key layout may specify axes.
+    status_t keyMapStatus = NAME_NOT_FOUND;
+    if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
         // Load the keymap for the device.
-        status_t status = loadKeyMap(device);
+        keyMapStatus = loadKeyMap(device);
+    }
 
+    // Configure the keyboard, gamepad or virtual keyboard.
+    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
         // Set system properties for the keyboard.
         setKeyboardProperties(device, false);
 
         // Register the keyboard as a built-in keyboard if it is eligible.
-        if (!status
+        if (!keyMapStatus
                 && mBuiltInKeyboardId == -1
                 && isEligibleBuiltInKeyboard(device->identifier,
                         device->configuration, &device->keyMap)) {
@@ -913,16 +931,6 @@
         }
     }
 
-    // See if this device is a joystick.
-    // Ignore touchscreens because they use the same absolute axes for other purposes.
-    // Assumes that joysticks always have buttons and the keymap has been loaded.
-    if (device->classes & INPUT_DEVICE_CLASS_GAMEPAD
-            && !(device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
-        if (containsNonZeroByte(abs_bitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
-            device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
-        }
-    }
-
     // If the device isn't recognized as something we handle, don't monitor it.
     if (device->classes == 0) {
         LOGV("Dropping device: id=%d, path='%s', name='%s'",
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index ab42a1f..7053a94 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -85,8 +85,6 @@
     int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
     int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
 
-    inline int32_t getRange() const { return maxValue - minValue; }
-
     inline void clear() {
         valid = false;
         minValue = 0;
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index e614e81..19295e6d 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -2245,6 +2245,21 @@
         policyFlags |= POLICY_FLAG_VIRTUAL;
         flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
     }
+    if (policyFlags & POLICY_FLAG_ALT) {
+        metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
+    }
+    if (policyFlags & POLICY_FLAG_ALT_GR) {
+        metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
+    }
+    if (policyFlags & POLICY_FLAG_SHIFT) {
+        metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
+    }
+    if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
+        metaState |= AMETA_CAPS_LOCK_ON;
+    }
+    if (policyFlags & POLICY_FLAG_FUNCTION) {
+        metaState |= AMETA_FUNCTION_ON;
+    }
 
     policyFlags |= POLICY_FLAG_TRUSTED;
 
@@ -2328,17 +2343,17 @@
                 }
 
                 MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
-                if (motionEntry->deviceId != deviceId) {
-                    // Keep looking for this device.
+                if (motionEntry->deviceId != deviceId
+                        || motionEntry->source != source) {
+                    // Keep looking for this device and source.
                     continue;
                 }
 
                 if (motionEntry->action != action
-                        || motionEntry->source != source
                         || motionEntry->pointerCount != pointerCount
                         || motionEntry->isInjected()) {
-                    // Last motion event in the queue for this device is not compatible for
-                    // appending new samples.  Stop here.
+                    // Last motion event in the queue for this device and source is
+                    // not compatible for appending new samples.  Stop here.
                     goto NoBatchingOrStreaming;
                 }
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 00c3eb7..3029028 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -33,6 +33,7 @@
 // Log debug messages about pointer assignment calculations.
 #define DEBUG_POINTER_ASSIGNMENT 0
 
+
 #include "InputReader.h"
 
 #include <cutils/log.h>
@@ -88,6 +89,18 @@
     return value ? "true" : "false";
 }
 
+static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation,
+        const int32_t map[][4], size_t mapSize) {
+    if (orientation != DISPLAY_ORIENTATION_0) {
+        for (size_t i = 0; i < mapSize; i++) {
+            if (value == map[i][0]) {
+                return map[i][orientation];
+            }
+        }
+    }
+    return value;
+}
+
 static const int32_t keyCodeRotationMap[][4] = {
         // key codes enumerated counter-clockwise with the original (unrotated) key first
         // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
@@ -96,24 +109,80 @@
         { AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT },
         { AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP },
 };
-static const int keyCodeRotationMapSize =
+static const size_t keyCodeRotationMapSize =
         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
 
 int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
-    if (orientation != DISPLAY_ORIENTATION_0) {
-        for (int i = 0; i < keyCodeRotationMapSize; i++) {
-            if (keyCode == keyCodeRotationMap[i][0]) {
-                return keyCodeRotationMap[i][orientation];
-            }
-        }
-    }
-    return keyCode;
+    return rotateValueUsingRotationMap(keyCode, orientation,
+            keyCodeRotationMap, keyCodeRotationMapSize);
+}
+
+static const int32_t edgeFlagRotationMap[][4] = {
+        // edge flags enumerated counter-clockwise with the original (unrotated) edge flag first
+        // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
+        { AMOTION_EVENT_EDGE_FLAG_BOTTOM,   AMOTION_EVENT_EDGE_FLAG_RIGHT,
+                AMOTION_EVENT_EDGE_FLAG_TOP,     AMOTION_EVENT_EDGE_FLAG_LEFT },
+        { AMOTION_EVENT_EDGE_FLAG_RIGHT,  AMOTION_EVENT_EDGE_FLAG_TOP,
+                AMOTION_EVENT_EDGE_FLAG_LEFT,   AMOTION_EVENT_EDGE_FLAG_BOTTOM },
+        { AMOTION_EVENT_EDGE_FLAG_TOP,     AMOTION_EVENT_EDGE_FLAG_LEFT,
+                AMOTION_EVENT_EDGE_FLAG_BOTTOM,   AMOTION_EVENT_EDGE_FLAG_RIGHT },
+        { AMOTION_EVENT_EDGE_FLAG_LEFT,   AMOTION_EVENT_EDGE_FLAG_BOTTOM,
+                AMOTION_EVENT_EDGE_FLAG_RIGHT,  AMOTION_EVENT_EDGE_FLAG_TOP },
+};
+static const size_t edgeFlagRotationMapSize =
+        sizeof(edgeFlagRotationMap) / sizeof(edgeFlagRotationMap[0]);
+
+static int32_t rotateEdgeFlag(int32_t edgeFlag, int32_t orientation) {
+    return rotateValueUsingRotationMap(edgeFlag, orientation,
+            edgeFlagRotationMap, edgeFlagRotationMapSize);
 }
 
 static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
     return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
 }
 
+static uint32_t getButtonStateForScanCode(int32_t scanCode) {
+    // Currently all buttons are mapped to the primary button.
+    switch (scanCode) {
+    case BTN_LEFT:
+    case BTN_RIGHT:
+    case BTN_MIDDLE:
+    case BTN_SIDE:
+    case BTN_EXTRA:
+    case BTN_FORWARD:
+    case BTN_BACK:
+    case BTN_TASK:
+        return BUTTON_STATE_PRIMARY;
+    default:
+        return 0;
+    }
+}
+
+// Returns true if the pointer should be reported as being down given the specified
+// button states.
+static bool isPointerDown(uint32_t buttonState) {
+    return buttonState & BUTTON_STATE_PRIMARY;
+}
+
+static int32_t calculateEdgeFlagsUsingPointerBounds(
+        const sp<PointerControllerInterface>& pointerController, float x, float y) {
+    int32_t edgeFlags = 0;
+    float minX, minY, maxX, maxY;
+    if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
+        if (x <= minX) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
+        } else if (x >= maxX) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+        }
+        if (y <= minY) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
+        } else if (y >= maxY) {
+            edgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+        }
+    }
+    return edgeFlags;
+}
+
 
 // --- InputReader ---
 
@@ -244,23 +313,23 @@
     }
 
     // Keyboard-like devices.
-    uint32_t keyboardSources = 0;
+    uint32_t keyboardSource = 0;
     int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
     if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
-        keyboardSources |= AINPUT_SOURCE_KEYBOARD;
+        keyboardSource |= AINPUT_SOURCE_KEYBOARD;
     }
     if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
         keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
     }
     if (classes & INPUT_DEVICE_CLASS_DPAD) {
-        keyboardSources |= AINPUT_SOURCE_DPAD;
+        keyboardSource |= AINPUT_SOURCE_DPAD;
     }
     if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
-        keyboardSources |= AINPUT_SOURCE_GAMEPAD;
+        keyboardSource |= AINPUT_SOURCE_GAMEPAD;
     }
 
-    if (keyboardSources != 0) {
-        device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType));
+    if (keyboardSource != 0) {
+        device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType));
     }
 
     // Cursor-like devices.
@@ -591,22 +660,22 @@
     dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
     dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
 
-    const KeyedVector<int32_t, InputDeviceInfo::MotionRange> ranges = deviceInfo.getMotionRanges();
+    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     if (!ranges.isEmpty()) {
         dump.append(INDENT2 "Motion Ranges:\n");
         for (size_t i = 0; i < ranges.size(); i++) {
-            int32_t axis = ranges.keyAt(i);
-            const char* label = getAxisLabel(axis);
+            const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+            const char* label = getAxisLabel(range.axis);
             char name[32];
             if (label) {
                 strncpy(name, label, sizeof(name));
                 name[sizeof(name) - 1] = '\0';
             } else {
-                snprintf(name, sizeof(name), "%d", axis);
+                snprintf(name, sizeof(name), "%d", range.axis);
             }
-            const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
-            dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
-                    name, range.min, range.max, range.flat, range.fuzz);
+            dump.appendFormat(INDENT3 "%s: source=0x%08x, "
+                    "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n",
+                    name, range.source, range.min, range.max, range.flat, range.fuzz);
         }
     }
 
@@ -811,8 +880,8 @@
 // --- KeyboardInputMapper ---
 
 KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
-        uint32_t sources, int32_t keyboardType) :
-        InputMapper(device), mSources(sources),
+        uint32_t source, int32_t keyboardType) :
+        InputMapper(device), mSource(source),
         mKeyboardType(keyboardType) {
     initializeLocked();
 }
@@ -826,7 +895,7 @@
 }
 
 uint32_t KeyboardInputMapper::getSources() {
-    return mSources;
+    return mSource;
 }
 
 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -919,6 +988,7 @@
 bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
     return scanCode < BTN_MOUSE
         || scanCode >= KEY_OK
+        || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE)
         || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
 }
 
@@ -1009,10 +1079,7 @@
         getContext()->fadePointer();
     }
 
-    if (policyFlags & POLICY_FLAG_FUNCTION) {
-        newMetaState |= AMETA_FUNCTION_ON;
-    }
-    getDispatcher()->notifyKey(when, getDeviceId(), mSources, policyFlags,
+    getDispatcher()->notifyKey(when, getDeviceId(), mSource, policyFlags,
             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
             AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
 }
@@ -1092,7 +1159,7 @@
 }
 
 uint32_t CursorInputMapper::getSources() {
-    return mSources;
+    return mSource;
 }
 
 void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1101,20 +1168,20 @@
     if (mParameters.mode == Parameters::MODE_POINTER) {
         float minX, minY, maxX, maxY;
         if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_X, minX, maxX, 0.0f, 0.0f);
-            info->addMotionRange(AMOTION_EVENT_AXIS_Y, minY, maxY, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f);
+            info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f);
         }
     } else {
-        info->addMotionRange(AMOTION_EVENT_AXIS_X, -1.0f, 1.0f, 0.0f, mXScale);
-        info->addMotionRange(AMOTION_EVENT_AXIS_Y, -1.0f, 1.0f, 0.0f, mYScale);
+        info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale);
+        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale);
     }
-    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f);
+    info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f);
 
     if (mHaveVWheel) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, -1.0f, 1.0f, 0.0f, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
     }
     if (mHaveHWheel) {
-        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, -1.0f, 1.0f, 0.0f, 0.0f);
+        info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f);
     }
 }
 
@@ -1131,7 +1198,8 @@
         dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mHaveHWheel));
         dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
         dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
-        dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
+        dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mLocked.buttonState);
+        dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mLocked.buttonState)));
         dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime);
     } // release lock
 }
@@ -1145,7 +1213,7 @@
     // Configure device mode.
     switch (mParameters.mode) {
     case Parameters::MODE_POINTER:
-        mSources = AINPUT_SOURCE_MOUSE;
+        mSource = AINPUT_SOURCE_MOUSE;
         mXPrecision = 1.0f;
         mYPrecision = 1.0f;
         mXScale = 1.0f;
@@ -1153,7 +1221,7 @@
         mPointerController = getPolicy()->obtainPointerController(getDeviceId());
         break;
     case Parameters::MODE_NAVIGATION:
-        mSources = AINPUT_SOURCE_TRACKBALL;
+        mSource = AINPUT_SOURCE_TRACKBALL;
         mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
         mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
         mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
@@ -1210,16 +1278,18 @@
 void CursorInputMapper::initializeLocked() {
     mAccumulator.clear();
 
-    mLocked.down = false;
+    mLocked.buttonState = 0;
     mLocked.downTime = 0;
 }
 
 void CursorInputMapper::reset() {
     for (;;) {
+        uint32_t buttonState;
         { // acquire lock
             AutoMutex _l(mLock);
 
-            if (! mLocked.down) {
+            buttonState = mLocked.buttonState;
+            if (!buttonState) {
                 initializeLocked();
                 break; // done
             }
@@ -1227,8 +1297,10 @@
 
         // Synthesize button up event on reset.
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-        mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
-        mAccumulator.btnMouse = false;
+        mAccumulator.clear();
+        mAccumulator.buttonDown = 0;
+        mAccumulator.buttonUp = buttonState;
+        mAccumulator.fields = Accumulator::FIELD_BUTTONS;
         sync(when);
     }
 
@@ -1237,24 +1309,25 @@
 
 void CursorInputMapper::process(const RawEvent* rawEvent) {
     switch (rawEvent->type) {
-    case EV_KEY:
-        switch (rawEvent->scanCode) {
-        case BTN_LEFT:
-        case BTN_RIGHT:
-        case BTN_MIDDLE:
-        case BTN_SIDE:
-        case BTN_EXTRA:
-        case BTN_FORWARD:
-        case BTN_BACK:
-        case BTN_TASK:
-            mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
-            mAccumulator.btnMouse = rawEvent->value != 0;
+    case EV_KEY: {
+        uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode);
+        if (buttonState) {
+            if (rawEvent->value) {
+                mAccumulator.buttonDown = buttonState;
+                mAccumulator.buttonUp = 0;
+            } else {
+                mAccumulator.buttonDown = 0;
+                mAccumulator.buttonUp = buttonState;
+            }
+            mAccumulator.fields |= Accumulator::FIELD_BUTTONS;
+
             // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
             // we need to ensure that we report the up/down promptly.
             sync(rawEvent->when);
             break;
         }
         break;
+    }
 
     case EV_REL:
         switch (rawEvent->scanCode) {
@@ -1293,30 +1366,34 @@
         return; // no new state changes, so nothing to do
     }
 
-    int motionEventAction;
+    int32_t motionEventAction;
+    int32_t motionEventEdgeFlags;
     PointerCoords pointerCoords;
     nsecs_t downTime;
     float vscroll, hscroll;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
+        bool down, downChanged;
+        bool wasDown = isPointerDown(mLocked.buttonState);
+        bool buttonsChanged = fields & Accumulator::FIELD_BUTTONS;
+        if (buttonsChanged) {
+            mLocked.buttonState = (mLocked.buttonState | mAccumulator.buttonDown)
+                    & ~mAccumulator.buttonUp;
 
-        if (downChanged) {
-            if (mAccumulator.btnMouse) {
-                if (!mLocked.down) {
-                    mLocked.down = true;
-                    mLocked.downTime = when;
-                } else {
-                    downChanged = false;
-                }
+            down = isPointerDown(mLocked.buttonState);
+
+            if (!wasDown && down) {
+                mLocked.downTime = when;
+                downChanged = true;
+            } else if (wasDown && !down) {
+                downChanged = true;
             } else {
-                if (mLocked.down) {
-                    mLocked.down = false;
-                } else {
-                    downChanged = false;
-                }
+                downChanged = false;
             }
+        } else {
+            down = wasDown;
+            downChanged = false;
         }
 
         downTime = mLocked.downTime;
@@ -1324,8 +1401,8 @@
         float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f;
 
         if (downChanged) {
-            motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
-        } else if (mLocked.down || mPointerController == NULL) {
+            motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
+        } else if (down || mPointerController == NULL) {
             motionEventAction = AMOTION_EVENT_ACTION_MOVE;
         } else {
             motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;
@@ -1364,21 +1441,29 @@
 
         pointerCoords.clear();
 
+        motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
+
         if (mPointerController != NULL) {
             mPointerController->move(deltaX, deltaY);
-            if (downChanged) {
-                mPointerController->setButtonState(mLocked.down ? POINTER_BUTTON_1 : 0);
+            if (buttonsChanged) {
+                mPointerController->setButtonState(mLocked.buttonState);
             }
+
             float x, y;
             mPointerController->getPosition(&x, &y);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+
+            if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
+                motionEventEdgeFlags = calculateEdgeFlagsUsingPointerBounds(
+                        mPointerController, x, y);
+            }
         } else {
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
         }
 
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mLocked.down ? 1.0f : 0.0f);
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
 
         if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) {
             vscroll = mAccumulator.relWheel;
@@ -1406,8 +1491,8 @@
 
     int32_t metaState = mContext->getGlobalMetaState();
     int32_t pointerId = 0;
-    getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
-            motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+    getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
+            motionEventAction, 0, metaState, motionEventEdgeFlags,
             1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
 
     mAccumulator.clear();
@@ -1416,7 +1501,7 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
+        getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
                 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
     }
@@ -1433,7 +1518,9 @@
 void CursorInputMapper::fadePointer() {
     { // acquire lock
         AutoMutex _l(mLock);
-        mPointerController->fade();
+        if (mPointerController != NULL) {
+            mPointerController->fade();
+        }
     } // release lock
 }
 
@@ -1453,7 +1540,7 @@
 }
 
 uint32_t TouchInputMapper::getSources() {
-    return mSources;
+    return mTouchSource;
 }
 
 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1464,38 +1551,33 @@
 
         // Ensure surface information is up to date so that orientation changes are
         // noticed immediately.
-        configureSurfaceLocked();
+        if (!configureSurfaceLocked()) {
+            return;
+        }
 
-        info->addMotionRange(AMOTION_EVENT_AXIS_X, mLocked.orientedRanges.x);
-        info->addMotionRange(AMOTION_EVENT_AXIS_Y, mLocked.orientedRanges.y);
+        info->addMotionRange(mLocked.orientedRanges.x);
+        info->addMotionRange(mLocked.orientedRanges.y);
 
         if (mLocked.orientedRanges.havePressure) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE,
-                    mLocked.orientedRanges.pressure);
+            info->addMotionRange(mLocked.orientedRanges.pressure);
         }
 
         if (mLocked.orientedRanges.haveSize) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_SIZE,
-                    mLocked.orientedRanges.size);
+            info->addMotionRange(mLocked.orientedRanges.size);
         }
 
         if (mLocked.orientedRanges.haveTouchSize) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
-                    mLocked.orientedRanges.touchMajor);
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR,
-                    mLocked.orientedRanges.touchMinor);
+            info->addMotionRange(mLocked.orientedRanges.touchMajor);
+            info->addMotionRange(mLocked.orientedRanges.touchMinor);
         }
 
         if (mLocked.orientedRanges.haveToolSize) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MAJOR,
-                    mLocked.orientedRanges.toolMajor);
-            info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MINOR,
-                    mLocked.orientedRanges.toolMinor);
+            info->addMotionRange(mLocked.orientedRanges.toolMajor);
+            info->addMotionRange(mLocked.orientedRanges.toolMinor);
         }
 
         if (mLocked.orientedRanges.haveOrientation) {
-            info->addMotionRange(AMOTION_EVENT_AXIS_ORIENTATION,
-                    mLocked.orientedRanges.orientation);
+            info->addMotionRange(mLocked.orientedRanges.orientation);
         }
     } // release lock
 }
@@ -1509,9 +1591,8 @@
         dumpRawAxes(dump);
         dumpCalibration(dump);
         dumpSurfaceLocked(dump);
+
         dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
-        dump.appendFormat(INDENT4 "XOrigin: %d\n", mLocked.xOrigin);
-        dump.appendFormat(INDENT4 "YOrigin: %d\n", mLocked.yOrigin);
         dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale);
         dump.appendFormat(INDENT4 "YScale: %0.3f\n", mLocked.yScale);
         dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mLocked.xPrecision);
@@ -1523,7 +1604,10 @@
         dump.appendFormat(INDENT4 "ToolSizeAreaBias: %0.3f\n", mLocked.toolSizeAreaBias);
         dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale);
         dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale);
-        dump.appendFormat(INDENT4 "OrientationSCale: %0.3f\n", mLocked.orientationScale);
+        dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mLocked.orientationScale);
+
+        dump.appendFormat(INDENT3 "Last Touch:\n");
+        dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
     } // release lock
 }
 
@@ -1557,10 +1641,10 @@
     // Configure sources.
     switch (mParameters.deviceType) {
     case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
-        mSources = AINPUT_SOURCE_TOUCHSCREEN;
+        mTouchSource = AINPUT_SOURCE_TOUCHSCREEN;
         break;
     case Parameters::DEVICE_TYPE_TOUCH_PAD:
-        mSources = AINPUT_SOURCE_TOUCHPAD;
+        mTouchSource = AINPUT_SOURCE_TOUCHPAD;
         break;
     default:
         assert(false);
@@ -1593,17 +1677,20 @@
             deviceTypeString)) {
         if (deviceTypeString == "touchScreen") {
             mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-        } else if (deviceTypeString != "touchPad") {
+        } else if (deviceTypeString == "touchPad") {
+            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+        } else {
             LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
         }
     }
-    bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
 
-    mParameters.orientationAware = isTouchScreen;
+    mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
     getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1;
+    mParameters.associatedDisplayId = mParameters.orientationAware
+            || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
+            ? 0 : -1;
 }
 
 void TouchInputMapper::dumpParameters(String8& dump) {
@@ -1657,21 +1744,36 @@
 }
 
 bool TouchInputMapper::configureSurfaceLocked() {
+    // Ensure we have valid X and Y axes.
+    if (!mRawAxes.x.valid || !mRawAxes.y.valid) {
+        LOGW(INDENT "Touch device '%s' did not report support for X or Y axis!  "
+                "The device will be inoperable.", getDeviceName().string());
+        return false;
+    }
+
     // Update orientation and dimensions if needed.
     int32_t orientation = DISPLAY_ORIENTATION_0;
-    int32_t width = mRawAxes.x.getRange();
-    int32_t height = mRawAxes.y.getRange();
+    int32_t width = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1;
+    int32_t height = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
 
     if (mParameters.associatedDisplayId >= 0) {
-        bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
-        bool wantOrientation = mParameters.orientationAware;
-
         // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
         if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
-                wantSize ? &width : NULL, wantSize ? &height : NULL,
-                wantOrientation ? &orientation : NULL)) {
+                &mLocked.associatedDisplayWidth, &mLocked.associatedDisplayHeight,
+                &mLocked.associatedDisplayOrientation)) {
             return false;
         }
+
+        // A touch screen inherits the dimensions of the display.
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+            width = mLocked.associatedDisplayWidth;
+            height = mLocked.associatedDisplayHeight;
+        }
+
+        // The device inherits the orientation of the display if it is orientation aware.
+        if (mParameters.orientationAware) {
+            orientation = mLocked.associatedDisplayOrientation;
+        }
     }
 
     bool orientationChanged = mLocked.surfaceOrientation != orientation;
@@ -1681,39 +1783,24 @@
 
     bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
     if (sizeChanged) {
-        LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d",
+        LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d",
                 getDeviceId(), getDeviceName().string(), width, height);
 
         mLocked.surfaceWidth = width;
         mLocked.surfaceHeight = height;
 
         // Configure X and Y factors.
-        if (mRawAxes.x.valid && mRawAxes.y.valid) {
-            mLocked.xOrigin = mCalibration.haveXOrigin
-                    ? mCalibration.xOrigin
-                    : mRawAxes.x.minValue;
-            mLocked.yOrigin = mCalibration.haveYOrigin
-                    ? mCalibration.yOrigin
-                    : mRawAxes.y.minValue;
-            mLocked.xScale = mCalibration.haveXScale
-                    ? mCalibration.xScale
-                    : float(width) / mRawAxes.x.getRange();
-            mLocked.yScale = mCalibration.haveYScale
-                    ? mCalibration.yScale
-                    : float(height) / mRawAxes.y.getRange();
-            mLocked.xPrecision = 1.0f / mLocked.xScale;
-            mLocked.yPrecision = 1.0f / mLocked.yScale;
+        mLocked.xScale = float(width) / (mRawAxes.x.maxValue - mRawAxes.x.minValue + 1);
+        mLocked.yScale = float(height) / (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1);
+        mLocked.xPrecision = 1.0f / mLocked.xScale;
+        mLocked.yPrecision = 1.0f / mLocked.yScale;
 
-            configureVirtualKeysLocked();
-        } else {
-            LOGW(INDENT "Touch device did not report support for X or Y axis!");
-            mLocked.xOrigin = 0;
-            mLocked.yOrigin = 0;
-            mLocked.xScale = 1.0f;
-            mLocked.yScale = 1.0f;
-            mLocked.xPrecision = 1.0f;
-            mLocked.yPrecision = 1.0f;
-        }
+        mLocked.orientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
+        mLocked.orientedRanges.x.source = mTouchSource;
+        mLocked.orientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
+        mLocked.orientedRanges.y.source = mTouchSource;
+
+        configureVirtualKeysLocked();
 
         // Scale factor for terms that are not oriented in a particular axis.
         // If the pixels are square then xScale == yScale otherwise we fake it
@@ -1726,11 +1813,16 @@
         // TouchMajor and TouchMinor factors.
         if (mCalibration.touchSizeCalibration != Calibration::TOUCH_SIZE_CALIBRATION_NONE) {
             mLocked.orientedRanges.haveTouchSize = true;
+
+            mLocked.orientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
+            mLocked.orientedRanges.touchMajor.source = mTouchSource;
             mLocked.orientedRanges.touchMajor.min = 0;
             mLocked.orientedRanges.touchMajor.max = diagonalSize;
             mLocked.orientedRanges.touchMajor.flat = 0;
             mLocked.orientedRanges.touchMajor.fuzz = 0;
+
             mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor;
+            mLocked.orientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
         }
 
         // ToolMajor and ToolMinor factors.
@@ -1774,11 +1866,16 @@
             }
 
             mLocked.orientedRanges.haveToolSize = true;
+
+            mLocked.orientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
+            mLocked.orientedRanges.toolMajor.source = mTouchSource;
             mLocked.orientedRanges.toolMajor.min = 0;
             mLocked.orientedRanges.toolMajor.max = diagonalSize;
             mLocked.orientedRanges.toolMajor.flat = 0;
             mLocked.orientedRanges.toolMajor.fuzz = 0;
+
             mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor;
+            mLocked.orientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
         }
 
         // Pressure factors.
@@ -1807,6 +1904,9 @@
             }
 
             mLocked.orientedRanges.havePressure = true;
+
+            mLocked.orientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
+            mLocked.orientedRanges.pressure.source = mTouchSource;
             mLocked.orientedRanges.pressure.min = 0;
             mLocked.orientedRanges.pressure.max = 1.0;
             mLocked.orientedRanges.pressure.flat = 0;
@@ -1823,6 +1923,9 @@
             }
 
             mLocked.orientedRanges.haveSize = true;
+
+            mLocked.orientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
+            mLocked.orientedRanges.size.source = mTouchSource;
             mLocked.orientedRanges.size.min = 0;
             mLocked.orientedRanges.size.max = 1.0;
             mLocked.orientedRanges.size.flat = 0;
@@ -1839,6 +1942,8 @@
                 }
             }
 
+            mLocked.orientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
+            mLocked.orientedRanges.orientation.source = mTouchSource;
             mLocked.orientedRanges.orientation.min = - M_PI_2;
             mLocked.orientedRanges.orientation.max = M_PI_2;
             mLocked.orientedRanges.orientation.flat = 0;
@@ -1847,38 +1952,51 @@
     }
 
     if (orientationChanged || sizeChanged) {
-        // Compute oriented surface dimensions, precision, and scales.
-        float orientedXScale, orientedYScale;
+        // Compute oriented surface dimensions, 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 (mLocked.surfaceOrientation) {
         case DISPLAY_ORIENTATION_90:
         case DISPLAY_ORIENTATION_270:
             mLocked.orientedSurfaceWidth = mLocked.surfaceHeight;
             mLocked.orientedSurfaceHeight = mLocked.surfaceWidth;
+
             mLocked.orientedXPrecision = mLocked.yPrecision;
             mLocked.orientedYPrecision = mLocked.xPrecision;
-            orientedXScale = mLocked.yScale;
-            orientedYScale = mLocked.xScale;
+
+            mLocked.orientedRanges.x.min = 0;
+            mLocked.orientedRanges.x.max = (mRawAxes.y.maxValue - mRawAxes.y.minValue)
+                    * mLocked.yScale;
+            mLocked.orientedRanges.x.flat = 0;
+            mLocked.orientedRanges.x.fuzz = mLocked.yScale;
+
+            mLocked.orientedRanges.y.min = 0;
+            mLocked.orientedRanges.y.max = (mRawAxes.x.maxValue - mRawAxes.x.minValue)
+                    * mLocked.xScale;
+            mLocked.orientedRanges.y.flat = 0;
+            mLocked.orientedRanges.y.fuzz = mLocked.xScale;
             break;
+
         default:
             mLocked.orientedSurfaceWidth = mLocked.surfaceWidth;
             mLocked.orientedSurfaceHeight = mLocked.surfaceHeight;
+
             mLocked.orientedXPrecision = mLocked.xPrecision;
             mLocked.orientedYPrecision = mLocked.yPrecision;
-            orientedXScale = mLocked.xScale;
-            orientedYScale = mLocked.yScale;
+
+            mLocked.orientedRanges.x.min = 0;
+            mLocked.orientedRanges.x.max = (mRawAxes.x.maxValue - mRawAxes.x.minValue)
+                    * mLocked.xScale;
+            mLocked.orientedRanges.x.flat = 0;
+            mLocked.orientedRanges.x.fuzz = mLocked.xScale;
+
+            mLocked.orientedRanges.y.min = 0;
+            mLocked.orientedRanges.y.max = (mRawAxes.y.maxValue - mRawAxes.y.minValue)
+                    * mLocked.yScale;
+            mLocked.orientedRanges.y.flat = 0;
+            mLocked.orientedRanges.y.fuzz = mLocked.yScale;
             break;
         }
-
-        // Configure position ranges.
-        mLocked.orientedRanges.x.min = 0;
-        mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth;
-        mLocked.orientedRanges.x.flat = 0;
-        mLocked.orientedRanges.x.fuzz = orientedXScale;
-
-        mLocked.orientedRanges.y.min = 0;
-        mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight;
-        mLocked.orientedRanges.y.flat = 0;
-        mLocked.orientedRanges.y.fuzz = orientedYScale;
     }
 
     return true;
@@ -1891,8 +2009,6 @@
 }
 
 void TouchInputMapper::configureVirtualKeysLocked() {
-    assert(mRawAxes.x.valid && mRawAxes.y.valid);
-
     Vector<VirtualKeyDefinition> virtualKeyDefinitions;
     getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
 
@@ -1906,8 +2022,8 @@
 
     int32_t touchScreenLeft = mRawAxes.x.minValue;
     int32_t touchScreenTop = mRawAxes.y.minValue;
-    int32_t touchScreenWidth = mRawAxes.x.getRange();
-    int32_t touchScreenHeight = mRawAxes.y.getRange();
+    int32_t touchScreenWidth = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1;
+    int32_t touchScreenHeight = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1;
 
     for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
         const VirtualKeyDefinition& virtualKeyDefinition =
@@ -1942,7 +2058,6 @@
                 * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
         virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
                 * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
-
     }
 }
 
@@ -1965,12 +2080,6 @@
     const PropertyMap& in = getDevice()->getConfiguration();
     Calibration& out = mCalibration;
 
-    // Position
-    out.haveXOrigin = in.tryGetProperty(String8("touch.position.xOrigin"), out.xOrigin);
-    out.haveYOrigin = in.tryGetProperty(String8("touch.position.yOrigin"), out.yOrigin);
-    out.haveXScale = in.tryGetProperty(String8("touch.position.xScale"), out.xScale);
-    out.haveYScale = in.tryGetProperty(String8("touch.position.yScale"), out.yScale);
-
     // Touch Size
     out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT;
     String8 touchSizeCalibrationString;
@@ -2182,20 +2291,6 @@
 void TouchInputMapper::dumpCalibration(String8& dump) {
     dump.append(INDENT3 "Calibration:\n");
 
-    // Position
-    if (mCalibration.haveXOrigin) {
-        dump.appendFormat(INDENT4 "touch.position.xOrigin: %d\n", mCalibration.xOrigin);
-    }
-    if (mCalibration.haveYOrigin) {
-        dump.appendFormat(INDENT4 "touch.position.yOrigin: %d\n", mCalibration.yOrigin);
-    }
-    if (mCalibration.haveXScale) {
-        dump.appendFormat(INDENT4 "touch.position.xScale: %0.3f\n", mCalibration.xScale);
-    }
-    if (mCalibration.haveYScale) {
-        dump.appendFormat(INDENT4 "touch.position.yScale: %0.3f\n", mCalibration.yScale);
-    }
-
     // Touch Size
     switch (mCalibration.touchSizeCalibration) {
     case Calibration::TOUCH_SIZE_CALIBRATION_NONE:
@@ -2363,8 +2458,10 @@
 
     uint32_t policyFlags = 0;
     if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) {
-        // Hide the pointer on an initial down.
-        getContext()->fadePointer();
+        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {
+            // If this is a touch screen, hide the pointer on an initial down.
+            getContext()->fadePointer();
+        }
 
         // Initial downs on external touch devices should wake the device.
         // We don't do this for internal touch screens to prevent them from waking
@@ -2378,7 +2475,7 @@
     // Process touches and virtual keys.
     TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
     if (touchResult == DISPATCH_TOUCH) {
-        detectGestures(when);
+        suppressSwipeOntoVirtualKeys(when);
         dispatchTouches(when, policyFlags);
     }
 
@@ -2505,7 +2602,7 @@
     return touchResult;
 }
 
-void TouchInputMapper::detectGestures(nsecs_t when) {
+void TouchInputMapper::suppressSwipeOntoVirtualKeys(nsecs_t when) {
     // Disable all virtual key touches that happen within a short time interval of the
     // most recent touch.  The idea is to filter out stray virtual key presses when
     // interacting with the touch screen.
@@ -2623,14 +2720,14 @@
         int32_t motionEventAction) {
     int32_t pointerIds[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
-    int32_t motionEventEdgeFlags = 0;
+    int32_t motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
     float xPrecision, yPrecision;
 
     { // acquire lock
         AutoMutex _l(mLock);
 
         // Walk through the the active pointers and map touch screen coordinates (TouchData) into
-        // display coordinates (PointerCoords) and adjust for display orientation.
+        // display or surface coordinates (PointerCoords) and adjust for display orientation.
         for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) {
             uint32_t id = idBits.firstMarkedBit();
             idBits.clearBit(id);
@@ -2638,10 +2735,6 @@
 
             const PointerData& in = touch->pointers[inIndex];
 
-            // X and Y
-            float x = float(in.x - mLocked.xOrigin) * mLocked.xScale;
-            float y = float(in.y - mLocked.yOrigin) * mLocked.yScale;
-
             // ToolMajor and ToolMinor
             float toolMajor, toolMinor;
             switch (mCalibration.toolSizeCalibration) {
@@ -2779,33 +2872,34 @@
                 orientation = 0;
             }
 
-            // Adjust coords for orientation.
+            // X and Y
+            // Adjust coords for surface orientation.
+            float x, y;
             switch (mLocked.surfaceOrientation) {
-            case DISPLAY_ORIENTATION_90: {
-                float xTemp = x;
-                x = y;
-                y = mLocked.surfaceWidth - xTemp;
+            case DISPLAY_ORIENTATION_90:
+                x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+                y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
                 orientation -= M_PI_2;
                 if (orientation < - M_PI_2) {
                     orientation += M_PI;
                 }
                 break;
-            }
-            case DISPLAY_ORIENTATION_180: {
-                x = mLocked.surfaceWidth - x;
-                y = mLocked.surfaceHeight - y;
+            case DISPLAY_ORIENTATION_180:
+                x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale;
+                y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
                 break;
-            }
-            case DISPLAY_ORIENTATION_270: {
-                float xTemp = x;
-                x = mLocked.surfaceHeight - y;
-                y = xTemp;
+            case DISPLAY_ORIENTATION_270:
+                x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale;
+                y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
                 orientation += M_PI_2;
                 if (orientation > M_PI_2) {
                     orientation -= M_PI;
                 }
                 break;
-            }
+            default:
+                x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale;
+                y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale;
+                break;
             }
 
             // Write output coords.
@@ -2831,18 +2925,22 @@
         // Check edge flags by looking only at the first pointer since the flags are
         // global to the event.
         if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
-            float x = pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X);
-            float y = pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y);
+            uint32_t inIndex = touch->idToIndex[pointerIds[0]];
+            const PointerData& in = touch->pointers[inIndex];
 
-            if (x <= 0) {
-                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
-            } else if (x >= mLocked.orientedSurfaceWidth) {
-                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+            if (in.x <= mRawAxes.x.minValue) {
+                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
+                        mLocked.surfaceOrientation);
+            } else if (in.x >= mRawAxes.x.maxValue) {
+                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
+                        mLocked.surfaceOrientation);
             }
-            if (y <= 0) {
-                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
-            } else if (y >= mLocked.orientedSurfaceHeight) {
-                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+            if (in.y <= mRawAxes.y.minValue) {
+                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
+                        mLocked.surfaceOrientation);
+            } else if (in.y >= mRawAxes.y.maxValue) {
+                motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
+                        mLocked.surfaceOrientation);
             }
         }
 
@@ -2850,18 +2948,15 @@
         yPrecision = mLocked.orientedYPrecision;
     } // release lock
 
-    getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags,
+    getDispatcher()->notifyMotion(when, getDeviceId(), mTouchSource, policyFlags,
             motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
             pointerCount, pointerIds, pointerCoords,
             xPrecision, yPrecision, mDownTime);
 }
 
 bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
-    if (mRawAxes.x.valid && mRawAxes.y.valid) {
-        return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue
-                && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue;
-    }
-    return true;
+    return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue
+            && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue;
 }
 
 const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked(
@@ -3069,11 +3164,6 @@
  * points has moved more than a screen height from the last position,
  * then drop it. */
 bool TouchInputMapper::applyBadTouchFilter() {
-    // This hack requires valid axis parameters.
-    if (! mRawAxes.y.valid) {
-        return false;
-    }
-
     uint32_t pointerCount = mCurrentTouch.pointerCount;
 
     // Nothing to do if there are no points.
@@ -3092,7 +3182,7 @@
     // the long size of the screen to be bad.  This was a magic value
     // determined by looking at the maximum distance it is feasible
     // to actually move in one sample.
-    int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16;
+    int32_t maxDeltaY = (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1) * 7 / 16;
 
     // XXX The original code in InputDevice.java included commented out
     //     code for testing the X axis.  Note that when we drop a point
@@ -3153,11 +3243,6 @@
  * the coordinate value for one axis has jumped to the other pointer's location.
  */
 bool TouchInputMapper::applyJumpyTouchFilter() {
-    // This hack requires valid axis parameters.
-    if (! mRawAxes.y.valid) {
-        return false;
-    }
-
     uint32_t pointerCount = mCurrentTouch.pointerCount;
     if (mLastTouch.pointerCount != pointerCount) {
 #if DEBUG_HACKS
@@ -3214,7 +3299,7 @@
     }
 
     if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
-        int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR;
+        int jumpyEpsilon = (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1) / JUMPY_EPSILON_DIVISOR;
 
         // We only replace the single worst jumpy point as characterized by pointer distance
         // in a single axis.
@@ -3854,9 +3939,11 @@
 
     for (size_t i = 0; i < mAxes.size(); i++) {
         const Axis& axis = mAxes.valueAt(i);
-        info->addMotionRange(axis.axisInfo.axis, axis.min, axis.max, axis.flat, axis.fuzz);
+        info->addMotionRange(axis.axisInfo.axis, AINPUT_SOURCE_JOYSTICK,
+                axis.min, axis.max, axis.flat, axis.fuzz);
         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
-            info->addMotionRange(axis.axisInfo.highAxis, axis.min, axis.max, axis.flat, axis.fuzz);
+            info->addMotionRange(axis.axisInfo.highAxis, AINPUT_SOURCE_JOYSTICK,
+                    axis.min, axis.max, axis.flat, axis.fuzz);
         }
     }
 }
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index e2cf08e7..68002ca 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -389,7 +389,7 @@
 
 class KeyboardInputMapper : public InputMapper {
 public:
-    KeyboardInputMapper(InputDevice* device, uint32_t sources, int32_t keyboardType);
+    KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType);
     virtual ~KeyboardInputMapper();
 
     virtual uint32_t getSources();
@@ -414,7 +414,7 @@
         int32_t scanCode;
     };
 
-    uint32_t mSources;
+    uint32_t mSource;
     int32_t mKeyboardType;
 
     // Immutable configuration parameters.
@@ -493,7 +493,7 @@
 
     struct Accumulator {
         enum {
-            FIELD_BTN_MOUSE = 1,
+            FIELD_BUTTONS = 1,
             FIELD_REL_X = 2,
             FIELD_REL_Y = 4,
             FIELD_REL_WHEEL = 8,
@@ -502,7 +502,9 @@
 
         uint32_t fields;
 
-        bool btnMouse;
+        uint32_t buttonDown;
+        uint32_t buttonUp;
+
         int32_t relX;
         int32_t relY;
         int32_t relWheel;
@@ -513,7 +515,7 @@
         }
     } mAccumulator;
 
-    int32_t mSources;
+    int32_t mSource;
     float mXScale;
     float mYScale;
     float mXPrecision;
@@ -527,7 +529,7 @@
     sp<PointerControllerInterface> mPointerController;
 
     struct LockedState {
-        bool down;
+        uint32_t buttonState;
         nsecs_t downTime;
     } mLocked;
 
@@ -629,7 +631,7 @@
     };
 
     // Input sources supported by the device.
-    int32_t mSources;
+    uint32_t mTouchSource; // sources when reporting touch data
 
     // Immutable configuration parameters.
     struct Parameters {
@@ -650,16 +652,6 @@
 
     // Immutable calibration parameters in parsed form.
     struct Calibration {
-        // Position
-        bool haveXOrigin;
-        int32_t xOrigin;
-        bool haveYOrigin;
-        int32_t yOrigin;
-        bool haveXScale;
-        float xScale;
-        bool haveYScale;
-        float yScale;
-
         // Touch Size
         enum TouchSizeCalibration {
             TOUCH_SIZE_CALIBRATION_DEFAULT,
@@ -755,12 +747,14 @@
         int32_t surfaceOrientation;
         int32_t surfaceWidth, surfaceHeight;
 
+        // The associated display orientation and width and height set by configureSurfaceLocked().
+        int32_t associatedDisplayOrientation;
+        int32_t associatedDisplayWidth, associatedDisplayHeight;
+
         // Translation and scaling factors, orientation-independent.
-        int32_t xOrigin;
         float xScale;
         float xPrecision;
 
-        int32_t yOrigin;
         float yScale;
         float yPrecision;
 
@@ -882,7 +876,7 @@
     void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
             BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
             int32_t motionEventAction);
-    void detectGestures(nsecs_t when);
+    void suppressSwipeOntoVirtualKeys(nsecs_t when);
 
     bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
     const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
@@ -912,7 +906,7 @@
             FIELD_ABS_X = 2,
             FIELD_ABS_Y = 4,
             FIELD_ABS_PRESSURE = 8,
-            FIELD_ABS_TOOL_WIDTH = 16
+            FIELD_ABS_TOOL_WIDTH = 16,
         };
 
         uint32_t fields;
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index 954872b..a4ee295 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -109,12 +109,12 @@
     switch (mLocked.displayOrientation) {
     case DISPLAY_ORIENTATION_90:
     case DISPLAY_ORIENTATION_270:
-        *outMaxX = mLocked.displayHeight;
-        *outMaxY = mLocked.displayWidth;
+        *outMaxX = mLocked.displayHeight - 1;
+        *outMaxY = mLocked.displayWidth - 1;
         break;
     default:
-        *outMaxX = mLocked.displayWidth;
-        *outMaxY = mLocked.displayHeight;
+        *outMaxX = mLocked.displayWidth - 1;
+        *outMaxY = mLocked.displayHeight - 1;
         break;
     }
     return true;
@@ -309,48 +309,53 @@
     AutoMutex _l(mLock);
 
     if (mLocked.displayOrientation != orientation) {
-        float absoluteX, absoluteY;
+        // Apply offsets to convert from the pixel top-left corner position to the pixel center.
+        // This creates an invariant frame of reference that we can easily rotate when
+        // taking into account that the pointer may be located at fractional pixel offsets.
+        float x = mLocked.pointerX + 0.5f;
+        float y = mLocked.pointerY + 0.5f;
+        float temp;
 
-        // Map from oriented display coordinates to absolute display coordinates.
+        // Undo the previous rotation.
         switch (mLocked.displayOrientation) {
         case DISPLAY_ORIENTATION_90:
-            absoluteX = mLocked.displayWidth - mLocked.pointerY;
-            absoluteY = mLocked.pointerX;
+            temp = x;
+            x = mLocked.displayWidth - y;
+            y = temp;
             break;
         case DISPLAY_ORIENTATION_180:
-            absoluteX = mLocked.displayWidth - mLocked.pointerX;
-            absoluteY = mLocked.displayHeight - mLocked.pointerY;
+            x = mLocked.displayWidth - x;
+            y = mLocked.displayHeight - y;
             break;
         case DISPLAY_ORIENTATION_270:
-            absoluteX = mLocked.pointerY;
-            absoluteY = mLocked.displayHeight - mLocked.pointerX;
-            break;
-        default:
-            absoluteX = mLocked.pointerX;
-            absoluteY = mLocked.pointerY;
+            temp = x;
+            x = y;
+            y = mLocked.displayHeight - temp;
             break;
         }
 
-        // Map from absolute display coordinates to oriented display coordinates.
+        // Perform the new rotation.
         switch (orientation) {
         case DISPLAY_ORIENTATION_90:
-            mLocked.pointerX = absoluteY;
-            mLocked.pointerY = mLocked.displayWidth - absoluteX;
+            temp = x;
+            x = y;
+            y = mLocked.displayWidth - x;
             break;
         case DISPLAY_ORIENTATION_180:
-            mLocked.pointerX = mLocked.displayWidth - absoluteX;
-            mLocked.pointerY = mLocked.displayHeight - absoluteY;
+            x = mLocked.displayWidth - x;
+            y = mLocked.displayHeight - y;
             break;
         case DISPLAY_ORIENTATION_270:
-            mLocked.pointerX = mLocked.displayHeight - absoluteY;
-            mLocked.pointerY = absoluteX;
-            break;
-        default:
-            mLocked.pointerX = absoluteX;
-            mLocked.pointerY = absoluteY;
+            temp = x;
+            x = mLocked.displayHeight - y;
+            y = temp;
             break;
         }
 
+        // Apply offsets to convert from the pixel center to the pixel top-left corner position
+        // and save the results.
+        mLocked.pointerX = x - 0.5f;
+        mLocked.pointerY = y - 0.5f;
         mLocked.displayOrientation = orientation;
 
         updateLocked();
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index e28dd7d..e1dab5c 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -31,10 +31,6 @@
 
 namespace android {
 
-enum {
-    POINTER_BUTTON_1 = 1 << 0,
-};
-
 /**
  * Interface for tracking a single (mouse) pointer.
  *
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index d77cb2f..67a2e21 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -405,7 +405,8 @@
         String8 name;
         uint32_t classes;
         PropertyMap configuration;
-        KeyedVector<int, RawAbsoluteAxisInfo> axes;
+        KeyedVector<int, RawAbsoluteAxisInfo> absoluteAxes;
+        KeyedVector<int, bool> relativeAxes;
         KeyedVector<int32_t, int32_t> keyCodeStates;
         KeyedVector<int32_t, int32_t> scanCodeStates;
         KeyedVector<int32_t, int32_t> switchStates;
@@ -460,7 +461,7 @@
         device->configuration.addAll(configuration);
     }
 
-    void addAxis(int32_t deviceId, int axis,
+    void addAbsoluteAxis(int32_t deviceId, int axis,
             int32_t minValue, int32_t maxValue, int flat, int fuzz) {
         Device* device = getDevice(deviceId);
 
@@ -470,7 +471,12 @@
         info.maxValue = maxValue;
         info.flat = flat;
         info.fuzz = fuzz;
-        device->axes.add(axis, info);
+        device->absoluteAxes.add(axis, info);
+    }
+
+    void addRelativeAxis(int32_t deviceId, int32_t axis) {
+        Device* device = getDevice(deviceId);
+        device->relativeAxes.add(axis, true);
     }
 
     void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) {
@@ -560,9 +566,9 @@
             RawAbsoluteAxisInfo* outAxisInfo) const {
         Device* device = getDevice(deviceId);
         if (device) {
-            ssize_t index = device->axes.indexOfKey(axis);
+            ssize_t index = device->absoluteAxes.indexOfKey(axis);
             if (index >= 0) {
-                *outAxisInfo = device->axes.valueAt(index);
+                *outAxisInfo = device->absoluteAxes.valueAt(index);
                 return OK;
             }
         }
@@ -570,6 +576,10 @@
     }
 
     virtual bool hasRelativeAxis(int32_t deviceId, int axis) const {
+        Device* device = getDevice(deviceId);
+        if (device) {
+            return device->relativeAxes.indexOfKey(axis) >= 0;
+        }
         return false;
     }
 
@@ -1487,13 +1497,15 @@
     }
 
     static void assertMotionRange(const InputDeviceInfo& info,
-            int32_t rangeType, float min, float max, float flat, float fuzz) {
-        const InputDeviceInfo::MotionRange* range = info.getMotionRange(rangeType);
-        ASSERT_TRUE(range != NULL) << "Range: " << rangeType;
-        ASSERT_NEAR(min, range->min, EPSILON) << "Range: " << rangeType;
-        ASSERT_NEAR(max, range->max, EPSILON) << "Range: " << rangeType;
-        ASSERT_NEAR(flat, range->flat, EPSILON) << "Range: " << rangeType;
-        ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Range: " << rangeType;
+            int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
+        const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
+        ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source;
+        ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
+        ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
+        ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
     }
 
     static void assertPointerCoords(const PointerCoords& coords,
@@ -2001,22 +2013,25 @@
     mapper->populateDeviceInfo(&info);
 
     // Initially there may not be a valid motion range.
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X));
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
-            0.0f, 1.0f, 0.0f, 0.0f));
+    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
+    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
 
     // When the bounds are set, then there should be a valid motion range.
-    mFakePointerController->setBounds(1, 2, 800, 480);
+    mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
 
     InputDeviceInfo info2;
     mapper->populateDeviceInfo(&info2);
 
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X,
-            1, 800, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y,
-            2, 480, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+            AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE,
+            1, 800 - 1, 0.0f, 0.0f));
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+            AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE,
+            2, 480 - 1, 0.0f, 0.0f));
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE,
             0.0f, 1.0f, 0.0f, 0.0f));
 }
 
@@ -2028,11 +2043,14 @@
     InputDeviceInfo info;
     mapper->populateDeviceInfo(&info);
 
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_X,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_TRACKBALL,
             -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_Y,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_TRACKBALL,
             -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD));
-    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TRACKBALL,
             0.0f, 1.0f, 0.0f, 0.0f));
 }
 
@@ -2320,9 +2338,9 @@
 };
 
 const int32_t TouchInputMapperTest::RAW_X_MIN = 25;
-const int32_t TouchInputMapperTest::RAW_X_MAX = 1020;
+const int32_t TouchInputMapperTest::RAW_X_MAX = 1019;
 const int32_t TouchInputMapperTest::RAW_Y_MIN = 30;
-const int32_t TouchInputMapperTest::RAW_Y_MAX = 1010;
+const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009;
 const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0;
 const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31;
 const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0;
@@ -2333,8 +2351,8 @@
 const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7;
 const int32_t TouchInputMapperTest::RAW_ID_MIN = 0;
 const int32_t TouchInputMapperTest::RAW_ID_MAX = 9;
-const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH;
-const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT;
+const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH;
+const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT;
 
 const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = {
         { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 },
@@ -2353,19 +2371,19 @@
 }
 
 int32_t TouchInputMapperTest::toRawX(float displayX) {
-    return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH + RAW_X_MIN);
+    return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN);
 }
 
 int32_t TouchInputMapperTest::toRawY(float displayY) {
-    return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT + RAW_Y_MIN);
+    return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
 }
 
 float TouchInputMapperTest::toDisplayX(int32_t rawX) {
-    return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN);
+    return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1);
 }
 
 float TouchInputMapperTest::toDisplayY(int32_t rawY) {
-    return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN);
+    return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1);
 }
 
 
@@ -2385,14 +2403,18 @@
 
 void SingleTouchInputMapperTest::prepareAxes(int axes) {
     if (axes & POSITION) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X,
+                RAW_X_MIN, RAW_X_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y,
+                RAW_Y_MIN, RAW_Y_MAX, 0, 0);
     }
     if (axes & PRESSURE) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE,
+                RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
     }
     if (axes & TOOL) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH,
+                RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
     }
 }
 
@@ -2950,12 +2972,12 @@
 
     // Rotation 90.
     prepareDisplay(DISPLAY_ORIENTATION_90);
-    processDown(mapper, toRawX(50), toRawY(75));
+    processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50));
     processSync(mapper);
 
     ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
 
     processUp(mapper);
     processSync(mapper);
@@ -2963,12 +2985,12 @@
 
     // Rotation 180.
     prepareDisplay(DISPLAY_ORIENTATION_180);
-    processDown(mapper, toRawX(50), toRawY(75));
+    processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
     processSync(mapper);
 
     ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
 
     processUp(mapper);
     processSync(mapper);
@@ -2976,12 +2998,12 @@
 
     // Rotation 270.
     prepareDisplay(DISPLAY_ORIENTATION_270);
-    processDown(mapper, toRawX(50), toRawY(75));
+    processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN);
     processSync(mapper);
 
     ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
-    ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
-    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+    ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+    ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
 
     processUp(mapper);
     processSync(mapper);
@@ -3040,33 +3062,37 @@
 
 void MultiTouchInputMapperTest::prepareAxes(int axes) {
     if (axes & POSITION) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0);
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X,
+                RAW_X_MIN, RAW_X_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y,
+                RAW_Y_MIN, RAW_Y_MAX, 0, 0);
     }
     if (axes & TOUCH) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR,
+                RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
         if (axes & MINOR) {
-            mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
+            mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR,
                     RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0);
         }
     }
     if (axes & TOOL) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR,
+                RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0);
         if (axes & MINOR) {
-            mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
+            mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR,
                     RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0);
         }
     }
     if (axes & ORIENTATION) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_ORIENTATION,
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION,
                 RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0);
     }
     if (axes & PRESSURE) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_PRESSURE,
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE,
                 RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0);
     }
     if (axes & ID) {
-        mFakeEventHub->addAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
+        mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID,
                 RAW_ID_MIN, RAW_ID_MAX, 0, 0);
     }
 }
@@ -3601,8 +3627,8 @@
     float y = toDisplayY(rawY);
     float pressure = float(rawTouchMajor) / RAW_TOUCH_MAX;
     float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX;
-    float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN),
-            float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN));
+    float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1),
+            float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1));
     float toolMajor = float(rawToolMajor) * scale;
     float toolMinor = float(rawToolMinor) * scale;
     float touchMajor = min(float(rawTouchMajor) * scale, toolMajor);
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
index 25eac6f..9398979 100644
--- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -236,22 +236,18 @@
         public final String mManufacturer;
         // USB accessory model (or null for unspecified)
         public final String mModel;
-        // USB accessory type (or null for unspecified)
-        public final String mType;
         // USB accessory version (or null for unspecified)
         public final String mVersion;
 
-        public AccessoryFilter(String manufacturer, String model, String type, String version) {
+        public AccessoryFilter(String manufacturer, String model, String version) {
             mManufacturer = manufacturer;
             mModel = model;
-            mType = type;
             mVersion = version;
         }
 
         public AccessoryFilter(UsbAccessory accessory) {
             mManufacturer = accessory.getManufacturer();
             mModel = accessory.getModel();
-            mType = accessory.getType();
             mVersion = accessory.getVersion();
         }
 
@@ -259,7 +255,6 @@
                 throws XmlPullParserException, IOException {
             String manufacturer = null;
             String model = null;
-            String type = null;
             String version = null;
 
             int count = parser.getAttributeCount();
@@ -271,13 +266,11 @@
                     manufacturer = value;
                 } else if ("model".equals(name)) {
                     model = value;
-                } else if ("type".equals(name)) {
-                    type = value;
                 } else if ("version".equals(name)) {
                     version = value;
                 }
              }
-             return new AccessoryFilter(manufacturer, model, type, version);
+             return new AccessoryFilter(manufacturer, model, version);
         }
 
         public void write(XmlSerializer serializer)throws IOException {
@@ -288,9 +281,6 @@
             if (mModel != null) {
                 serializer.attribute(null, "model", mModel);
             }
-            if (mType != null) {
-                serializer.attribute(null, "type", mType);
-            }
             if (mVersion != null) {
                 serializer.attribute(null, "version", mVersion);
             }
@@ -300,7 +290,6 @@
         public boolean matches(UsbAccessory acc) {
             if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
             if (mModel != null && !acc.getModel().equals(mModel)) return false;
-            if (mType != null && !acc.getType().equals(mType)) return false;
             if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
             return true;
         }
@@ -308,21 +297,19 @@
         @Override
         public boolean equals(Object obj) {
             // can't compare if we have wildcard strings
-            if (mManufacturer == null || mModel == null || mType == null || mVersion == null) {
+            if (mManufacturer == null || mModel == null || mVersion == null) {
                 return false;
             }
             if (obj instanceof AccessoryFilter) {
                 AccessoryFilter filter = (AccessoryFilter)obj;
                 return (mManufacturer.equals(filter.mManufacturer) &&
                         mModel.equals(filter.mModel) &&
-                        mType.equals(filter.mType) &&
                         mVersion.equals(filter.mVersion));
             }
             if (obj instanceof UsbAccessory) {
                 UsbAccessory accessory = (UsbAccessory)obj;
                 return (mManufacturer.equals(accessory.getManufacturer()) &&
                         mModel.equals(accessory.getModel()) &&
-                        mType.equals(accessory.getType()) &&
                         mVersion.equals(accessory.getVersion()));
             }
             return false;
@@ -332,7 +319,6 @@
         public int hashCode() {
             return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
                     (mModel == null ? 0 : mModel.hashCode()) ^
-                    (mType == null ? 0 : mType.hashCode()) ^
                     (mVersion == null ? 0 : mVersion.hashCode()));
         }
 
@@ -340,7 +326,6 @@
         public String toString() {
             return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
                                 "\", mModel=\"" + mModel +
-                                "\", mType=\"" + mType +
                                 "\", mVersion=\"" + mVersion + "\"]";
         }
     }
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index bd4e787..80dddc2 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -1103,12 +1103,11 @@
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mSources, deviceInfo.getSources());
     env->SetIntField(deviceObj, gInputDeviceClassInfo.mKeyboardType, deviceInfo.getKeyboardType());
 
-    const KeyedVector<int, InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
-        int rangeType = ranges.keyAt(i);
-        const InputDeviceInfo::MotionRange& range = ranges.valueAt(i);
+        const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
         env->CallVoidMethod(deviceObj, gInputDeviceClassInfo.addMotionRange,
-                rangeType, range.min, range.max, range.flat, range.fuzz);
+                range.axis, range.source, range.min, range.max, range.flat, range.fuzz);
         if (env->ExceptionCheck()) {
             return NULL;
         }
@@ -1321,7 +1320,7 @@
             "<init>", "()V");
 
     GET_METHOD_ID(gInputDeviceClassInfo.addMotionRange, gInputDeviceClassInfo.clazz,
-            "addMotionRange", "(IFFFF)V");
+            "addMotionRange", "(IIFFFF)V");
 
     GET_FIELD_ID(gInputDeviceClassInfo.mId, gInputDeviceClassInfo.clazz,
             "mId", "I");
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 3c49e54..c66f181 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -193,12 +193,13 @@
         return NULL;
     }
     jclass stringClass = env->FindClass("java/lang/String");
-    jobjectArray strArray = env->NewObjectArray(4, stringClass, NULL);
+    jobjectArray strArray = env->NewObjectArray(5, stringClass, NULL);
     if (!strArray) goto out;
     set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0);
     set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1);
-    set_accessory_string(env, fd, ACCESSORY_GET_STRING_TYPE, strArray, 2);
+    set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
     set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
+    set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
 
 out:
     close(fd);