Add support for new input sources.

Added several new coordinate values to MotionEvents to capture
touch major/minor area, tool major/minor area and orientation.

Renamed NDK input constants per convention.

Added InputDevice class in Java which will eventually provide
useful information about available input devices.

Added APIs for manufacturing new MotionEvent objects with multiple
pointers and all necessary coordinate data.

Fixed a bug in the input dispatcher where it could get stuck with
a pointer down forever.

Fixed a bug in the WindowManager where the input window list could
end up containing stale removed windows.

Fixed a bug in the WindowManager where the input channel was being
removed only after the final animation transition had taken place
which caused spurious WINDOW DIED log messages to be printed.

Change-Id: Ie55084da319b20aad29b28a0499b8dd98bb5da68
diff --git a/api/9.xml b/api/9.xml
index b7596bd..076bed7 100644
--- a/api/9.xml
+++ b/api/9.xml
@@ -167794,6 +167794,38 @@
 </parameter>
 </constructor>
 </class>
+<class name="InputEvent"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="mDeviceId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
 <class name="KeyCharacterMap"
  extends="java.lang.Object"
  abstract="false"
@@ -168130,7 +168162,7 @@
 </field>
 </class>
 <class name="KeyEvent"
- extends="java.lang.Object"
+ extends="android.view.InputEvent"
  abstract="false"
  static="false"
  final="false"
@@ -168423,17 +168455,6 @@
 <parameter name="c" type="int">
 </parameter>
 </method>
-<method name="getDeviceId"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDisplayLabel"
  return="char"
  abstract="false"
@@ -171308,7 +171329,7 @@
 </method>
 </interface>
 <class name="MotionEvent"
- extends="java.lang.Object"
+ extends="android.view.InputEvent"
  abstract="false"
  static="false"
  final="true"
@@ -171397,17 +171418,6 @@
  visibility="public"
 >
 </method>
-<method name="getDeviceId"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDownTime"
  return="long"
  abstract="false"
diff --git a/api/current.xml b/api/current.xml
index f448b85..0626cd5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -173010,6 +173010,285 @@
 </parameter>
 </constructor>
 </class>
+<class name="InputDevice"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="InputDevice"
+ type="android.view.InputDevice"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getKeyCharacterMap"
+ return="android.view.KeyCharacterMap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSources"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="SOURCE_CLASS_BUTTON"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_CLASS_JOYSTICK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_CLASS_MASK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="255"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_CLASS_POINTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_CLASS_POSITION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_CLASS_TRACKBALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_DPAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="513"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_GAMEPAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1025"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_JOYSTICK_LEFT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16777232"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_JOYSTICK_RIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="33554448"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_KEYBOARD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="257"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_MOUSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8194"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_TOUCHPAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048584"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_TOUCHSCREEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4098"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_TRACKBALL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65540"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SOURCE_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="InputEvent"
+ extends="java.lang.Object"
+ abstract="true"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="getDeviceId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSource"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="mDeviceId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+<field name="mSource"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+</field>
+</class>
 <class name="InputQueue"
  extends="java.lang.Object"
  abstract="false"
@@ -173389,7 +173668,7 @@
 </field>
 </class>
 <class name="KeyEvent"
- extends="java.lang.Object"
+ extends="android.view.InputEvent"
  abstract="false"
  static="false"
  final="false"
@@ -173467,7 +173746,7 @@
 </parameter>
 <parameter name="metaState" type="int">
 </parameter>
-<parameter name="device" type="int">
+<parameter name="deviceId" type="int">
 </parameter>
 <parameter name="scancode" type="int">
 </parameter>
@@ -173491,7 +173770,7 @@
 </parameter>
 <parameter name="metaState" type="int">
 </parameter>
-<parameter name="device" type="int">
+<parameter name="deviceId" type="int">
 </parameter>
 <parameter name="scancode" type="int">
 </parameter>
@@ -173505,11 +173784,39 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="downTime" type="long">
+</parameter>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
+<parameter name="code" type="int">
+</parameter>
+<parameter name="repeat" type="int">
+</parameter>
+<parameter name="metaState" type="int">
+</parameter>
+<parameter name="deviceId" type="int">
+</parameter>
+<parameter name="scancode" type="int">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+<parameter name="source" type="int">
+</parameter>
+</constructor>
+<constructor name="KeyEvent"
+ type="android.view.KeyEvent"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
 <parameter name="time" type="long">
 </parameter>
 <parameter name="characters" type="java.lang.String">
 </parameter>
-<parameter name="device" type="int">
+<parameter name="deviceId" type="int">
 </parameter>
 <parameter name="flags" type="int">
 </parameter>
@@ -173682,17 +173989,6 @@
 <parameter name="c" type="int">
 </parameter>
 </method>
-<method name="getDeviceId"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDisplayLabel"
  return="char"
  abstract="false"
@@ -176776,7 +177072,7 @@
 </method>
 </interface>
 <class name="MotionEvent"
- extends="java.lang.Object"
+ extends="android.view.InputEvent"
  abstract="false"
  static="false"
  final="true"
@@ -176808,6 +177104,23 @@
 <parameter name="metaState" type="int">
 </parameter>
 </method>
+<method name="addBatch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="pointerCoords" type="android.view.MotionEvent.PointerCoords[]">
+</parameter>
+<parameter name="metaState" type="int">
+</parameter>
+</method>
 <method name="describeContents"
  return="int"
  abstract="false"
@@ -176865,17 +177178,6 @@
  visibility="public"
 >
 </method>
-<method name="getDeviceId"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="getDownTime"
  return="long"
  abstract="false"
@@ -176922,6 +177224,51 @@
 <parameter name="pos" type="int">
 </parameter>
 </method>
+<method name="getHistoricalOrientation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalOrientation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalPointerCoords"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+<parameter name="outPointerCoords" type="android.view.MotionEvent.PointerCoords">
+</parameter>
+</method>
 <method name="getHistoricalPressure"
  return="float"
  abstract="false"
@@ -176978,6 +177325,118 @@
 <parameter name="pos" type="int">
 </parameter>
 </method>
+<method name="getHistoricalToolMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalToolMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalToolMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalToolMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalTouchMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalTouchMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalTouchMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pos" type="int">
+</parameter>
+</method>
+<method name="getHistoricalTouchMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="pos" type="int">
+</parameter>
+</method>
 <method name="getHistoricalX"
  return="float"
  abstract="false"
@@ -177056,6 +177515,45 @@
  visibility="public"
 >
 </method>
+<method name="getOrientation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOrientation"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
+<method name="getPointerCoords"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+<parameter name="outPointerCoords" type="android.view.MotionEvent.PointerCoords">
+</parameter>
+</method>
 <method name="getPointerCount"
  return="int"
  abstract="false"
@@ -177150,6 +177648,102 @@
 <parameter name="pointerIndex" type="int">
 </parameter>
 </method>
+<method name="getToolMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getToolMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
+<method name="getToolMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getToolMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
+<method name="getTouchMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTouchMajor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
+<method name="getTouchMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getTouchMinor"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pointerIndex" type="int">
+</parameter>
+</method>
 <method name="getX"
  return="float"
  abstract="false"
@@ -177236,6 +177830,41 @@
 </parameter>
 <parameter name="action" type="int">
 </parameter>
+<parameter name="pointers" type="int">
+</parameter>
+<parameter name="pointerIds" type="int[]">
+</parameter>
+<parameter name="pointerCoords" type="android.view.MotionEvent.PointerCoords[]">
+</parameter>
+<parameter name="metaState" type="int">
+</parameter>
+<parameter name="xPrecision" type="float">
+</parameter>
+<parameter name="yPrecision" type="float">
+</parameter>
+<parameter name="deviceId" type="int">
+</parameter>
+<parameter name="edgeFlags" type="int">
+</parameter>
+<parameter name="source" type="int">
+</parameter>
+</method>
+<method name="obtain"
+ return="android.view.MotionEvent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="downTime" type="long">
+</parameter>
+<parameter name="eventTime" type="long">
+</parameter>
+<parameter name="action" type="int">
+</parameter>
 <parameter name="x" type="float">
 </parameter>
 <parameter name="y" type="float">
@@ -177676,6 +178305,113 @@
 >
 </field>
 </class>
+<class name="MotionEvent.PointerCoords"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MotionEvent.PointerCoords"
+ type="android.view.MotionEvent.PointerCoords"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="orientation"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="pressure"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="size"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="toolMajor"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="toolMinor"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="touchMajor"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="touchMinor"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="x"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="y"
+ type="float"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="OrientationEventListener"
  extends="java.lang.Object"
  abstract="true"
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e26a090..57a72bf 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -41,6 +41,7 @@
 import android.view.Gravity;
 import android.view.IWindowSession;
 import android.view.InputChannel;
+import android.view.InputDevice;
 import android.view.InputHandler;
 import android.view.InputQueue;
 import android.view.KeyEvent;
@@ -214,9 +215,12 @@
         
         final InputHandler mInputHandler = new BaseInputHandler() {
             @Override
-            public void handleTouch(MotionEvent event, Runnable finishedCallback) {
+            public void handleMotion(MotionEvent event, Runnable finishedCallback) {
                 try {
-                    dispatchPointer(event);
+                    int source = event.getSource();
+                    if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+                        dispatchPointer(event);
+                    }
                 } finally {
                     finishedCallback.run();
                 }
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index e24c3c9..f2cad2f 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -30,6 +30,8 @@
 public final class InputChannel implements Parcelable {
     private static final String TAG = "InputChannel";
     
+    private static final boolean DEBUG = false;
+    
     public static final Parcelable.Creator<InputChannel> CREATOR
             = new Parcelable.Creator<InputChannel>() {
         public InputChannel createFromParcel(Parcel source) {
@@ -84,8 +86,10 @@
         if (name == null) {
             throw new IllegalArgumentException("name must not be null");
         }
-        
-        Slog.d(TAG, "Opening input channel pair '" + name + "'");
+
+        if (DEBUG) {
+            Slog.d(TAG, "Opening input channel pair '" + name + "'");
+        }
         return nativeOpenInputChannelPair(name);
     }
     
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
new file mode 100755
index 0000000..568caa2
--- /dev/null
+++ b/core/java/android/view/InputDevice.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Describes the capabilities of a particular input device.
+ * <p>
+ * Each input device may support multiple classes of input.  For example, a multifunction
+ * keyboard may compose the capabilities of a standard keyboard together with a track pad mouse
+ * or other pointing device.
+ * </p><p>
+ * Some input devices present multiple distinguishable sources of input.  For example, a
+ * game pad may have two analog joysticks, a directional pad and a full complement of buttons.
+ * Applications can query the framework about the characteristics of each distinct source.
+ * </p><p>
+ * As a further wrinkle, different kinds of input sources uses different coordinate systems
+ * to describe motion events.  Refer to the comments on the input source constants for
+ * the appropriate interpretation.
+ */
+public final class InputDevice {
+    private int mId;
+    private String mName;
+    private int mSources;
+    
+    /**
+     * A mask for input source classes.
+     * 
+     * Each distinct input source constant has one or more input source class bits set to
+     * specify the desired interpretation for its input events.
+     */
+    public static final int SOURCE_CLASS_MASK = 0x000000ff;
+    
+    /**
+     * The input source has buttons or keys.
+     * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_GAMEPAD}, {@link #SOURCE_DPAD}.
+     * 
+     * A {@link KeyEvent} should be interpreted as a button or key press.
+     * 
+     * Use {@link #hasKeyCode} to query whether the device supports a particular button or key.
+     */
+    public static final int SOURCE_CLASS_BUTTON = 0x00000001;
+    
+    /**
+     * The input source is a pointing device associated with a display.
+     * Examples: {@link #SOURCE_TOUCHSCREEN}, {@link #SOURCE_MOUSE}.
+     * 
+     * A {@link MotionEvent} should be interpreted as absolute coordinates in
+     * display units according to the {@link View} hierarchy.  Pointer down/up indicated when
+     * the finger touches the display or when the selection button is pressed/released.
+     * 
+     * Use {@link #getMotionRange} to query the range of the pointing device.  Some devices permit
+     * touches outside the display area so the effective range may be somewhat smaller or larger
+     * than the actual display size.
+     */
+    public static final int SOURCE_CLASS_POINTER = 0x00000002;
+    
+    /**
+     * The input source is a trackball navigation device.
+     * Examples: {@link #SOURCE_TRACKBALL}.
+     * 
+     * A {@link MotionEvent} should be interpreted as relative movements in device-specific
+     * units used for navigation purposes.  Pointer down/up indicates when the selection button
+     * is pressed/released.
+     * 
+     * Use {@link #getMotionRange} to query the range of motion.
+     */
+    public static final int SOURCE_CLASS_TRACKBALL = 0x00000004;
+    
+    /**
+     * The input source is an absolute positioning device not associated with a display
+     * (unlike {@link #SOURCE_CLASS_POINTER}).
+     * 
+     * A {@link MotionEvent} should be interpreted as absolute coordinates in
+     * device-specific surface units.
+     * 
+     * Use {@link #getMotionRange} to query the range of positions.
+     */
+    public static final int SOURCE_CLASS_POSITION = 0x00000008;
+    
+    /**
+     * The input source is a joystick.
+     * 
+     * A {@link KeyEvent} should be interpreted as a joystick button press.
+     * 
+     * A {@link MotionEvent} should be interpreted in absolute coordinates as a joystick
+     * position in normalized device-specific units nominally between -1.0 and 1.0.
+     * 
+     * Use {@link #getMotionRange} to query the range and precision of motion.
+     */
+    public static final int SOURCE_CLASS_JOYSTICK = 0x00000010;
+    
+    /**
+     * The input source is unknown.
+     */
+    public static final int SOURCE_UNKNOWN = 0x00000000;
+    
+    /**
+     * The input source is a keyboard.
+     * 
+     * @see #SOURCE_CLASS_BUTTON
+     */
+    public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;
+    
+    /**
+     * The input source is a DPad.
+     * 
+     * @see #SOURCE_CLASS_BUTTON
+     */
+    public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;
+    
+    /**
+     * The input source is a gamepad.
+     * 
+     * @see #SOURCE_CLASS_BUTTON
+     */
+    public static final int SOURCE_GAMEPAD = 0x00000400 | SOURCE_CLASS_BUTTON;
+    
+    /**
+     * The input source is a touch screen pointing device.
+     * 
+     * @see #SOURCE_CLASS_POINTER
+     */
+    public static final int SOURCE_TOUCHSCREEN = 0x00001000 | SOURCE_CLASS_POINTER;
+    
+    /**
+     * The input source is a mouse pointing device.
+     * This code is also used for other mouse-like pointing devices such as trackpads
+     * and trackpoints.
+     * 
+     * @see #SOURCE_CLASS_POINTER
+     */
+    public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER;
+    
+    /**
+     * The input source is a trackball.
+     * 
+     * @see #SOURCE_CLASS_TRACKBALL
+     */
+    public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;
+    
+    /**
+     * The input source is a touch pad or digitizer tablet that is not
+     * associated with a display (unlike {@link SOURCE_TOUCHSCREEN}).
+     * 
+     * @see #SOURCE_CLASS_POSITION
+     */
+    public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
+
+    /**
+     * The input source is a joystick mounted on the left or is a standalone joystick.
+     * 
+     * @see #SOURCE_CLASS_JOYSTICK
+     */
+    public static final int SOURCE_JOYSTICK_LEFT = 0x01000000 | SOURCE_CLASS_JOYSTICK;
+    
+    /**
+     * The input source is a joystick mounted on the right.
+     * 
+     * @see #SOURCE_CLASS_JOYSTICK
+     */
+    public static final int SOURCE_JOYSTICK_RIGHT = 0x02000000 | SOURCE_CLASS_JOYSTICK;
+
+    /*
+    public static final int MOTION_RANGE_X = 0;
+    public static final int MOTION_RANGE_Y = 1;
+    public static final int MOTION_RANGE_PRESSURE = 2;
+    public static final int MOTION_RANGE_SIZE = 3;
+    public static final int MOTION_RANGE_TOUCH_MAJOR = 4;
+    public static final int MOTION_RANGE_TOUCH_MINOR = 5;
+    public static final int MOTION_RANGE_TOOL_MAJOR = 6;
+    public static final int MOTION_RANGE_TOOL_MINOR = 7;
+    public static final int MOTION_RANGE_ORIENTATION = 8;
+    
+    public static InputDevice getDevice(int id) {
+    }
+    */
+    
+    /**
+     * Gets the name of this input device.
+     * @return The input device name.
+     */
+    public String getName() {
+        return mName;
+    }
+    
+    /**
+     * Gets the input sources supported by this input device as a combined bitfield.
+     * @return The supported input sources.
+     */
+    public int getSources() {
+        return mSources;
+    }
+    
+    /**
+     * Gets the key character map associated with this input device.
+     * @return The key character map.
+     */
+    public KeyCharacterMap getKeyCharacterMap() {
+        return KeyCharacterMap.load(mId);
+    }
+    
+    /*
+    
+    public MotionRange getMotionRange(int range) {
+    }
+    
+    public boolean hasKeyCode(int keyCode) {
+    }
+    
+    public static final class MotionRange {
+        public float min;
+        public float max;
+        public float range;
+        public float flat;
+        public float fuzz;
+    }*/
+}
diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java
new file mode 100755
index 0000000..445a980
--- /dev/null
+++ b/core/java/android/view/InputEvent.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.os.Parcelable;
+
+/**
+ * Common base class for input events.
+ */
+public abstract class InputEvent implements Parcelable {
+    protected int mDeviceId;
+    protected int mSource;
+    
+    /*package*/ InputEvent() {
+    }
+
+    /**
+     * Gets the id for the device that this event came from.  An id of
+     * zero indicates that the event didn't come from a physical device
+     * and maps to the default keymap.  The other numbers are arbitrary and
+     * you shouldn't depend on the values.
+     * 
+     * @return The device id.
+     * @see InputDevice#getDevice
+     */
+    public final int getDeviceId() {
+        return mDeviceId;
+    }
+    
+    /**
+     * Gets the source of the event.
+     * 
+     * @return The event source or {@link InputDevice.SOURCE_UNKNOWN} if unknown.
+     * @see InputDevice#getSourceInfo
+     */
+    public final int getSource() {
+        return mSource;
+    }
+    
+    /**
+     * Modifies the source of the event.
+     * @param source The source.
+     * 
+     * @hide
+     */
+    public final void setSource(int source) {
+        mSource = source;
+    }
+}
diff --git a/core/java/android/view/InputHandler.java b/core/java/android/view/InputHandler.java
index 816f622..41a152d 100644
--- a/core/java/android/view/InputHandler.java
+++ b/core/java/android/view/InputHandler.java
@@ -32,22 +32,12 @@
     public void handleKey(KeyEvent event, Runnable finishedCallback);
     
     /**
-     * Handle a touch event.
+     * Handle a motion event.
      * It is the responsibility of the callee to ensure that the finished callback is
      * eventually invoked when the event processing is finished and the input system
      * can send the next event.
      * @param event The motion event data.
      * @param finishedCallback The callback to invoke when event processing is finished.
      */
-    public void handleTouch(MotionEvent event, Runnable finishedCallback);
-    
-    /**
-     * Handle a trackball event.
-     * It is the responsibility of the callee to ensure that the finished callback is
-     * eventually invoked when the event processing is finished and the input system
-     * can send the next event.
-     * @param event The motion event data.
-     * @param finishedCallback The callback to invoke when event processing is finished.
-     */
-    public void handleTrackball(MotionEvent event, Runnable finishedCallback);
+    public void handleMotion(MotionEvent event, Runnable finishedCallback);
 }
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index 7feee38..997246f 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -26,6 +26,8 @@
 public final class InputQueue {
     private static final String TAG = "InputQueue";
     
+    private static final boolean DEBUG = false;
+    
     public static interface Callback {
         void onInputQueueCreated(InputQueue queue);
         void onInputQueueDestroyed(InputQueue queue);
@@ -33,15 +35,6 @@
 
     final InputChannel mChannel;
     
-    // Describes the interpretation of an event.
-    // XXX This concept is tentative.  See comments in android/input.h.
-    /** @hide */
-    public static final int INPUT_EVENT_NATURE_KEY = 1;
-    /** @hide */
-    public static final int INPUT_EVENT_NATURE_TOUCH = 2;
-    /** @hide */
-    public static final int INPUT_EVENT_NATURE_TRACKBALL = 3;
-    
     private static Object sLock = new Object();
     
     private static native void nativeRegisterInputChannel(InputChannel inputChannel,
@@ -79,7 +72,10 @@
         }
         
         synchronized (sLock) {
-            Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
+            if (DEBUG) {
+                Slog.d(TAG, "Registering input channel '" + inputChannel + "'");
+            }
+            
             nativeRegisterInputChannel(inputChannel, inputHandler, messageQueue);
         }
     }
@@ -96,35 +92,26 @@
         }
 
         synchronized (sLock) {
-            Slog.d(TAG, "Unregistering input channel '" + inputChannel + "'");
+            if (DEBUG) {
+                Slog.d(TAG, "Unregistering input channel '" + inputChannel + "'");
+            }
+            
             nativeUnregisterInputChannel(inputChannel);
         }
     }
     
     @SuppressWarnings("unused")
     private static void dispatchKeyEvent(InputHandler inputHandler,
-            KeyEvent event, int nature, long finishedToken) {
+            KeyEvent event, long finishedToken) {
         Runnable finishedCallback = new FinishedCallback(finishedToken);
-        
-        if (nature == INPUT_EVENT_NATURE_KEY) {
-            inputHandler.handleKey(event, finishedCallback);
-        } else {
-            Slog.d(TAG, "Unsupported nature for key event: " + nature);
-        }
+        inputHandler.handleKey(event, finishedCallback);
     }
 
     @SuppressWarnings("unused")
     private static void dispatchMotionEvent(InputHandler inputHandler,
-            MotionEvent event, int nature, long finishedToken) {
+            MotionEvent event, long finishedToken) {
         Runnable finishedCallback = new FinishedCallback(finishedToken);
-        
-        if (nature == INPUT_EVENT_NATURE_TOUCH) {
-            inputHandler.handleTouch(event, finishedCallback);
-        } else if (nature == INPUT_EVENT_NATURE_TRACKBALL) {
-            inputHandler.handleTrackball(event, finishedCallback);
-        } else {
-            Slog.d(TAG, "Unsupported nature for motion event: " + nature);
-        }
+        inputHandler.handleMotion(event, finishedCallback);
     }
     
     // TODO consider recycling finished callbacks when done
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 25958aa..9981d87 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -26,6 +26,9 @@
 import java.lang.Character;
 import java.lang.ref.WeakReference;
 
+/**
+ * Describes the keys provided by a device and their associated labels.
+ */
 public class KeyCharacterMap
 {
     /**
@@ -59,6 +62,11 @@
     private static SparseArray<WeakReference<KeyCharacterMap>> sInstances 
         = new SparseArray<WeakReference<KeyCharacterMap>>();
 
+    /**
+     * Loads the key character maps for the keyboard with the specified device id.
+     * @param keyboard The device id of the keyboard.
+     * @return The associated key character map.
+     */
     public static KeyCharacterMap load(int keyboard)
     {
         synchronized (sLock) {
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 9c05008..dd0d21a3 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -26,7 +26,7 @@
 /**
  * Contains constants for key events.
  */
-public class KeyEvent implements Parcelable {
+public class KeyEvent extends InputEvent implements Parcelable {
     // key codes
     public static final int KEYCODE_UNKNOWN         = 0;
     public static final int KEYCODE_SOFT_LEFT       = 1;
@@ -349,7 +349,6 @@
     private int mKeyCode;
     private int mScanCode;
     private int mRepeatCount;
-    private int mDeviceId;
     private int mFlags;
     private long mDownTime;
     private long mEventTime;
@@ -484,19 +483,19 @@
      * @param repeat A repeat count for down events (> 0 if this is after the
      * initial down) or event count for multiple events.
      * @param metaState Flags indicating which meta keys are currently pressed.
-     * @param device The device ID that generated the key event.
+     * @param deviceId The device ID that generated the key event.
      * @param scancode Raw device scan code of the event.
      */
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState,
-                    int device, int scancode) {
+                    int deviceId, int scancode) {
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
         mMetaState = metaState;
-        mDeviceId = device;
+        mDeviceId = deviceId;
         mScanCode = scancode;
     }
 
@@ -513,44 +512,79 @@
      * @param repeat A repeat count for down events (> 0 if this is after the
      * initial down) or event count for multiple events.
      * @param metaState Flags indicating which meta keys are currently pressed.
-     * @param device The device ID that generated the key event.
+     * @param deviceId The device ID that generated the key event.
      * @param scancode Raw device scan code of the event.
      * @param flags The flags for this key event
      */
     public KeyEvent(long downTime, long eventTime, int action,
                     int code, int repeat, int metaState,
-                    int device, int scancode, int flags) {
+                    int deviceId, int scancode, int flags) {
         mDownTime = downTime;
         mEventTime = eventTime;
         mAction = action;
         mKeyCode = code;
         mRepeatCount = repeat;
         mMetaState = metaState;
-        mDeviceId = device;
+        mDeviceId = deviceId;
         mScanCode = scancode;
         mFlags = flags;
     }
 
     /**
+     * Create a new key event.
+     * 
+     * @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
+     * at which this key code originally went down.
+     * @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
+     * at which this event happened.
+     * @param action Action code: either {@link #ACTION_DOWN},
+     * {@link #ACTION_UP}, or {@link #ACTION_MULTIPLE}.
+     * @param code The key code.
+     * @param repeat A repeat count for down events (> 0 if this is after the
+     * initial down) or event count for multiple events.
+     * @param metaState Flags indicating which meta keys are currently pressed.
+     * @param deviceId The device ID that generated the key event.
+     * @param scancode Raw device scan code of the event.
+     * @param flags The flags for this key event
+     * @param source The input source such as {@link InputDevice#SOURCE_KEYBOARD}.
+     */
+    public KeyEvent(long downTime, long eventTime, int action,
+                    int code, int repeat, int metaState,
+                    int deviceId, int scancode, int flags, int source) {
+        mDownTime = downTime;
+        mEventTime = eventTime;
+        mAction = action;
+        mKeyCode = code;
+        mRepeatCount = repeat;
+        mMetaState = metaState;
+        mDeviceId = deviceId;
+        mScanCode = scancode;
+        mFlags = flags;
+        mSource = source;
+    }
+
+    /**
      * Create a new key event for a string of characters.  The key code,
-     * action, and repeat could will automatically be set to
-     * {@link #KEYCODE_UNKNOWN}, {@link #ACTION_MULTIPLE}, and 0 for you.
+     * action, repeat count and source will automatically be set to
+     * {@link #KEYCODE_UNKNOWN}, {@link #ACTION_MULTIPLE}, 0, and
+     * {@link InputDevice#SOURCE_KEYBOARD} for you.
      * 
      * @param time The time (in {@link android.os.SystemClock#uptimeMillis})
      * at which this event occured.
      * @param characters The string of characters.
-     * @param device The device ID that generated the key event.
+     * @param deviceId The device ID that generated the key event.
      * @param flags The flags for this key event
      */
-    public KeyEvent(long time, String characters, int device, int flags) {
+    public KeyEvent(long time, String characters, int deviceId, int flags) {
         mDownTime = time;
         mEventTime = time;
         mCharacters = characters;
         mAction = ACTION_MULTIPLE;
         mKeyCode = KEYCODE_UNKNOWN;
         mRepeatCount = 0;
-        mDeviceId = device;
+        mDeviceId = deviceId;
         mFlags = flags;
+        mSource = InputDevice.SOURCE_KEYBOARD;
     }
 
     /**
@@ -564,6 +598,7 @@
         mRepeatCount = origEvent.mRepeatCount;
         mMetaState = origEvent.mMetaState;
         mDeviceId = origEvent.mDeviceId;
+        mSource = origEvent.mSource;
         mScanCode = origEvent.mScanCode;
         mFlags = origEvent.mFlags;
         mCharacters = origEvent.mCharacters;
@@ -589,6 +624,7 @@
         mRepeatCount = newRepeat;
         mMetaState = origEvent.mMetaState;
         mDeviceId = origEvent.mDeviceId;
+        mSource = origEvent.mSource;
         mScanCode = origEvent.mScanCode;
         mFlags = origEvent.mFlags;
         mCharacters = origEvent.mCharacters;
@@ -642,6 +678,7 @@
         mRepeatCount = origEvent.mRepeatCount;
         mMetaState = origEvent.mMetaState;
         mDeviceId = origEvent.mDeviceId;
+        mSource = origEvent.mSource;
         mScanCode = origEvent.mScanCode;
         mFlags = origEvent.mFlags;
         // Don't copy mCharacters, since one way or the other we'll lose it
@@ -897,18 +934,6 @@
     }
 
     /**
-     * Return the id for the keyboard that this event came from.  A device
-     * id of 0 indicates the event didn't come from a physical device and
-     * maps to the default keymap.  The other numbers are arbitrary and
-     * you shouldn't depend on the values.
-     * 
-     * @see KeyCharacterMap#load
-     */
-    public final int getDeviceId() {
-        return mDeviceId;
-    }
-
-    /**
      * Renamed to {@link #getDeviceId}.
      * 
      * @hide
@@ -1204,6 +1229,7 @@
         out.writeInt(mRepeatCount);
         out.writeInt(mMetaState);
         out.writeInt(mDeviceId);
+        out.writeInt(mSource);
         out.writeInt(mScanCode);
         out.writeInt(mFlags);
         out.writeLong(mDownTime);
@@ -1216,6 +1242,7 @@
         mRepeatCount = in.readInt();
         mMetaState = in.readInt();
         mDeviceId = in.readInt();
+        mSource = in.readInt();
         mScanCode = in.readInt();
         mFlags = in.readInt();
         mDownTime = in.readLong();
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ae8c21d..0015db0 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -19,16 +19,17 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
-import android.util.Log;
 
 /**
  * Object used to report movement (mouse, pen, finger, trackball) events.  This
  * class may hold either absolute or relative movements, depending on what
  * it is being used for.
+ * 
+ * Refer to {@link InputDevice} for information about how different kinds of
+ * input devices and sources represent pointer coordinates.
  */
-public final class MotionEvent implements Parcelable {
+public final class MotionEvent extends InputEvent implements Parcelable {
     private static final long MS_PER_NS = 1000000;
-    static final boolean DEBUG_POINTERS = false;
     
     /**
      * Bit mask of the parts of the action code that are the action itself.
@@ -189,22 +190,52 @@
     static public final int SAMPLE_Y = 1;
     
     /**
-     * Offset for the sample's X coordinate.
+     * Offset for the sample's pressure.
      * @hide
      */
     static public final int SAMPLE_PRESSURE = 2;
     
     /**
-     * Offset for the sample's X coordinate.
+     * Offset for the sample's size
      * @hide
      */
     static public final int SAMPLE_SIZE = 3;
     
     /**
+     * Offset for the sample's touch major axis length.
+     * @hide
+     */
+    static public final int SAMPLE_TOUCH_MAJOR = 4;
+
+    /**
+     * Offset for the sample's touch minor axis length.
+     * @hide
+     */
+    static public final int SAMPLE_TOUCH_MINOR = 5;
+    
+    /**
+     * Offset for the sample's tool major axis length.
+     * @hide
+     */
+    static public final int SAMPLE_TOOL_MAJOR = 6;
+
+    /**
+     * Offset for the sample's tool minor axis length.
+     * @hide
+     */
+    static public final int SAMPLE_TOOL_MINOR = 7;
+    
+    /**
+     * Offset for the sample's orientation.
+     * @hide
+     */
+    static public final int SAMPLE_ORIENTATION = 8;
+
+    /**
      * Number of data items for each sample.
      * @hide
      */
-    static public final int NUM_SAMPLE_DATA = 4;
+    static public final int NUM_SAMPLE_DATA = 9;
     
     /**
      * Number of possible pointers.
@@ -225,7 +256,6 @@
     private float mYOffset;
     private float mXPrecision;
     private float mYPrecision;
-    private int mDeviceId;
     private int mEdgeFlags;
     private int mMetaState;
     
@@ -298,18 +328,16 @@
      * 
      * @param downTime The time (in ms) when the user originally pressed down to start 
      * a stream of position events.  This must be obtained from {@link SystemClock#uptimeMillis()}.
-     * @param eventTime  The the time (in ms) when this specific event was generated.  This 
+     * @param eventTime The the time (in ms) when this specific event was generated.  This 
      * must be obtained from {@link SystemClock#uptimeMillis()}.
-     * @param eventTimeNano  The the time (in ns) when this specific event was generated.  This 
-     * must be obtained from {@link System#nanoTime()}.
      * @param action The kind of action being performed -- one of either
      * {@link #ACTION_DOWN}, {@link #ACTION_MOVE}, {@link #ACTION_UP}, or
      * {@link #ACTION_CANCEL}.
      * @param pointers The number of points that will be in this event.
-     * @param inPointerIds An array of <em>pointers</em> values providing
+     * @param pointerIds An array of <em>pointers</em> values providing
      * an identifier for each pointer.
-     * @param inData An array of <em>pointers*NUM_SAMPLE_DATA</em> of initial
-     * data samples for the event.
+     * @param pointerCoords An array of <em>pointers</em> values providing
+     * a {@link PointerCoords} coordinate object for each pointer.
      * @param metaState The state of any meta / modifier keys that were in effect when
      * the event was generated.
      * @param xPrecision The precision of the X coordinate being reported.
@@ -319,14 +347,15 @@
      * numbers are arbitrary and you shouldn't depend on the values.
      * @param edgeFlags A bitfield indicating which edges, if any, where touched by this
      * MotionEvent.
-     *
-     * @hide
+     * @param source The source of this event.
      */
-    static public MotionEvent obtainNano(long downTime, long eventTime, long eventTimeNano,
-            int action, int pointers, int[] inPointerIds, float[] inData, int metaState,
-            float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
+    static public MotionEvent obtain(long downTime, long eventTime,
+            int action, int pointers, int[] pointerIds, PointerCoords[] pointerCoords,
+            int metaState, float xPrecision, float yPrecision, int deviceId,
+            int edgeFlags, int source) {
         MotionEvent ev = obtain(pointers, 1);
         ev.mDeviceId = deviceId;
+        ev.mSource = source;
         ev.mEdgeFlags = edgeFlags;
         ev.mDownTimeNano = downTime * MS_PER_NS;
         ev.mAction = action;
@@ -342,26 +371,11 @@
         ev.mLastDataSampleIndex = 0;
         ev.mLastEventTimeNanoSampleIndex = 0;
         
-        System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers);
+        System.arraycopy(pointerIds, 0, ev.mPointerIdentifiers, 0, pointers);
         
-        ev.mEventTimeNanoSamples[0] = eventTimeNano;
+        ev.mEventTimeNanoSamples[0] = eventTime * MS_PER_NS;
         
-        System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA);
-
-        if (DEBUG_POINTERS) {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("New:");
-            for (int i = 0; i < pointers; i++) {
-                sb.append(" #");
-                sb.append(ev.getPointerId(i));
-                sb.append("(");
-                sb.append(ev.getX(i));
-                sb.append(",");
-                sb.append(ev.getY(i));
-                sb.append(")");
-            }
-            Log.v("MotionEvent", sb.toString());
-        }
+        ev.setPointerCoordsAtSampleIndex(0, pointerCoords);
         
         return ev;
     }
@@ -402,6 +416,7 @@
             float xPrecision, float yPrecision, int deviceId, int edgeFlags) {
         MotionEvent ev = obtain(1, 1);
         ev.mDeviceId = deviceId;
+        ev.mSource = InputDevice.SOURCE_UNKNOWN;
         ev.mEdgeFlags = edgeFlags;
         ev.mDownTimeNano = downTime * MS_PER_NS;
         ev.mAction = action;
@@ -421,11 +436,7 @@
         
         ev.mEventTimeNanoSamples[0] = eventTime * MS_PER_NS;
         
-        float[] dataSamples = ev.mDataSamples;
-        dataSamples[SAMPLE_X] = x;
-        dataSamples[SAMPLE_Y] = y;
-        dataSamples[SAMPLE_PRESSURE] = pressure;
-        dataSamples[SAMPLE_SIZE] = size;
+        ev.setPointerCoordsAtSampleIndex(0, x, y, pressure, size);
         return ev;
     }
 
@@ -501,6 +512,7 @@
     static public MotionEvent obtain(MotionEvent o) {
         MotionEvent ev = obtain(o.mNumPointers, o.mNumSamples);
         ev.mDeviceId = o.mDeviceId;
+        ev.mSource = o.mSource;
         ev.mEdgeFlags = o.mEdgeFlags;
         ev.mDownTimeNano = o.mDownTimeNano;
         ev.mAction = o.mAction;
@@ -531,6 +543,7 @@
     static public MotionEvent obtainNoHistory(MotionEvent o) {
         MotionEvent ev = obtain(o.mNumPointers, 1);
         ev.mDeviceId = o.mDeviceId;
+        ev.mSource = o.mSource;
         ev.mEdgeFlags = o.mEdgeFlags;
         ev.mDownTimeNano = o.mDownTimeNano;
         ev.mAction = o.mAction;
@@ -602,6 +615,10 @@
             history[i + SAMPLE_Y] *= scale;
             // no need to scale pressure
             history[i + SAMPLE_SIZE] *= scale;    // TODO: square this?
+            history[i + SAMPLE_TOUCH_MAJOR] *= scale;
+            history[i + SAMPLE_TOUCH_MINOR] *= scale;
+            history[i + SAMPLE_TOOL_MAJOR] *= scale;
+            history[i + SAMPLE_TOOL_MINOR] *= scale;
         }
     }
 
@@ -696,6 +713,46 @@
     public final float getSize() {
         return mDataSamples[mLastDataSampleIndex + SAMPLE_SIZE];
     }
+    
+    /**
+     * {@link #getTouchMajor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getTouchMajor() {
+        return mDataSamples[mLastDataSampleIndex + SAMPLE_TOUCH_MAJOR];
+    }
+
+    /**
+     * {@link #getTouchMinor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getTouchMinor() {
+        return mDataSamples[mLastDataSampleIndex + SAMPLE_TOUCH_MINOR];
+    }
+    
+    /**
+     * {@link #getToolMajor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getToolMajor() {
+        return mDataSamples[mLastDataSampleIndex + SAMPLE_TOOL_MAJOR];
+    }
+
+    /**
+     * {@link #getToolMinor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getToolMinor() {
+        return mDataSamples[mLastDataSampleIndex + SAMPLE_TOOL_MINOR];
+    }
+    
+    /**
+     * {@link #getOrientation(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getOrientation() {
+        return mDataSamples[mLastDataSampleIndex + SAMPLE_ORIENTATION];
+    }
 
     /**
      * The number of pointers of data contained in this event.  Always
@@ -796,6 +853,93 @@
         return mDataSamples[mLastDataSampleIndex
                             + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_SIZE];
     }
+    
+    /**
+     * Returns the length of the major axis of an ellipse that describes the touch
+     * area at the point of contact for the given pointer
+     * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+     * identifier for this index).
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     */
+    public final float getTouchMajor(int pointerIndex) {
+        return mDataSamples[mLastDataSampleIndex
+                            + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_TOUCH_MAJOR];
+    }
+    
+    /**
+     * Returns the length of the minor axis of an ellipse that describes the touch
+     * area at the point of contact for the given pointer
+     * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+     * identifier for this index).
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     */
+    public final float getTouchMinor(int pointerIndex) {
+        return mDataSamples[mLastDataSampleIndex
+                            + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_TOUCH_MINOR];
+    }
+    
+    /**
+     * Returns the length of the major axis of an ellipse that describes the size of
+     * the approaching tool for the given pointer
+     * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+     * identifier for this index).
+     * The tool area represents the estimated size of the finger or pen that is
+     * touching the device independent of its actual touch area at the point of contact.
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     */
+    public final float getToolMajor(int pointerIndex) {
+        return mDataSamples[mLastDataSampleIndex
+                            + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_TOOL_MAJOR];
+    }
+    
+    /**
+     * Returns the length of the minor axis of an ellipse that describes the size of
+     * the approaching tool for the given pointer
+     * <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+     * identifier for this index).
+     * The tool area represents the estimated size of the finger or pen that is
+     * touching the device independent of its actual touch area at the point of contact.
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     */
+    public final float getToolMinor(int pointerIndex) {
+        return mDataSamples[mLastDataSampleIndex
+                            + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_TOOL_MINOR];
+    }
+    
+    /**
+     * Returns the orientation of the touch area and tool area in radians clockwise from vertical
+     * for the given pointer <em>index</em> (use {@link #getPointerId(int)} to find the pointer
+     * identifier for this index).
+     * An angle of 0 degrees indicates that the major axis of contact is oriented
+     * upwards, is perfectly circular or is of unknown orientation.  A positive angle
+     * indicates that the major axis of contact is oriented to the right.  A negative angle
+     * indicates that the major axis of contact is oriented to the left.
+     * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+     * (finger pointing fully right).
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     */
+    public final float getOrientation(int pointerIndex) {
+        return mDataSamples[mLastDataSampleIndex
+                            + pointerIndex * NUM_SAMPLE_DATA + SAMPLE_ORIENTATION];
+    }
+    
+    /**
+     * Populates a {@link PointerCoords} object with pointer coordinate data for
+     * the specified pointer index.
+     * 
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param outPointerCoords The pointer coordinate object to populate.
+     */
+    public final void getPointerCoords(int pointerIndex, PointerCoords outPointerCoords) {
+        final int sampleIndex = mLastDataSampleIndex + pointerIndex * NUM_SAMPLE_DATA;
+        getPointerCoordsAtSampleIndex(sampleIndex, outPointerCoords);
+    }
 
     /**
      * Returns the state of any meta / modifier keys that were in effect when
@@ -820,7 +964,7 @@
     public final float getRawX() {
         return mDataSamples[mLastDataSampleIndex + SAMPLE_X];
     }
-
+    
     /**
      * Returns the original raw Y coordinate of this event.  For touch
      * events on the screen, this is the original location of the event
@@ -910,6 +1054,46 @@
     }
 
     /**
+     * {@link #getHistoricalTouchMajor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getHistoricalTouchMajor(int pos) {
+        return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_TOUCH_MAJOR];
+    }
+
+    /**
+     * {@link #getHistoricalTouchMinor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getHistoricalTouchMinor(int pos) {
+        return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_TOUCH_MINOR];
+    }
+    
+    /**
+     * {@link #getHistoricalToolMajor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getHistoricalToolMajor(int pos) {
+        return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_TOOL_MAJOR];
+    }
+
+    /**
+     * {@link #getHistoricalToolMinor(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getHistoricalToolMinor(int pos) {
+        return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_TOOL_MINOR];
+    }
+    
+    /**
+     * {@link #getHistoricalOrientation(int)} for the first pointer index (may be an
+     * arbitrary pointer identifier).
+     */
+    public final float getHistoricalOrientation(int pos) {
+        return mDataSamples[pos * mNumPointers * NUM_SAMPLE_DATA + SAMPLE_ORIENTATION];
+    }
+    
+    /**
      * Returns a historical X coordinate, as per {@link #getX(int)}, that
      * occurred between this event and the previous event for the given pointer.
      * Only applies to ACTION_MOVE events.
@@ -980,17 +1164,119 @@
         return mDataSamples[(pos * mNumPointers + pointerIndex)
                             * NUM_SAMPLE_DATA + SAMPLE_SIZE];
     }
-
+    
     /**
-     * Return the id for the device that this event came from.  An id of
-     * zero indicates that the event didn't come from a physical device; other
-     * numbers are arbitrary and you shouldn't depend on the values.
+     * Returns a historical touch major axis coordinate, as per {@link #getTouchMajor(int)}, that
+     * occurred between this event and the previous event for the given pointer.
+     * Only applies to ACTION_MOVE events.
+     *
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param pos Which historical value to return; must be less than
+     * {@link #getHistorySize}
+     * 
+     * @see #getHistorySize
+     * @see #getTouchMajor
      */
-    public final int getDeviceId() {
-        return mDeviceId;
+    public final float getHistoricalTouchMajor(int pointerIndex, int pos) {
+        return mDataSamples[(pos * mNumPointers + pointerIndex)
+                            * NUM_SAMPLE_DATA + SAMPLE_TOUCH_MAJOR];
     }
 
     /**
+     * Returns a historical touch minor axis coordinate, as per {@link #getTouchMinor(int)}, that
+     * occurred between this event and the previous event for the given pointer.
+     * Only applies to ACTION_MOVE events.
+     *
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param pos Which historical value to return; must be less than
+     * {@link #getHistorySize}
+     * 
+     * @see #getHistorySize
+     * @see #getTouchMinor
+     */
+    public final float getHistoricalTouchMinor(int pointerIndex, int pos) {
+        return mDataSamples[(pos * mNumPointers + pointerIndex)
+                            * NUM_SAMPLE_DATA + SAMPLE_TOUCH_MINOR];
+    }
+
+    /**
+     * Returns a historical tool major axis coordinate, as per {@link #getToolMajor(int)}, that
+     * occurred between this event and the previous event for the given pointer.
+     * Only applies to ACTION_MOVE events.
+     *
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param pos Which historical value to return; must be less than
+     * {@link #getHistorySize}
+     * 
+     * @see #getHistorySize
+     * @see #getToolMajor
+     */
+    public final float getHistoricalToolMajor(int pointerIndex, int pos) {
+        return mDataSamples[(pos * mNumPointers + pointerIndex)
+                            * NUM_SAMPLE_DATA + SAMPLE_TOOL_MAJOR];
+    }
+
+    /**
+     * Returns a historical tool minor axis coordinate, as per {@link #getToolMinor(int)}, that
+     * occurred between this event and the previous event for the given pointer.
+     * Only applies to ACTION_MOVE events.
+     *
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param pos Which historical value to return; must be less than
+     * {@link #getHistorySize}
+     * 
+     * @see #getHistorySize
+     * @see #getToolMinor
+     */
+    public final float getHistoricalToolMinor(int pointerIndex, int pos) {
+        return mDataSamples[(pos * mNumPointers + pointerIndex)
+                            * NUM_SAMPLE_DATA + SAMPLE_TOOL_MINOR];
+    }
+
+    /**
+     * Returns a historical orientation coordinate, as per {@link #getOrientation(int)}, that
+     * occurred between this event and the previous event for the given pointer.
+     * Only applies to ACTION_MOVE events.
+     *
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param pos Which historical value to return; must be less than
+     * {@link #getHistorySize}
+     * 
+     * @see #getHistorySize
+     * @see #getOrientation
+     */
+    public final float getHistoricalOrientation(int pointerIndex, int pos) {
+        return mDataSamples[(pos * mNumPointers + pointerIndex)
+                            * NUM_SAMPLE_DATA + SAMPLE_ORIENTATION];
+    }
+
+    /**
+     * Populates a {@link PointerCoords} object with historical pointer coordinate data,
+     * as per {@link #getPointerCoords}, that occurred between this event and the previous
+     * event for the given pointer.
+     * Only applies to ACTION_MOVE events.
+     * 
+     * @param pointerIndex Raw index of pointer to retrieve.  Value may be from 0
+     * (the first pointer that is down) to {@link #getPointerCount()}-1.
+     * @param pos Which historical value to return; must be less than
+     * {@link #getHistorySize}
+     * @param outPointerCoords The pointer coordinate object to populate.
+     * 
+     * @see #getHistorySize
+     * @see #getPointerCoords
+     */
+    public final void getHistoricalPointerCoords(int pointerIndex, int pos,
+            PointerCoords outPointerCoords) {
+        final int sampleIndex = (pos * mNumPointers + pointerIndex) * NUM_SAMPLE_DATA;
+        getPointerCoordsAtSampleIndex(sampleIndex, outPointerCoords);
+    }
+    
+    /**
      * Returns a bitfield indicating which edges, if any, were touched by this
      * MotionEvent. For touch events, clients can use this to determine if the
      * user's finger was touching the edge of the display.
@@ -1044,6 +1330,54 @@
         mYOffset = y - mDataSamples[mLastDataSampleIndex + SAMPLE_Y];
     }
     
+    private final void getPointerCoordsAtSampleIndex(int sampleIndex,
+            PointerCoords outPointerCoords) {
+        outPointerCoords.x = mDataSamples[sampleIndex + SAMPLE_X] + mXOffset;
+        outPointerCoords.y = mDataSamples[sampleIndex + SAMPLE_Y] + mYOffset;
+        outPointerCoords.pressure = mDataSamples[sampleIndex + SAMPLE_PRESSURE];
+        outPointerCoords.size = mDataSamples[sampleIndex + SAMPLE_SIZE];
+        outPointerCoords.touchMajor = mDataSamples[sampleIndex + SAMPLE_TOUCH_MAJOR];
+        outPointerCoords.touchMinor = mDataSamples[sampleIndex + SAMPLE_TOUCH_MINOR];
+        outPointerCoords.toolMajor = mDataSamples[sampleIndex + SAMPLE_TOOL_MAJOR];
+        outPointerCoords.toolMinor = mDataSamples[sampleIndex + SAMPLE_TOOL_MINOR];
+        outPointerCoords.orientation = mDataSamples[sampleIndex + SAMPLE_ORIENTATION];
+    }
+    
+    private final void setPointerCoordsAtSampleIndex(int sampleIndex,
+            PointerCoords[] pointerCoords) {
+        final int numPointers = mNumPointers;
+        for (int i = 0; i < numPointers; i++) {
+            setPointerCoordsAtSampleIndex(sampleIndex, pointerCoords[i]);
+            sampleIndex += NUM_SAMPLE_DATA;
+        }
+    }
+    
+    private final void setPointerCoordsAtSampleIndex(int sampleIndex,
+            PointerCoords pointerCoords) {
+        mDataSamples[sampleIndex + SAMPLE_X] = pointerCoords.x - mXOffset;
+        mDataSamples[sampleIndex + SAMPLE_Y] = pointerCoords.y - mYOffset;
+        mDataSamples[sampleIndex + SAMPLE_PRESSURE] = pointerCoords.pressure;
+        mDataSamples[sampleIndex + SAMPLE_SIZE] = pointerCoords.size;
+        mDataSamples[sampleIndex + SAMPLE_TOUCH_MAJOR] = pointerCoords.touchMajor;
+        mDataSamples[sampleIndex + SAMPLE_TOUCH_MINOR] = pointerCoords.touchMinor;
+        mDataSamples[sampleIndex + SAMPLE_TOOL_MAJOR] = pointerCoords.toolMajor;
+        mDataSamples[sampleIndex + SAMPLE_TOOL_MINOR] = pointerCoords.toolMinor;
+        mDataSamples[sampleIndex + SAMPLE_ORIENTATION] = pointerCoords.orientation;
+    }
+    
+    private final void setPointerCoordsAtSampleIndex(int sampleIndex,
+            float x, float y, float pressure, float size) {
+        mDataSamples[sampleIndex + SAMPLE_X] = x - mXOffset;
+        mDataSamples[sampleIndex + SAMPLE_Y] = y - mYOffset;
+        mDataSamples[sampleIndex + SAMPLE_PRESSURE] = pressure;
+        mDataSamples[sampleIndex + SAMPLE_SIZE] = size;
+        mDataSamples[sampleIndex + SAMPLE_TOUCH_MAJOR] = pressure;
+        mDataSamples[sampleIndex + SAMPLE_TOUCH_MINOR] = pressure;
+        mDataSamples[sampleIndex + SAMPLE_TOOL_MAJOR] = size;
+        mDataSamples[sampleIndex + SAMPLE_TOOL_MINOR] = size;
+        mDataSamples[sampleIndex + SAMPLE_ORIENTATION] = 0;
+    }
+    
     private final void incrementNumSamplesAndReserveStorage(int dataSampleStride) {
         if (mNumSamples == mEventTimeNanoSamples.length) {
             long[] newEventTimeNanoSamples = new long[mNumSamples + BASE_AVAIL_SAMPLES];
@@ -1066,11 +1400,12 @@
 
     /**
      * Add a new movement to the batch of movements in this event.  The event's
-     * current location, position and size is updated to the new values.  In
-     * the future, the current values in the event will be added to a list of
-     * historic values.
+     * current location, position and size is updated to the new values.
+     * The current values in the event are added to a list of historical values.
+     * 
+     * Only applies to {@link ACTION_MOVE} events.
      *
-     * @param eventTime The time stamp for this data.
+     * @param eventTime The time stamp (in ms) for this data.
      * @param x The new X position.
      * @param y The new Y position.
      * @param pressure The new pressure.
@@ -1082,62 +1417,30 @@
         incrementNumSamplesAndReserveStorage(NUM_SAMPLE_DATA);
         
         mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
-        
-        float[] dataSamples = mDataSamples;
-        dataSamples[mLastDataSampleIndex + SAMPLE_X] = x - mXOffset;
-        dataSamples[mLastDataSampleIndex + SAMPLE_Y] = y - mYOffset;
-        dataSamples[mLastDataSampleIndex + SAMPLE_PRESSURE] = pressure;
-        dataSamples[mLastDataSampleIndex + SAMPLE_SIZE] = size;
+        setPointerCoordsAtSampleIndex(mLastDataSampleIndex, x, y, pressure, size);
         
         mMetaState |= metaState;
     }
 
     /**
-     * Add a new movement to the batch of movements in this event.  The
-     * input data must contain (NUM_SAMPLE_DATA * {@link #getPointerCount()})
-     * samples of data.
-     *
-     * @param eventTime The time stamp for this data.
-     * @param inData The actual data.
-     * @param metaState Meta key state.
+     * Add a new movement to the batch of movements in this event.  The event's
+     * current location, position and size is updated to the new values.
+     * The current values in the event are added to a list of historical values.
      * 
-     * @hide
+     * Only applies to {@link ACTION_MOVE} events.
+     *
+     * @param eventTime The time stamp (in ms) for this data.
+     * @param pointerCoords The new pointer coordinates.
+     * @param metaState Meta key state.
      */
-    public final void addBatch(long eventTime, float[] inData, int metaState) {
-        final int numPointers = mNumPointers;
-        final int dataSampleStride = numPointers * NUM_SAMPLE_DATA;
+    public final void addBatch(long eventTime, PointerCoords[] pointerCoords, int metaState) {
+        final int dataSampleStride = mNumPointers * NUM_SAMPLE_DATA;
         incrementNumSamplesAndReserveStorage(dataSampleStride);
         
         mEventTimeNanoSamples[mLastEventTimeNanoSampleIndex] = eventTime * MS_PER_NS;
-        
-        float[] dataSamples = mDataSamples;
-        System.arraycopy(inData, 0, dataSamples, mLastDataSampleIndex, dataSampleStride);
-
-        if (mXOffset != 0 || mYOffset != 0) {
-            int index = mLastEventTimeNanoSampleIndex;
-            for (int i = 0; i < numPointers; i++) {
-                dataSamples[index + SAMPLE_X] -= mXOffset;
-                dataSamples[index + SAMPLE_Y] -= mYOffset;
-                index += NUM_SAMPLE_DATA;
-            }
-        }
+        setPointerCoordsAtSampleIndex(mLastDataSampleIndex, pointerCoords);
         
         mMetaState |= metaState;
-        
-        if (DEBUG_POINTERS) {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("Add:");
-            for (int i = 0; i < mNumPointers; i++) {
-                sb.append(" #");
-                sb.append(getPointerId(i));
-                sb.append("(");
-                sb.append(getX(i));
-                sb.append(",");
-                sb.append(getY(i));
-                sb.append(")");
-            }
-            Log.v("MotionEvent", sb.toString());
-        }
     }
 
     @Override
@@ -1165,6 +1468,7 @@
             ev.mXPrecision = in.readFloat();
             ev.mYPrecision = in.readFloat();
             ev.mDeviceId = in.readInt();
+            ev.mSource = in.readInt();
             ev.mEdgeFlags = in.readInt();
             ev.mMetaState = in.readInt();
             
@@ -1212,6 +1516,7 @@
         out.writeFloat(mXPrecision);
         out.writeFloat(mYPrecision);
         out.writeInt(mDeviceId);
+        out.writeInt(mSource);
         out.writeInt(mEdgeFlags);
         out.writeInt(mMetaState);
         
@@ -1230,4 +1535,108 @@
             out.writeFloat(dataSamples[i]);
         }
     }
+    
+    /**
+     * Transfer object for pointer coordinates.
+     * 
+     * Objects of this type can be used to manufacture new {@link MotionEvent} objects
+     * and to query pointer coordinate information in bulk.
+     * 
+     * Refer to {@link InputDevice} for information about how different kinds of
+     * input devices and sources represent pointer coordinates.
+     */
+    public static final class PointerCoords {
+        /**
+         * The X coordinate of the pointer movement.
+         * The interpretation varies by input source and may represent the position of
+         * the center of the contact area, a relative displacement in device-specific units
+         * or something else.
+         */
+        public float x;
+        
+        /**
+         * The Y coordinate of the pointer movement.
+         * The interpretation varies by input source and may represent the position of
+         * the center of the contact area, a relative displacement in device-specific units
+         * or something else.
+         */
+        public float y;
+        
+        /**
+         * A scaled value that describes the pressure applied to the pointer.
+         * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
+         * however values higher than 1 may be generated depending on the calibration of
+         * the input device.
+         */
+        public float pressure;
+        
+        /**
+         * A scaled value of the approximate size of the pointer touch area.
+         * This represents some approximation of the area of the screen being
+         * pressed; the actual value in pixels corresponding to the
+         * touch is normalized with the device specific range of values
+         * and scaled to a value between 0 and 1. The value of size can be used to
+         * determine fat touch events.
+         */
+        public float size;
+        
+        /**
+         * The length of the major axis of an ellipse that describes the touch area at
+         * the point of contact.
+         */
+        public float touchMajor;
+        
+        /**
+         * The length of the minor axis of an ellipse that describes the touch area at
+         * the point of contact.
+         */
+        public float touchMinor;
+        
+        /**
+         * The length of the major axis of an ellipse that describes the size of
+         * the approaching tool.
+         * The tool area represents the estimated size of the finger or pen that is
+         * touching the device independent of its actual touch area at the point of contact.
+         */
+        public float toolMajor;
+        
+        /**
+         * The length of the minor axis of an ellipse that describes the size of
+         * the approaching tool.
+         * The tool area represents the estimated size of the finger or pen that is
+         * touching the device independent of its actual touch area at the point of contact.
+         */
+        public float toolMinor;
+        
+        /**
+         * The orientation of the touch area and tool area in radians clockwise from vertical.
+         * An angle of 0 degrees indicates that the major axis of contact is oriented
+         * upwards, is perfectly circular or is of unknown orientation.  A positive angle
+         * indicates that the major axis of contact is oriented to the right.  A negative angle
+         * indicates that the major axis of contact is oriented to the left.
+         * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+         * (finger pointing fully right).
+         */
+        public float orientation;
+        
+        /*
+        private static final float PI_8 = (float) (Math.PI / 8);
+        
+        public float getTouchWidth() {
+            return Math.abs(orientation) > PI_8 ? touchMajor : touchMinor;
+        }
+        
+        public float getTouchHeight() {
+            return Math.abs(orientation) > PI_8 ? touchMinor : touchMajor;
+        }
+        
+        public float getToolWidth() {
+            return Math.abs(orientation) > PI_8 ? toolMajor : toolMinor;
+        }
+        
+        public float getToolHeight() {
+            return Math.abs(orientation) > PI_8 ? toolMinor : toolMajor;
+        }
+        */
+    }
 }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 260bf7bc..7ce04cf 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -516,7 +516,7 @@
                 }
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
-                if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
+                if (Config.LOGV) Log.v(TAG, "Added window " + mWindow);
                 if (res < WindowManagerImpl.ADD_OKAY) {
                     mView = null;
                     mAttachInfo.mRootView = null;
@@ -769,7 +769,7 @@
             desiredWindowWidth = frame.width();
             desiredWindowHeight = frame.height();
             if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
-                if (DEBUG_ORIENTATION) Log.v("ViewRoot",
+                if (DEBUG_ORIENTATION) Log.v(TAG,
                         "View " + host + " resized to: " + frame);
                 fullRedrawNeeded = true;
                 mLayoutRequested = true;
@@ -833,7 +833,7 @@
             childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
 
             // Ask host how big it wants to be
-            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v("ViewRoot",
+            if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
                     "Measuring " + host + " in display " + desiredWindowWidth
                     + "x" + desiredWindowHeight + "...");
             host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -1010,7 +1010,7 @@
             }
             
             if (DEBUG_ORIENTATION) Log.v(
-                    "ViewRoot", "Relayout returned: frame=" + frame + ", surface=" + mSurface);
+                    TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);
 
             attachInfo.mWindowLeft = frame.left;
             attachInfo.mWindowTop = frame.top;
@@ -1131,7 +1131,7 @@
             mLayoutRequested = false;
             mScrollMayChange = true;
             if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(
-                "ViewRoot", "Laying out " + host + " to (" +
+                TAG, "Laying out " + host + " to (" +
                 host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
             long startTime = 0L;
             if (Config.DEBUG && ViewDebug.profileLayout) {
@@ -1260,7 +1260,7 @@
             if ((relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0
                     || mReportNextDraw) {
                 if (LOCAL_LOGV) {
-                    Log.v("ViewRoot", "FINISHED DRAWING: " + mWindowAttributes.getTitle());
+                    Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
                 }
                 mReportNextDraw = false;
                 if (mSurfaceHolder != null && mSurface.isValid()) {
@@ -1437,7 +1437,7 @@
         }
 
         if (DEBUG_ORIENTATION || DEBUG_DRAW) {
-            Log.v("ViewRoot", "Draw " + mView + "/"
+            Log.v(TAG, "Draw " + mView + "/"
                     + mWindowAttributes.getTitle()
                     + ": dirty={" + dirty.left + "," + dirty.top
                     + "," + dirty.right + "," + dirty.bottom + "} surface="
@@ -1462,12 +1462,12 @@
                 // TODO: Do this in native
                 canvas.setDensity(mDensity);
             } catch (Surface.OutOfResourcesException e) {
-                Log.e("ViewRoot", "OutOfResourcesException locking surface", e);
+                Log.e(TAG, "OutOfResourcesException locking surface", e);
                 // TODO: we should ask the window manager to do something!
                 // for now we just do nothing
                 return;
             } catch (IllegalArgumentException e) {
-                Log.e("ViewRoot", "IllegalArgumentException locking surface", e);
+                Log.e(TAG, "IllegalArgumentException locking surface", e);
                 // TODO: we should ask the window manager to do something!
                 // for now we just do nothing
                 return;
@@ -1478,7 +1478,7 @@
                     long startTime = 0L;
 
                     if (DEBUG_ORIENTATION || DEBUG_DRAW) {
-                        Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w="
+                        Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
                                 + canvas.getWidth() + ", h=" + canvas.getHeight());
                         //canvas.drawARGB(255, 255, 0, 0);
                     }
@@ -1547,7 +1547,7 @@
         }
 
         if (LOCAL_LOGV) {
-            Log.v("ViewRoot", "Surface " + surface + " unlockCanvasAndPost");
+            Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
         }
 
         if (scrolling) {
@@ -1739,7 +1739,7 @@
     }
 
     void dispatchDetachedFromWindow() {
-        if (Config.LOGV) Log.v("ViewRoot", "Detaching in " + this + " of " + mSurface);
+        if (Config.LOGV) Log.v(TAG, "Detaching in " + this + " of " + mSurface);
 
         if (mView != null) {
             mView.dispatchDetachedFromWindow();
@@ -1867,7 +1867,7 @@
             break;
         case DISPATCH_KEY:
             if (LOCAL_LOGV) Log.v(
-                "ViewRoot", "Dispatching key "
+                TAG, "Dispatching key "
                 + msg.obj + " to " + mView);
             deliverKeyEvent((KeyEvent)msg.obj, true);
             break;
@@ -1989,7 +1989,7 @@
             break;
         case DISPATCH_KEY_FROM_IME: {
             if (LOCAL_LOGV) Log.v(
-                "ViewRoot", "Dispatching key "
+                TAG, "Dispatching key "
                 + msg.obj + " from IME to " + mView);
             KeyEvent event = (KeyEvent)msg.obj;
             if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
@@ -2484,7 +2484,7 @@
         if (handled) {
             if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
-                    "ViewRoot", "Telling window manager key is finished");
+                    TAG, "Telling window manager key is finished");
                 finishKeyEvent(event);
             }
             return;
@@ -2517,10 +2517,10 @@
                 return;
             } else if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
-                        "ViewRoot", "Telling window manager key is finished");
+                        TAG, "Telling window manager key is finished");
                 finishKeyEvent(event);
             } else {
-                Log.w("ViewRoot", "handleFinishedEvent(seq=" + seq
+                Log.w(TAG, "handleFinishedEvent(seq=" + seq
                         + " handled=" + handled + " ev=" + event
                         + ") neither delivering nor finishing key");
             }
@@ -2592,7 +2592,7 @@
         } finally {
             if (sendDone) {
                 if (LOCAL_LOGV) Log.v(
-                    "ViewRoot", "Telling window manager key is finished");
+                    TAG, "Telling window manager key is finished");
                 finishKeyEvent(event);
             }
             // Let the exception fall through -- the looper will catch
@@ -2715,7 +2715,7 @@
 
     void doDie() {
         checkThread();
-        if (Config.LOGV) Log.v("ViewRoot", "DIE in " + this + " of " + mSurface);
+        if (Config.LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
         synchronized (this) {
             if (mAdded && !mFirst) {
                 int viewVisibility = mView.getVisibility();
@@ -2781,16 +2781,10 @@
             dispatchKey(event);
         }
 
-        public void handleTouch(MotionEvent event, Runnable finishedCallback) {
+        public void handleMotion(MotionEvent event, Runnable finishedCallback) {
             finishedCallback.run();
             
-            dispatchPointer(event);
-        }
-
-        public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
-            finishedCallback.run();
-            
-            dispatchTrackball(event);
+            dispatchMotion(event);
         }
     };
 
@@ -2812,10 +2806,22 @@
         msg.obj = event;
 
         if (LOCAL_LOGV) Log.v(
-            "ViewRoot", "sending key " + event + " to " + mView);
+            TAG, "sending key " + event + " to " + mView);
 
         sendMessageAtTime(msg, event.getEventTime());
     }
+    
+    public void dispatchMotion(MotionEvent event) {
+        int source = event.getSource();
+        if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+            dispatchPointer(event);
+        } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+            dispatchTrackball(event);
+        } else {
+            // TODO
+            Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
+        }
+    }
 
     public void dispatchPointer(MotionEvent event) {
         Message msg = obtainMessage(DISPATCH_POINTER);
diff --git a/core/java/com/android/internal/view/BaseInputHandler.java b/core/java/com/android/internal/view/BaseInputHandler.java
index 6fe5063..e943a7d 100644
--- a/core/java/com/android/internal/view/BaseInputHandler.java
+++ b/core/java/com/android/internal/view/BaseInputHandler.java
@@ -29,11 +29,7 @@
         finishedCallback.run();
     }
     
-    public void handleTouch(MotionEvent event, Runnable finishedCallback) {
-        finishedCallback.run();
-    }
-    
-    public void handleTrackball(MotionEvent event, Runnable finishedCallback) {
+    public void handleMotion(MotionEvent event, Runnable finishedCallback) {
         finishedCallback.run();
     }
 }
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 9f042c2..c17b504 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -196,7 +196,7 @@
 void AInputQueue::finishEvent(AInputEvent* event, bool handled) {
     bool needFinished = true;
 
-    if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
+    if (!handled && ((InputEvent*)event)->getType() == AINPUT_EVENT_TYPE_KEY
             && ((KeyEvent*)event)->hasDefaultAction()) {
         // The app didn't handle this, but it may have a default action
         // associated with it.  We need to hand this back to Java to be
@@ -767,7 +767,7 @@
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeInputQueue != NULL) {
             KeyEvent* event = new KeyEvent();
-            android_view_KeyEvent_toNative(env, eventObj, INPUT_EVENT_NATURE_KEY, event);
+            android_view_KeyEvent_toNative(env, eventObj, event);
             code->nativeInputQueue->dispatchEvent(event);
         }
     }
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 6fb3cf7..226c797 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -326,12 +326,11 @@
     //       the input handler object itself for the same reason.
 
     int32_t inputEventType = inputEvent->getType();
-    int32_t inputEventNature = inputEvent->getNature();
 
     jobject inputEventObj;
     jmethodID dispatchMethodId;
     switch (inputEventType) {
-    case INPUT_EVENT_TYPE_KEY:
+    case AINPUT_EVENT_TYPE_KEY:
 #if DEBUG_DISPATCH_CYCLE
         LOGD("channel '%s' ~ Received key event.", connection->getInputChannelName());
 #endif
@@ -340,7 +339,7 @@
         dispatchMethodId = gInputQueueClassInfo.dispatchKeyEvent;
         break;
 
-    case INPUT_EVENT_TYPE_MOTION:
+    case AINPUT_EVENT_TYPE_MOTION:
 #if DEBUG_DISPATCH_CYCLE
         LOGD("channel '%s' ~ Received motion event.", connection->getInputChannelName());
 #endif
@@ -367,7 +366,7 @@
 #endif
     env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
             dispatchMethodId, inputHandlerObjLocal, inputEventObj,
-            jint(inputEventNature), jlong(finishedToken));
+            jlong(finishedToken));
 #if DEBUG_DISPATCH_CYCLE
     LOGD("Returned from input handler.");
 #endif
@@ -471,11 +470,11 @@
 
     GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchKeyEvent, gInputQueueClassInfo.clazz,
             "dispatchKeyEvent",
-            "(Landroid/view/InputHandler;Landroid/view/KeyEvent;IJ)V");
+            "(Landroid/view/InputHandler;Landroid/view/KeyEvent;J)V");
 
     GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchMotionEvent, gInputQueueClassInfo.clazz,
             "dispatchMotionEvent",
-            "(Landroid/view/InputHandler;Landroid/view/MotionEvent;IJ)V");
+            "(Landroid/view/InputHandler;Landroid/view/MotionEvent;J)V");
     return 0;
 }
 
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 8f648f4..7e7583c 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -32,12 +32,13 @@
 
     jmethodID ctor;
 
+    jfieldID mDeviceId;
+    jfieldID mSource;
     jfieldID mMetaState;
     jfieldID mAction;
     jfieldID mKeyCode;
     jfieldID mScanCode;
     jfieldID mRepeatCount;
-    jfieldID mDeviceId;
     jfieldID mFlags;
     jfieldID mDownTime;
     jfieldID mEventTime;
@@ -56,22 +57,24 @@
             event->getMetaState(),
             event->getDeviceId(),
             event->getScanCode(),
-            event->getFlags());
+            event->getFlags(),
+            event->getSource());
 }
 
-void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature,
+void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
         KeyEvent* event) {
+    jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
+    jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
     jint metaState = env->GetIntField(eventObj, gKeyEventClassInfo.mMetaState);
     jint action = env->GetIntField(eventObj, gKeyEventClassInfo.mAction);
     jint keyCode = env->GetIntField(eventObj, gKeyEventClassInfo.mKeyCode);
     jint scanCode = env->GetIntField(eventObj, gKeyEventClassInfo.mScanCode);
     jint repeatCount = env->GetIntField(eventObj, gKeyEventClassInfo.mRepeatCount);
-    jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
     jint flags = env->GetIntField(eventObj, gKeyEventClassInfo.mFlags);
     jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime);
     jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
 
-    event->initialize(deviceId, nature, action, flags, keyCode, scanCode, metaState, repeatCount,
+    event->initialize(deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             milliseconds_to_nanoseconds(downTime),
             milliseconds_to_nanoseconds(eventTime));
 }
@@ -91,8 +94,6 @@
     { "native_hasDefaultAction", "(I)Z", (void*)native_hasDefaultAction },
 };
 
-static const char* const kKeyEventPathName = "android/view/KeyEvent";
-
 #define FIND_CLASS(var, className) \
         var = env->FindClass(className); \
         LOG_FATAL_IF(! var, "Unable to find class " className); \
@@ -107,11 +108,15 @@
         LOG_FATAL_IF(! var, "Unable to find field " fieldName);
 
 int register_android_view_KeyEvent(JNIEnv* env) {
-    FIND_CLASS(gKeyEventClassInfo.clazz, kKeyEventPathName);
+    FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
         
     GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz,
-            "<init>", "(JJIIIIIII)V");
+            "<init>", "(JJIIIIIIII)V");
 
+    GET_FIELD_ID(gKeyEventClassInfo.mDeviceId, gKeyEventClassInfo.clazz,
+            "mDeviceId", "I");
+    GET_FIELD_ID(gKeyEventClassInfo.mSource, gKeyEventClassInfo.clazz,
+            "mSource", "I");
     GET_FIELD_ID(gKeyEventClassInfo.mMetaState, gKeyEventClassInfo.clazz,
             "mMetaState", "I");
     GET_FIELD_ID(gKeyEventClassInfo.mAction, gKeyEventClassInfo.clazz,
@@ -122,8 +127,6 @@
             "mScanCode", "I");
     GET_FIELD_ID(gKeyEventClassInfo.mRepeatCount, gKeyEventClassInfo.clazz,
             "mRepeatCount", "I");
-    GET_FIELD_ID(gKeyEventClassInfo.mDeviceId, gKeyEventClassInfo.clazz,
-            "mDeviceId", "I");
     GET_FIELD_ID(gKeyEventClassInfo.mFlags, gKeyEventClassInfo.clazz,
             "mFlags", "I");
     GET_FIELD_ID(gKeyEventClassInfo.mDownTime, gKeyEventClassInfo.clazz,
@@ -134,8 +137,7 @@
             "mCharacters", "Ljava/lang/String;");
 
     return AndroidRuntime::registerNativeMethods(
-        env, kKeyEventPathName,
-        g_methods, NELEM(g_methods));
+        env, "android/view/KeyEvent", g_methods, NELEM(g_methods));
 }
 
 } // namespace android
diff --git a/core/jni/android_view_KeyEvent.h b/core/jni/android_view_KeyEvent.h
index 3c71b1a..0bd410c 100644
--- a/core/jni/android_view_KeyEvent.h
+++ b/core/jni/android_view_KeyEvent.h
@@ -27,7 +27,7 @@
 extern jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event);
 
 /* Copies the contents of a DVM KeyEvent object to a native KeyEvent instance. */
-extern void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature,
+extern void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
         KeyEvent* event);
 
 } // namespace android
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 78137e2..fe247e8 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -24,7 +24,7 @@
 #include "android_view_MotionEvent.h"
 
 // Number of float items per entry in a DVM sample data array
-#define NUM_SAMPLE_DATA 4
+#define NUM_SAMPLE_DATA 9
 
 namespace android {
 
@@ -36,13 +36,14 @@
     jmethodID obtain;
     jmethodID recycle;
 
+    jfieldID mDeviceId;
+    jfieldID mSource;
     jfieldID mDownTimeNano;
     jfieldID mAction;
     jfieldID mXOffset;
     jfieldID mYOffset;
     jfieldID mXPrecision;
     jfieldID mYPrecision;
-    jfieldID mDeviceId;
     jfieldID mEdgeFlags;
     jfieldID mMetaState;
     jfieldID mNumPointers;
@@ -70,6 +71,10 @@
         return NULL;
     }
 
+    env->SetIntField(eventObj, gMotionEventClassInfo.mDeviceId,
+            event->getDeviceId());
+    env->SetIntField(eventObj, gMotionEventClassInfo.mSource,
+            event->getSource());
     env->SetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano,
             event->getDownTime());
     env->SetIntField(eventObj, gMotionEventClassInfo.mAction,
@@ -82,8 +87,6 @@
             event->getXPrecision());
     env->SetFloatField(eventObj, gMotionEventClassInfo.mYPrecision,
             event->getYPrecision());
-    env->SetIntField(eventObj, gMotionEventClassInfo.mDeviceId,
-            event->getDeviceId());
     env->SetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags,
             event->getEdgeFlags());
     env->SetIntField(eventObj, gMotionEventClassInfo.mMetaState,
@@ -129,6 +132,11 @@
         *(destDataSamples++) = srcSamplePointerCoords->y;
         *(destDataSamples++) = srcSamplePointerCoords->pressure;
         *(destDataSamples++) = srcSamplePointerCoords->size;
+        *(destDataSamples++) = srcSamplePointerCoords->touchMajor;
+        *(destDataSamples++) = srcSamplePointerCoords->touchMinor;
+        *(destDataSamples++) = srcSamplePointerCoords->toolMajor;
+        *(destDataSamples++) = srcSamplePointerCoords->toolMinor;
+        *(destDataSamples++) = srcSamplePointerCoords->orientation;
         srcSamplePointerCoords += 1;
     }
 
@@ -142,15 +150,16 @@
     return eventObj;
 }
 
-void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature,
+void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
         MotionEvent* event) {
+    jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId);
+    jint source = env->GetIntField(eventObj, gMotionEventClassInfo.mSource);
     jlong downTimeNano = env->GetLongField(eventObj, gMotionEventClassInfo.mDownTimeNano);
     jint action = env->GetIntField(eventObj, gMotionEventClassInfo.mAction);
     jfloat xOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mXOffset);
     jfloat yOffset = env->GetFloatField(eventObj, gMotionEventClassInfo.mYOffset);
     jfloat xPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mXPrecision);
     jfloat yPrecision = env->GetFloatField(eventObj, gMotionEventClassInfo.mYPrecision);
-    jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId);
     jint edgeFlags = env->GetIntField(eventObj, gMotionEventClassInfo.mEdgeFlags);
     jint metaState = env->GetIntField(eventObj, gMotionEventClassInfo.mMetaState);
     jint numPointers = env->GetIntField(eventObj, gMotionEventClassInfo.mNumPointers);
@@ -180,9 +189,14 @@
         samplePointerCoords[j].y = *(srcDataSamples++);
         samplePointerCoords[j].pressure = *(srcDataSamples++);
         samplePointerCoords[j].size = *(srcDataSamples++);
+        samplePointerCoords[j].touchMajor = *(srcDataSamples++);
+        samplePointerCoords[j].touchMinor = *(srcDataSamples++);
+        samplePointerCoords[j].toolMajor = *(srcDataSamples++);
+        samplePointerCoords[j].toolMinor = *(srcDataSamples++);
+        samplePointerCoords[j].orientation = *(srcDataSamples++);
     }
 
-    event->initialize(deviceId, nature, action, edgeFlags, metaState,
+    event->initialize(deviceId, source, action, edgeFlags, metaState,
             xOffset, yOffset, xPrecision, yPrecision, downTimeNano, sampleEventTime,
             numPointers, pointerIdentifiers, samplePointerCoords);
 
@@ -193,6 +207,11 @@
             samplePointerCoords[j].y = *(srcDataSamples++);
             samplePointerCoords[j].pressure = *(srcDataSamples++);
             samplePointerCoords[j].size = *(srcDataSamples++);
+            samplePointerCoords[j].touchMajor = *(srcDataSamples++);
+            samplePointerCoords[j].touchMinor = *(srcDataSamples++);
+            samplePointerCoords[j].toolMajor = *(srcDataSamples++);
+            samplePointerCoords[j].toolMinor = *(srcDataSamples++);
+            samplePointerCoords[j].orientation = *(srcDataSamples++);
         }
         event->addSample(sampleEventTime, samplePointerCoords);
     }
@@ -242,6 +261,10 @@
     GET_METHOD_ID(gMotionEventClassInfo.recycle, gMotionEventClassInfo.clazz,
             "recycle", "()V");
 
+    GET_FIELD_ID(gMotionEventClassInfo.mDeviceId, gMotionEventClassInfo.clazz,
+            "mDeviceId", "I");
+    GET_FIELD_ID(gMotionEventClassInfo.mSource, gMotionEventClassInfo.clazz,
+            "mSource", "I");
     GET_FIELD_ID(gMotionEventClassInfo.mDownTimeNano, gMotionEventClassInfo.clazz,
             "mDownTimeNano", "J");
     GET_FIELD_ID(gMotionEventClassInfo.mAction, gMotionEventClassInfo.clazz,
@@ -254,8 +277,6 @@
             "mXPrecision", "F");
     GET_FIELD_ID(gMotionEventClassInfo.mYPrecision, gMotionEventClassInfo.clazz,
             "mYPrecision", "F");
-    GET_FIELD_ID(gMotionEventClassInfo.mDeviceId, gMotionEventClassInfo.clazz,
-            "mDeviceId", "I");
     GET_FIELD_ID(gMotionEventClassInfo.mEdgeFlags, gMotionEventClassInfo.clazz,
             "mEdgeFlags", "I");
     GET_FIELD_ID(gMotionEventClassInfo.mMetaState, gMotionEventClassInfo.clazz,
diff --git a/core/jni/android_view_MotionEvent.h b/core/jni/android_view_MotionEvent.h
index 03ee32f..86e4bde 100644
--- a/core/jni/android_view_MotionEvent.h
+++ b/core/jni/android_view_MotionEvent.h
@@ -27,7 +27,7 @@
 extern jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event);
 
 /* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance. */
-extern void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj, int32_t nature,
+extern void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
         MotionEvent* event);
 
 /* Recycles a DVM MotionEvent object. */
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index d322a34..5be17d3 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -60,6 +60,32 @@
 class KeyLayoutMap;
 
 /*
+ * Input device classes.
+ */
+enum {
+    /* The input device is a keyboard. */
+    INPUT_DEVICE_CLASS_KEYBOARD      = 0x00000001,
+
+    /* The input device is an alpha-numeric keyboard (not just a dial pad). */
+    INPUT_DEVICE_CLASS_ALPHAKEY      = 0x00000002,
+
+    /* The input device is a touchscreen (either single-touch or multi-touch). */
+    INPUT_DEVICE_CLASS_TOUCHSCREEN   = 0x00000004,
+
+    /* The input device is a trackball. */
+    INPUT_DEVICE_CLASS_TRACKBALL     = 0x00000008,
+
+    /* The input device is a multi-touch touchscreen. */
+    INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
+
+    /* The input device is a directional pad. */
+    INPUT_DEVICE_CLASS_DPAD          = 0x00000020,
+
+    /* The input device is a gamepad (implies keyboard). */
+    INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040
+};
+
+/*
  * Grand Central Station for events.
  *
  * The event hub aggregates input events received across all known input
diff --git a/include/ui/Input.h b/include/ui/Input.h
index a7d23d4..f069888 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -32,7 +32,7 @@
     /*
      * Private control to determine when an app is tracking a key sequence.
      */
-    KEY_EVENT_FLAG_START_TRACKING = 0x40000000
+    AKEY_EVENT_FLAG_START_TRACKING = 0x40000000
 };
 
 /*
@@ -130,6 +130,11 @@
     float y;
     float pressure;
     float size;
+    float touchMajor;
+    float touchMinor;
+    float toolMajor;
+    float toolMinor;
+    float orientation;
 };
 
 /*
@@ -143,14 +148,14 @@
 
     inline int32_t getDeviceId() const { return mDeviceId; }
 
-    inline int32_t getNature() const { return mNature; }
+    inline int32_t getSource() const { return mSource; }
     
 protected:
-    void initialize(int32_t deviceId, int32_t nature);
+    void initialize(int32_t deviceId, int32_t source);
 
 private:
     int32_t mDeviceId;
-    int32_t mNature;
+    int32_t mSource;
 };
 
 /*
@@ -160,7 +165,7 @@
 public:
     virtual ~KeyEvent() { }
 
-    virtual int32_t getType() const { return INPUT_EVENT_TYPE_KEY; }
+    virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; }
 
     inline int32_t getAction() const { return mAction; }
 
@@ -188,7 +193,7 @@
     
     void initialize(
             int32_t deviceId,
-            int32_t nature,
+            int32_t source,
             int32_t action,
             int32_t flags,
             int32_t keyCode,
@@ -216,7 +221,7 @@
 public:
     virtual ~MotionEvent() { }
 
-    virtual int32_t getType() const { return INPUT_EVENT_TYPE_MOTION; }
+    virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; }
 
     inline int32_t getAction() const { return mAction; }
 
@@ -264,6 +269,26 @@
         return getCurrentPointerCoords(pointerIndex).size;
     }
 
+    inline float getTouchMajor(size_t pointerIndex) const {
+        return getCurrentPointerCoords(pointerIndex).touchMajor;
+    }
+
+    inline float getTouchMinor(size_t pointerIndex) const {
+        return getCurrentPointerCoords(pointerIndex).touchMinor;
+    }
+
+    inline float getToolMajor(size_t pointerIndex) const {
+        return getCurrentPointerCoords(pointerIndex).toolMajor;
+    }
+
+    inline float getToolMinor(size_t pointerIndex) const {
+        return getCurrentPointerCoords(pointerIndex).toolMinor;
+    }
+
+    inline float getOrientation(size_t pointerIndex) const {
+        return getCurrentPointerCoords(pointerIndex).orientation;
+    }
+
     inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
 
     inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const {
@@ -294,9 +319,29 @@
         return getHistoricalPointerCoords(pointerIndex, historicalIndex).size;
     }
 
+    inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
+        return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMajor;
+    }
+
+    inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
+        return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMinor;
+    }
+
+    inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
+        return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMajor;
+    }
+
+    inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
+        return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMinor;
+    }
+
+    inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
+        return getHistoricalPointerCoords(pointerIndex, historicalIndex).orientation;
+    }
+
     void initialize(
             int32_t deviceId,
-            int32_t nature,
+            int32_t source,
             int32_t action,
             int32_t edgeFlags,
             int32_t metaState,
diff --git a/include/ui/InputDevice.h b/include/ui/InputDevice.h
index 4420600..3b9c70e 100644
--- a/include/ui/InputDevice.h
+++ b/include/ui/InputDevice.h
@@ -42,6 +42,7 @@
 extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
 extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
 
+
 /*
  * An input device structure tracks the state of a single input device.
  *
@@ -168,8 +169,11 @@
                 FIELD_ABS_MT_POSITION_X = 1,
                 FIELD_ABS_MT_POSITION_Y = 2,
                 FIELD_ABS_MT_TOUCH_MAJOR = 4,
-                FIELD_ABS_MT_WIDTH_MAJOR = 8,
-                FIELD_ABS_MT_TRACKING_ID = 16
+                FIELD_ABS_MT_TOUCH_MINOR = 8,
+                FIELD_ABS_MT_WIDTH_MAJOR = 16,
+                FIELD_ABS_MT_WIDTH_MINOR = 32,
+                FIELD_ABS_MT_ORIENTATION = 64,
+                FIELD_ABS_MT_TRACKING_ID = 128
             };
 
             uint32_t pointerCount;
@@ -179,7 +183,10 @@
                 int32_t absMTPositionX;
                 int32_t absMTPositionY;
                 int32_t absMTTouchMajor;
+                int32_t absMTTouchMinor;
                 int32_t absMTWidthMajor;
+                int32_t absMTWidthMinor;
+                int32_t absMTOrientation;
                 int32_t absMTTrackingId;
 
                 inline void clear() {
@@ -206,6 +213,11 @@
         int32_t y;
         int32_t pressure;
         int32_t size;
+        int32_t touchMajor;
+        int32_t touchMinor;
+        int32_t toolMajor;
+        int32_t toolMinor;
+        int32_t orientation;
     };
 
     struct TouchData {
@@ -236,6 +248,7 @@
             AbsoluteAxisInfo yAxis;
             AbsoluteAxisInfo pressureAxis;
             AbsoluteAxisInfo sizeAxis;
+            AbsoluteAxisInfo orientationAxis;
         } parameters;
 
         // The touch data of the current sample being processed.
@@ -290,6 +303,8 @@
 
             int32_t sizeOrigin;
             float sizeScale;
+
+            float orientationScale;
         } precalculated;
 
         void reset();
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index eb8f820..674852a 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -167,10 +167,10 @@
      */
     virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0;
     virtual void notifyAppSwitchComing(nsecs_t eventTime) = 0;
-    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
+    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
             uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
             int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
-    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature,
+    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
             uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags,
             uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime) = 0;
@@ -232,10 +232,10 @@
 
     virtual void notifyConfigurationChanged(nsecs_t eventTime);
     virtual void notifyAppSwitchComing(nsecs_t eventTime);
-    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
+    virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
             uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
             int32_t scanCode, int32_t metaState, nsecs_t downTime);
-    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature,
+    virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
             uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags,
             uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
@@ -281,7 +281,7 @@
 
     struct KeyEntry : EventEntry {
         int32_t deviceId;
-        int32_t nature;
+        int32_t source;
         uint32_t policyFlags;
         int32_t action;
         int32_t flags;
@@ -301,7 +301,7 @@
 
     struct MotionEntry : EventEntry {
         int32_t deviceId;
-        int32_t nature;
+        int32_t source;
         uint32_t policyFlags;
         int32_t action;
         int32_t metaState;
@@ -424,11 +424,11 @@
 
         ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime);
         KeyEntry* obtainKeyEntry(nsecs_t eventTime,
-                int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+                int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
                 int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
                 int32_t repeatCount, nsecs_t downTime);
         MotionEntry* obtainMotionEntry(nsecs_t eventTime,
-                int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+                int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
                 int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
                 nsecs_t downTime, uint32_t pointerCount,
                 const int32_t* pointerIds, const PointerCoords* pointerCoords);
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 226d1d5..31ec701 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -119,7 +119,7 @@
     };
 
     int32_t deviceId;
-    int32_t nature;
+    int32_t source;
 
     union {
         struct {
@@ -198,7 +198,7 @@
      */
     status_t publishKeyEvent(
             int32_t deviceId,
-            int32_t nature,
+            int32_t source,
             int32_t action,
             int32_t flags,
             int32_t keyCode,
@@ -216,7 +216,7 @@
      */
     status_t publishMotionEvent(
             int32_t deviceId,
-            int32_t nature,
+            int32_t source,
             int32_t action,
             int32_t edgeFlags,
             int32_t metaState,
@@ -233,7 +233,7 @@
     /* Appends a motion sample to a motion event unless already consumed.
      *
      * Returns OK on success.
-     * Returns INVALID_OPERATION if the current event is not a MOTION_EVENT_ACTION_MOVE event.
+     * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event.
      * Returns FAILED_TRANSACTION if the current event has already been consumed.
      * Returns NO_MEMORY if the buffer is full and no additional samples can be added.
      */
@@ -272,7 +272,7 @@
     status_t publishInputEvent(
             int32_t type,
             int32_t deviceId,
-            int32_t nature);
+            int32_t source);
 };
 
 /*
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 768b04e..33dd3732 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -168,12 +168,12 @@
                 device_t* device = mDevicesById[i].device;
                 if (device != NULL && (device->classes & deviceClasses) != 0) {
                     int32_t result = getScanCodeStateLocked(device, scanCode);
-                    if (result >= KEY_STATE_DOWN) {
+                    if (result >= AKEY_STATE_DOWN) {
                         return result;
                     }
                 }
             }
-            return KEY_STATE_UP;
+            return AKEY_STATE_UP;
         } else {
             device_t* device = getDevice(deviceId);
             if (device != NULL) {
@@ -181,7 +181,7 @@
             }
         }
     }
-    return KEY_STATE_UNKNOWN;
+    return AKEY_STATE_UNKNOWN;
 }
 
 int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
@@ -189,9 +189,9 @@
     memset(key_bitmask, 0, sizeof(key_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
-        return test_bit(scanCode, key_bitmask) ? KEY_STATE_DOWN : KEY_STATE_UP;
+        return test_bit(scanCode, key_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
     }
-    return KEY_STATE_UNKNOWN;
+    return AKEY_STATE_UNKNOWN;
 }
 
 int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t deviceClasses,
@@ -202,19 +202,19 @@
             device_t* device = mDevicesById[i].device;
             if (device != NULL && (device->classes & deviceClasses) != 0) {
                 int32_t result = getKeyCodeStateLocked(device, keyCode);
-                if (result >= KEY_STATE_DOWN) {
+                if (result >= AKEY_STATE_DOWN) {
                     return result;
                 }
             }
         }
-        return KEY_STATE_UP;
+        return AKEY_STATE_UP;
     } else {
         device_t* device = getDevice(deviceId);
         if (device != NULL) {
             return getKeyCodeStateLocked(device, keyCode);
         }
     }
-    return KEY_STATE_UNKNOWN;
+    return AKEY_STATE_UNKNOWN;
 }
 
 int32_t EventHub::getKeyCodeStateLocked(device_t* device, int32_t keyCode) const {
@@ -235,12 +235,12 @@
             int32_t sc = scanCodes.itemAt(i);
             //LOGI("Code %d: down=%d", sc, test_bit(sc, key_bitmask));
             if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, key_bitmask)) {
-                return KEY_STATE_DOWN;
+                return AKEY_STATE_DOWN;
             }
         }
-        return KEY_STATE_UP;
+        return AKEY_STATE_UP;
     }
-    return KEY_STATE_UNKNOWN;
+    return AKEY_STATE_UNKNOWN;
 }
 
 int32_t EventHub::getSwitchState(int32_t deviceId, int32_t deviceClasses, int32_t sw) const {
@@ -251,19 +251,19 @@
         if (deviceId == -1) {
             deviceId = mSwitches[sw];
             if (deviceId == 0) {
-                return KEY_STATE_UNKNOWN;
+                return AKEY_STATE_UNKNOWN;
             }
         }
 
         device_t* device = getDevice(deviceId);
         if (device == NULL) {
-            return KEY_STATE_UNKNOWN;
+            return AKEY_STATE_UNKNOWN;
         }
 
         return getSwitchStateLocked(device, sw);
     }
 #endif
-    return KEY_STATE_UNKNOWN;
+    return AKEY_STATE_UNKNOWN;
 }
 
 int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
@@ -271,9 +271,9 @@
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
-        return test_bit(sw, sw_bitmask) ? KEY_STATE_DOWN : KEY_STATE_UP;
+        return test_bit(sw, sw_bitmask) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
     }
-    return KEY_STATE_UNKNOWN;
+    return AKEY_STATE_UNKNOWN;
 }
 
 status_t EventHub::scancodeToKeycode(int32_t deviceId, int scancode,
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 1f19c2c..e5f014f 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -13,9 +13,9 @@
 
 // class InputEvent
 
-void InputEvent::initialize(int32_t deviceId, int32_t nature) {
+void InputEvent::initialize(int32_t deviceId, int32_t source) {
     mDeviceId = deviceId;
-    mNature = nature;
+    mSource = source;
 }
 
 // class KeyEvent
@@ -86,7 +86,7 @@
 
 void KeyEvent::initialize(
         int32_t deviceId,
-        int32_t nature,
+        int32_t source,
         int32_t action,
         int32_t flags,
         int32_t keyCode,
@@ -95,7 +95,7 @@
         int32_t repeatCount,
         nsecs_t downTime,
         nsecs_t eventTime) {
-    InputEvent::initialize(deviceId, nature);
+    InputEvent::initialize(deviceId, source);
     mAction = action;
     mFlags = flags;
     mKeyCode = keyCode;
@@ -110,7 +110,7 @@
 
 void MotionEvent::initialize(
         int32_t deviceId,
-        int32_t nature,
+        int32_t source,
         int32_t action,
         int32_t edgeFlags,
         int32_t metaState,
@@ -123,7 +123,7 @@
         size_t pointerCount,
         const int32_t* pointerIds,
         const PointerCoords* pointerCoords) {
-    InputEvent::initialize(deviceId, nature);
+    InputEvent::initialize(deviceId, source);
     mAction = action;
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
diff --git a/libs/ui/InputDevice.cpp b/libs/ui/InputDevice.cpp
index 6014017..b2a4d6c 100644
--- a/libs/ui/InputDevice.cpp
+++ b/libs/ui/InputDevice.cpp
@@ -108,7 +108,7 @@
 // --- InputDevice::KeyboardState ---
 
 void InputDevice::KeyboardState::reset() {
-    current.metaState = META_NONE;
+    current.metaState = AMETA_NONE;
     current.downTime = 0;
 }
 
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index c4ffce1..a438c69 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -245,14 +245,14 @@
 void InputDispatcher::processKeyLockedInterruptible(
         nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    LOGD("processKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
+    LOGD("processKey - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, "
             "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
-            entry->eventTime, entry->deviceId, entry->nature, entry->policyFlags, entry->action,
+            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action,
             entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
             entry->downTime);
 #endif
 
-    if (entry->action == KEY_EVENT_ACTION_DOWN && ! entry->isInjected()) {
+    if (entry->action == AKEY_EVENT_ACTION_DOWN && ! entry->isInjected()) {
         if (mKeyRepeatState.lastKeyEntry
                 && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
             // We have seen two identical key downs in a row which indicates that the device
@@ -287,7 +287,7 @@
         if (queuedEntry->type == EventEntry::TYPE_KEY) {
             KeyEntry* queuedKeyEntry = static_cast<KeyEntry*>(queuedEntry);
             if (queuedKeyEntry->deviceId == entry->deviceId
-                    && entry->action == KEY_EVENT_ACTION_UP) {
+                    && entry->action == AKEY_EVENT_ACTION_UP) {
                 resetKeyRepeatLocked();
                 return;
             }
@@ -303,7 +303,7 @@
         entry->repeatCount += 1;
     } else {
         KeyEntry* newEntry = mAllocator.obtainKeyEntry(currentTime,
-                entry->deviceId, entry->nature, policyFlags,
+                entry->deviceId, entry->source, policyFlags,
                 entry->action, entry->flags, entry->keyCode, entry->scanCode,
                 entry->metaState, entry->repeatCount + 1, entry->downTime);
 
@@ -314,16 +314,16 @@
     }
 
     if (entry->repeatCount == 1) {
-        entry->flags |= KEY_EVENT_FLAG_LONG_PRESS;
+        entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
     }
 
     mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatTimeout;
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, "
+    LOGD("processKeyRepeat - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
             "repeatCount=%d, downTime=%lld",
-            entry->eventTime, entry->deviceId, entry->nature, entry->policyFlags,
+            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
             entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
             entry->repeatCount, entry->downTime);
 #endif
@@ -334,9 +334,9 @@
 void InputDispatcher::processMotionLockedInterruptible(
         nsecs_t currentTime, MotionEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    LOGD("processMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
+    LOGD("processMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, "
             "metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld",
-            entry->eventTime, entry->deviceId, entry->nature, entry->policyFlags, entry->action,
+            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action,
             entry->metaState, entry->edgeFlags, entry->xPrecision, entry->yPrecision,
             entry->downTime);
 
@@ -357,7 +357,7 @@
 
     // Keep in mind that due to batching, it is possible for the number of samples actually
     // dispatched to change before the application finally consumed them.
-    if (entry->action == MOTION_EVENT_ACTION_MOVE) {
+    if (entry->action == AMOTION_EVENT_ACTION_MOVE) {
         LOGD("  ... Total movement samples currently batched %d ...", sampleCount);
     }
 #endif
@@ -375,7 +375,7 @@
     mCurrentInputTargetsValid = false;
     mLock.unlock();
 
-    mReusableKeyEvent.initialize(entry->deviceId, entry->nature, entry->action, entry->flags,
+    mReusableKeyEvent.initialize(entry->deviceId, entry->source, entry->action, entry->flags,
             entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
             entry->downTime, entry->eventTime);
 
@@ -404,7 +404,7 @@
     mCurrentInputTargetsValid = false;
     mLock.unlock();
 
-    mReusableMotionEvent.initialize(entry->deviceId, entry->nature, entry->action,
+    mReusableMotionEvent.initialize(entry->deviceId, entry->source, entry->action,
             entry->edgeFlags, entry->metaState,
             0, 0, entry->xPrecision, entry->yPrecision,
             entry->downTime, entry->eventTime, entry->pointerCount, entry->pointerIds,
@@ -611,11 +611,11 @@
         int32_t action = keyEntry->action;
         int32_t flags = keyEntry->flags;
         if (dispatchEntry->targetFlags & InputTarget::FLAG_CANCEL) {
-            flags |= KEY_EVENT_FLAG_CANCELED;
+            flags |= AKEY_EVENT_FLAG_CANCELED;
         }
 
         // Publish the key event.
-        status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->nature,
+        status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source,
                 action, flags, keyEntry->keyCode, keyEntry->scanCode,
                 keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                 keyEntry->eventTime);
@@ -635,10 +635,10 @@
         // Apply target flags.
         int32_t action = motionEntry->action;
         if (dispatchEntry->targetFlags & InputTarget::FLAG_OUTSIDE) {
-            action = MOTION_EVENT_ACTION_OUTSIDE;
+            action = AMOTION_EVENT_ACTION_OUTSIDE;
         }
         if (dispatchEntry->targetFlags & InputTarget::FLAG_CANCEL) {
-            action = MOTION_EVENT_ACTION_CANCEL;
+            action = AMOTION_EVENT_ACTION_CANCEL;
         }
 
         // If headMotionSample is non-NULL, then it points to the first new sample that we
@@ -652,7 +652,7 @@
 
         // Publish the motion event and the first motion sample.
         status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
-                motionEntry->nature, action, motionEntry->edgeFlags, motionEntry->metaState,
+                motionEntry->source, action, motionEntry->edgeFlags, motionEntry->metaState,
                 dispatchEntry->xOffset, dispatchEntry->yOffset,
                 motionEntry->xPrecision, motionEntry->yPrecision,
                 motionEntry->downTime, firstMotionSample->eventTime,
@@ -964,13 +964,13 @@
     } // release lock
 }
 
-void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t nature,
+void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
         uint32_t policyFlags, int32_t action, int32_t flags,
         int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    LOGD("notifyKey - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, action=0x%x, "
+    LOGD("notifyKey - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, "
             "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
-            eventTime, deviceId, nature, policyFlags, action, flags,
+            eventTime, deviceId, source, policyFlags, action, flags,
             keyCode, scanCode, metaState, downTime);
 #endif
 
@@ -980,7 +980,7 @@
 
         int32_t repeatCount = 0;
         KeyEntry* newEntry = mAllocator.obtainKeyEntry(eventTime,
-                deviceId, nature, policyFlags, action, flags, keyCode, scanCode,
+                deviceId, source, policyFlags, action, flags, keyCode, scanCode,
                 metaState, repeatCount, downTime);
 
         wasEmpty = mInboundQueue.isEmpty();
@@ -992,15 +992,15 @@
     }
 }
 
-void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t nature,
+void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
         uint32_t policyFlags, int32_t action, int32_t metaState, int32_t edgeFlags,
         uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, nature=0x%x, policyFlags=0x%x, "
+    LOGD("notifyMotion - eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, "
             "action=0x%x, metaState=0x%x, edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, "
             "downTime=%lld",
-            eventTime, deviceId, nature, policyFlags, action, metaState, edgeFlags,
+            eventTime, deviceId, source, policyFlags, action, metaState, edgeFlags,
             xPrecision, yPrecision, downTime);
     for (uint32_t i = 0; i < pointerCount; i++) {
         LOGD("  Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f",
@@ -1014,7 +1014,7 @@
         AutoMutex _l(mLock);
 
         // Attempt batching and streaming of move events.
-        if (action == MOTION_EVENT_ACTION_MOVE) {
+        if (action == AMOTION_EVENT_ACTION_MOVE) {
             // BATCHING CASE
             //
             // Try to append a move sample to the tail of the inbound queue for this device.
@@ -1033,7 +1033,7 @@
                     continue;
                 }
 
-                if (motionEntry->action != MOTION_EVENT_ACTION_MOVE
+                if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
                         || motionEntry->pointerCount != pointerCount
                         || motionEntry->isInjected()) {
                     // Last motion event in the queue for this device is not compatible for
@@ -1094,7 +1094,7 @@
 
                             MotionEntry* syncedMotionEntry = static_cast<MotionEntry*>(
                                     dispatchEntry->eventEntry);
-                            if (syncedMotionEntry->action != MOTION_EVENT_ACTION_MOVE
+                            if (syncedMotionEntry->action != AMOTION_EVENT_ACTION_MOVE
                                     || syncedMotionEntry->deviceId != deviceId
                                     || syncedMotionEntry->pointerCount != pointerCount
                                     || syncedMotionEntry->isInjected()) {
@@ -1124,7 +1124,7 @@
 
         // Just enqueue a new motion event.
         MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime,
-                deviceId, nature, policyFlags, action, metaState, edgeFlags,
+                deviceId, source, policyFlags, action, metaState, edgeFlags,
                 xPrecision, yPrecision, downTime,
                 pointerCount, pointerIds, pointerCoords);
 
@@ -1224,19 +1224,19 @@
 InputDispatcher::EventEntry* InputDispatcher::createEntryFromInputEventLocked(
         const InputEvent* event) {
     switch (event->getType()) {
-    case INPUT_EVENT_TYPE_KEY: {
+    case AINPUT_EVENT_TYPE_KEY: {
         const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
         uint32_t policyFlags = 0; // XXX consider adding a policy flag to track injected events
 
         KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
-                keyEvent->getDeviceId(), keyEvent->getNature(), policyFlags,
+                keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags,
                 keyEvent->getAction(), keyEvent->getFlags(),
                 keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), keyEvent->getDownTime());
         return keyEntry;
     }
 
-    case INPUT_EVENT_TYPE_MOTION: {
+    case AINPUT_EVENT_TYPE_MOTION: {
         const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
         uint32_t policyFlags = 0; // XXX consider adding a policy flag to track injected events
 
@@ -1245,7 +1245,7 @@
         size_t pointerCount = motionEvent->getPointerCount();
 
         MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
-                motionEvent->getDeviceId(), motionEvent->getNature(), policyFlags,
+                motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
                 motionEvent->getAction(), motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
                 motionEvent->getXPrecision(), motionEvent->getYPrecision(),
                 motionEvent->getDownTime(), uint32_t(pointerCount),
@@ -1500,14 +1500,14 @@
 }
 
 InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t eventTime,
-        int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+        int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
         int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
         int32_t repeatCount, nsecs_t downTime) {
     KeyEntry* entry = mKeyEntryPool.alloc();
     initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime);
 
     entry->deviceId = deviceId;
-    entry->nature = nature;
+    entry->source = source;
     entry->policyFlags = policyFlags;
     entry->action = action;
     entry->flags = flags;
@@ -1520,7 +1520,7 @@
 }
 
 InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime,
-        int32_t deviceId, int32_t nature, uint32_t policyFlags, int32_t action,
+        int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
         int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
         nsecs_t downTime, uint32_t pointerCount,
         const int32_t* pointerIds, const PointerCoords* pointerCoords) {
@@ -1529,7 +1529,7 @@
 
     entry->eventTime = eventTime;
     entry->deviceId = deviceId;
-    entry->nature = nature;
+    entry->source = source;
     entry->policyFlags = policyFlags;
     entry->action = action;
     entry->metaState = metaState;
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 0a21db7..cd4654a 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <limits.h>
+#include <math.h>
 
 /** Amount that trackball needs to move in order to generate a key event. */
 #define TRACKBALL_MOVEMENT_THRESHOLD 6
@@ -60,33 +61,33 @@
     int32_t mask;
     switch (keyCode) {
     case AKEYCODE_ALT_LEFT:
-        mask = META_ALT_LEFT_ON;
+        mask = AMETA_ALT_LEFT_ON;
         break;
     case AKEYCODE_ALT_RIGHT:
-        mask = META_ALT_RIGHT_ON;
+        mask = AMETA_ALT_RIGHT_ON;
         break;
     case AKEYCODE_SHIFT_LEFT:
-        mask = META_SHIFT_LEFT_ON;
+        mask = AMETA_SHIFT_LEFT_ON;
         break;
     case AKEYCODE_SHIFT_RIGHT:
-        mask = META_SHIFT_RIGHT_ON;
+        mask = AMETA_SHIFT_RIGHT_ON;
         break;
     case AKEYCODE_SYM:
-        mask = META_SYM_ON;
+        mask = AMETA_SYM_ON;
         break;
     default:
         return oldMetaState;
     }
 
     int32_t newMetaState = down ? oldMetaState | mask : oldMetaState & ~ mask
-            & ~ (META_ALT_ON | META_SHIFT_ON);
+            & ~ (AMETA_ALT_ON | AMETA_SHIFT_ON);
 
-    if (newMetaState & (META_ALT_LEFT_ON | META_ALT_RIGHT_ON)) {
-        newMetaState |= META_ALT_ON;
+    if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+        newMetaState |= AMETA_ALT_ON;
     }
 
-    if (newMetaState & (META_SHIFT_LEFT_ON | META_SHIFT_RIGHT_ON)) {
-        newMetaState |= META_SHIFT_ON;
+    if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
+        newMetaState |= AMETA_SHIFT_ON;
     }
 
     return newMetaState;
@@ -324,11 +325,26 @@
                     InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
             pointer->absMTTouchMajor = rawEvent->value;
             break;
+        case ABS_MT_TOUCH_MINOR:
+            pointer->fields |=
+                    InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
+            pointer->absMTTouchMinor = rawEvent->value;
+            break;
         case ABS_MT_WIDTH_MAJOR:
             pointer->fields |=
                     InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
             pointer->absMTWidthMajor = rawEvent->value;
             break;
+        case ABS_MT_WIDTH_MINOR:
+            pointer->fields |=
+                    InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
+            pointer->absMTWidthMinor = rawEvent->value;
+            break;
+        case ABS_MT_ORIENTATION:
+            pointer->fields |=
+                    InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_ORIENTATION;
+            pointer->absMTOrientation = rawEvent->value;
+            break;
         case ABS_MT_TRACKING_ID:
             pointer->fields |=
                     InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TRACKING_ID;
@@ -408,17 +424,17 @@
     int32_t keyEventAction;
     if (down) {
         device->keyboard.current.downTime = when;
-        keyEventAction = KEY_EVENT_ACTION_DOWN;
+        keyEventAction = AKEY_EVENT_ACTION_DOWN;
     } else {
-        keyEventAction = KEY_EVENT_ACTION_UP;
+        keyEventAction = AKEY_EVENT_ACTION_UP;
     }
 
-    int32_t keyEventFlags = KEY_EVENT_FLAG_FROM_SYSTEM;
+    int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
     if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
-        keyEventFlags = keyEventFlags | KEY_EVENT_FLAG_WOKE_HERE;
+        keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
     }
 
-    mDispatcher->notifyKey(when, device->id, INPUT_EVENT_NATURE_KEY, policyFlags,
+    mDispatcher->notifyKey(when, device->id, AINPUT_SOURCE_KEYBOARD, policyFlags,
             keyEventAction, keyEventFlags, keyCode, scanCode,
             device->keyboard.current.metaState,
             device->keyboard.current.downTime);
@@ -473,11 +489,29 @@
             continue;
         }
 
+        out->pointers[outCount].x = in->accumulator.pointers[inIndex].absMTPositionX;
+        out->pointers[outCount].y = in->accumulator.pointers[inIndex].absMTPositionY;
+
+        out->pointers[outCount].touchMajor = in->accumulator.pointers[inIndex].absMTTouchMajor;
+        out->pointers[outCount].touchMinor = (fields
+                & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
+                ? in->accumulator.pointers[inIndex].absMTTouchMinor
+                        : in->accumulator.pointers[inIndex].absMTTouchMajor;
+
+        out->pointers[outCount].toolMajor = in->accumulator.pointers[inIndex].absMTWidthMajor;
+        out->pointers[outCount].toolMinor = (fields
+                & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
+                ? in->accumulator.pointers[inIndex].absMTWidthMinor
+                        : in->accumulator.pointers[inIndex].absMTWidthMajor;
+
+        out->pointers[outCount].orientation = (fields
+                & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
+                ? in->accumulator.pointers[inIndex].absMTOrientation : 0;
+
+        // Derive an approximation of pressure and size.
         // FIXME assignment of pressure may be incorrect, probably better to let
         // pressure = touch / width.  Later on we pass width to MotionEvent as a size, which
         // isn't quite right either.  Should be using touch for that.
-        out->pointers[outCount].x = in->accumulator.pointers[inIndex].absMTPositionX;
-        out->pointers[outCount].y = in->accumulator.pointers[inIndex].absMTPositionY;
         out->pointers[outCount].pressure = in->accumulator.pointers[inIndex].absMTTouchMajor;
         out->pointers[outCount].size = in->accumulator.pointers[inIndex].absMTWidthMajor;
 
@@ -556,6 +590,11 @@
         out->pointers[0].y = in->current.y;
         out->pointers[0].pressure = in->current.pressure;
         out->pointers[0].size = in->current.size;
+        out->pointers[0].touchMajor = in->current.pressure;
+        out->pointers[0].touchMinor = in->current.pressure;
+        out->pointers[0].toolMajor = in->current.size;
+        out->pointers[0].toolMinor = in->current.size;
+        out->pointers[0].orientation = 0;
         out->idToIndex[0] = 0;
         out->idBits.markBit(0);
     }
@@ -635,8 +674,8 @@
                     device->touchScreen.currentVirtualKey.keyCode,
                     device->touchScreen.currentVirtualKey.scanCode);
 #endif
-            dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
-                    KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
+            dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_UP,
+                    AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
             return true; // consumed
         }
 
@@ -658,9 +697,9 @@
                 device->touchScreen.currentVirtualKey.keyCode,
                 device->touchScreen.currentVirtualKey.scanCode);
 #endif
-        dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_UP,
-                KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY
-                        | KEY_EVENT_FLAG_CANCELED);
+        dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_UP,
+                AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
+                        | AKEY_EVENT_FLAG_CANCELED);
         return true; // consumed
 
     default:
@@ -679,8 +718,8 @@
                         device->touchScreen.currentVirtualKey.keyCode,
                         device->touchScreen.currentVirtualKey.scanCode);
 #endif
-                dispatchVirtualKey(when, device, policyFlags, KEY_EVENT_ACTION_DOWN,
-                        KEY_EVENT_FLAG_FROM_SYSTEM | KEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
+                dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_DOWN,
+                        AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
                 return true; // consumed
             }
         }
@@ -698,15 +737,15 @@
     nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
     int32_t metaState = globalMetaState();
 
-    if (keyEventAction == KEY_EVENT_ACTION_DOWN) {
+    if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
         mPolicy->virtualKeyDownFeedback();
     }
 
     int32_t policyActions = mPolicy->interceptKey(when, device->id,
-            keyEventAction == KEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
+            keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
 
     if (applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
-        mDispatcher->notifyKey(when, device->id, INPUT_EVENT_NATURE_KEY, policyFlags,
+        mDispatcher->notifyKey(when, device->id, AINPUT_SOURCE_KEYBOARD, policyFlags,
                 keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
     }
 }
@@ -725,7 +764,7 @@
     if (currentIdBits == lastIdBits) {
         // No pointer id changes so this is a move event.
         // The dispatcher takes care of batching moves so we don't have to deal with that here.
-        int32_t motionEventAction = MOTION_EVENT_ACTION_MOVE;
+        int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE;
         dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
                 currentIdBits, motionEventAction);
     } else {
@@ -743,10 +782,10 @@
 
             int32_t motionEventAction;
             if (activeIdBits.isEmpty()) {
-                motionEventAction = MOTION_EVENT_ACTION_UP;
+                motionEventAction = AMOTION_EVENT_ACTION_UP;
             } else {
-                motionEventAction = MOTION_EVENT_ACTION_POINTER_UP
-                        | (upId << MOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+                motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP
+                        | (upId << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
             }
 
             dispatchTouch(when, device, policyFlags, & device->touchScreen.lastTouch,
@@ -761,11 +800,11 @@
 
             int32_t motionEventAction;
             if (oldActiveIdBits.isEmpty()) {
-                motionEventAction = MOTION_EVENT_ACTION_DOWN;
+                motionEventAction = AMOTION_EVENT_ACTION_DOWN;
                 device->touchScreen.downTime = when;
             } else {
-                motionEventAction = MOTION_EVENT_ACTION_POINTER_DOWN
-                        | (downId << MOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+                motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN
+                        | (downId << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
             }
 
             dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
@@ -813,11 +852,17 @@
         float size = float(touch->pointers[index].size
                 - precalculated.sizeOrigin) * precalculated.sizeScale;
 
+        float orientation = float(touch->pointers[index].orientation)
+                * precalculated.orientationScale;
+
+        bool vertical = abs(orientation) <= M_PI / 8;
+
         switch (mDisplayOrientation) {
         case InputReaderPolicyInterface::ROTATION_90: {
             float xTemp = x;
             x = y;
             y = mDisplayWidth - xTemp;
+            vertical = ! vertical;
             break;
         }
         case InputReaderPolicyInterface::ROTATION_180: {
@@ -829,16 +874,35 @@
             float xTemp = x;
             x = mDisplayHeight - y;
             y = xTemp;
+            vertical = ! vertical;
             break;
         }
         }
 
+        float touchMajor, touchMinor, toolMajor, toolMinor;
+        if (vertical) {
+            touchMajor = float(touch->pointers[index].touchMajor) * precalculated.yScale;
+            touchMinor = float(touch->pointers[index].touchMinor) * precalculated.xScale;
+            toolMajor = float(touch->pointers[index].toolMajor) * precalculated.yScale;
+            toolMinor = float(touch->pointers[index].toolMinor) * precalculated.xScale;
+        } else {
+            touchMajor = float(touch->pointers[index].touchMajor) * precalculated.xScale;
+            touchMinor = float(touch->pointers[index].touchMinor) * precalculated.yScale;
+            toolMajor = float(touch->pointers[index].toolMajor) * precalculated.xScale;
+            toolMinor = float(touch->pointers[index].toolMinor) * precalculated.yScale;
+        }
+
         pointerIds[pointerCount] = int32_t(id);
 
         pointerCoords[pointerCount].x = x;
         pointerCoords[pointerCount].y = y;
         pointerCoords[pointerCount].pressure = pressure;
         pointerCoords[pointerCount].size = size;
+        pointerCoords[pointerCount].touchMajor = touchMajor;
+        pointerCoords[pointerCount].touchMinor = touchMinor;
+        pointerCoords[pointerCount].toolMajor = toolMajor;
+        pointerCoords[pointerCount].toolMinor = toolMinor;
+        pointerCoords[pointerCount].orientation = orientation;
 
         pointerCount += 1;
     }
@@ -847,21 +911,21 @@
     // global to the event.
     // XXX Maybe we should revise the edge flags API to work on a per-pointer basis.
     int32_t motionEventEdgeFlags = 0;
-    if (motionEventAction == MOTION_EVENT_ACTION_DOWN) {
+    if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
         if (pointerCoords[0].x <= 0) {
-            motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_LEFT;
+            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
         } else if (pointerCoords[0].x >= orientedWidth) {
-            motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_RIGHT;
+            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
         }
         if (pointerCoords[0].y <= 0) {
-            motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_TOP;
+            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
         } else if (pointerCoords[0].y >= orientedHeight) {
-            motionEventEdgeFlags |= MOTION_EVENT_EDGE_FLAG_BOTTOM;
+            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
         }
     }
 
     nsecs_t downTime = device->touchScreen.downTime;
-    mDispatcher->notifyMotion(when, device->id, INPUT_EVENT_NATURE_TOUCH, policyFlags,
+    mDispatcher->notifyMotion(when, device->id, AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
             motionEventAction, globalMetaState(), motionEventEdgeFlags,
             pointerCount, pointerIds, pointerCoords,
             0, 0, downTime);
@@ -912,9 +976,9 @@
 
     int32_t motionEventAction;
     if (downChanged) {
-        motionEventAction = down ? MOTION_EVENT_ACTION_DOWN : MOTION_EVENT_ACTION_UP;
+        motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
     } else {
-        motionEventAction = MOTION_EVENT_ACTION_MOVE;
+        motionEventAction = AMOTION_EVENT_ACTION_MOVE;
     }
 
     int32_t pointerId = 0;
@@ -925,6 +989,11 @@
             ? device->trackball.accumulator.relY * device->trackball.precalculated.yScale : 0;
     pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
     pointerCoords.size = 0;
+    pointerCoords.touchMajor = 0;
+    pointerCoords.touchMinor = 0;
+    pointerCoords.toolMajor = 0;
+    pointerCoords.toolMinor = 0;
+    pointerCoords.orientation = 0;
 
     float temp;
     switch (mDisplayOrientation) {
@@ -946,8 +1015,8 @@
         break;
     }
 
-    mDispatcher->notifyMotion(when, device->id, INPUT_EVENT_NATURE_TRACKBALL, policyFlags,
-            motionEventAction, globalMetaState(), MOTION_EVENT_EDGE_FLAG_NONE,
+    mDispatcher->notifyMotion(when, device->id, AINPUT_SOURCE_TRACKBALL, policyFlags,
+            motionEventAction, globalMetaState(), AMOTION_EVENT_EDGE_FLAG_NONE,
             1, & pointerId, & pointerCoords,
             device->trackball.precalculated.xPrecision,
             device->trackball.precalculated.yPrecision,
@@ -1079,6 +1148,8 @@
                 & device->touchScreen.parameters.pressureAxis);
         configureAbsoluteAxisInfo(device, ABS_MT_WIDTH_MAJOR, "Size",
                 & device->touchScreen.parameters.sizeAxis);
+        configureAbsoluteAxisInfo(device, ABS_MT_ORIENTATION, "Orientation",
+                & device->touchScreen.parameters.orientationAxis);
     } else if (device->isSingleTouchScreen()) {
         configureAbsoluteAxisInfo(device, ABS_X, "X",
                 & device->touchScreen.parameters.xAxis);
@@ -1088,6 +1159,7 @@
                 & device->touchScreen.parameters.pressureAxis);
         configureAbsoluteAxisInfo(device, ABS_TOOL_WIDTH, "Size",
                 & device->touchScreen.parameters.sizeAxis);
+        device->touchScreen.parameters.orientationAxis.valid = false;
     }
 
     if (device->isTouchScreen()) {
@@ -1117,6 +1189,14 @@
             device->touchScreen.precalculated.sizeOrigin = 0;
             device->touchScreen.precalculated.sizeScale = 1.0f;
         }
+
+        if (device->touchScreen.parameters.orientationAxis.valid
+                && device->touchScreen.parameters.orientationAxis.maxValue > 0) {
+            device->touchScreen.precalculated.orientationScale =
+                    M_PI_4 / device->touchScreen.parameters.orientationAxis.maxValue;
+        } else {
+            device->touchScreen.precalculated.orientationScale = 0.0f;
+        }
     }
 
     if (device->isTrackball()) {
@@ -1347,7 +1427,7 @@
         AutoMutex _l(mExportedStateLock);
 
         if (mExportedVirtualScanCode == scanCode) {
-            return KEY_STATE_VIRTUAL;
+            return AKEY_STATE_VIRTUAL;
         }
     } // release exported state lock
 
@@ -1360,7 +1440,7 @@
         AutoMutex _l(mExportedStateLock);
 
         if (mExportedVirtualKeyCode == keyCode) {
-            return KEY_STATE_VIRTUAL;
+            return AKEY_STATE_VIRTUAL;
         }
     } // release exported state lock
 
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index fc83e31..cf0f63e 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -270,7 +270,7 @@
 status_t InputPublisher::publishInputEvent(
         int32_t type,
         int32_t deviceId,
-        int32_t nature) {
+        int32_t source) {
     if (mPinned) {
         LOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
                 "not yet been reset.", mChannel->getName().string());
@@ -302,13 +302,13 @@
     mSharedMessage->consumed = false;
     mSharedMessage->type = type;
     mSharedMessage->deviceId = deviceId;
-    mSharedMessage->nature = nature;
+    mSharedMessage->source = source;
     return OK;
 }
 
 status_t InputPublisher::publishKeyEvent(
         int32_t deviceId,
-        int32_t nature,
+        int32_t source,
         int32_t action,
         int32_t flags,
         int32_t keyCode,
@@ -318,15 +318,15 @@
         nsecs_t downTime,
         nsecs_t eventTime) {
 #if DEBUG_TRANSPORT_ACTIONS
-    LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, nature=%d, "
+    LOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=%d, "
             "action=%d, flags=%d, keyCode=%d, scanCode=%d, metaState=%d, repeatCount=%d,"
             "downTime=%lld, eventTime=%lld",
             mChannel->getName().string(),
-            deviceId, nature, action, flags, keyCode, scanCode, metaState, repeatCount,
+            deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             downTime, eventTime);
 #endif
 
-    status_t result = publishInputEvent(INPUT_EVENT_TYPE_KEY, deviceId, nature);
+    status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
     if (result < 0) {
         return result;
     }
@@ -344,7 +344,7 @@
 
 status_t InputPublisher::publishMotionEvent(
         int32_t deviceId,
-        int32_t nature,
+        int32_t source,
         int32_t action,
         int32_t edgeFlags,
         int32_t metaState,
@@ -358,12 +358,12 @@
         const int32_t* pointerIds,
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
-    LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, nature=%d, "
+    LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=%d, "
             "action=%d, edgeFlags=%d, metaState=%d, xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
             "pointerCount=%d",
             mChannel->getName().string(),
-            deviceId, nature, action, edgeFlags, metaState, xOffset, yOffset,
+            deviceId, source, action, edgeFlags, metaState, xOffset, yOffset,
             xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
 
@@ -373,7 +373,7 @@
         return BAD_VALUE;
     }
 
-    status_t result = publishInputEvent(INPUT_EVENT_TYPE_MOTION, deviceId, nature);
+    status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
     if (result < 0) {
         return result;
     }
@@ -399,7 +399,7 @@
     // Cache essential information about the motion event to ensure that a malicious consumer
     // cannot confuse the publisher by modifying the contents of the shared memory buffer while
     // it is being updated.
-    if (action == MOTION_EVENT_ACTION_MOVE) {
+    if (action == AMOTION_EVENT_ACTION_MOVE) {
         mMotionEventPointerCount = pointerCount;
         mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
         mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
@@ -420,7 +420,7 @@
 
     if (! mPinned || ! mMotionEventSampleDataTail) {
         LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
-                "MOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
+                "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
         return INVALID_OPERATION;
     }
 
@@ -588,7 +588,7 @@
     mSharedMessage->consumed = true;
 
     switch (mSharedMessage->type) {
-    case INPUT_EVENT_TYPE_KEY: {
+    case AINPUT_EVENT_TYPE_KEY: {
         KeyEvent* keyEvent = factory->createKeyEvent();
         if (! keyEvent) return NO_MEMORY;
 
@@ -598,7 +598,7 @@
         break;
     }
 
-    case INPUT_EVENT_TYPE_MOTION: {
+    case AINPUT_EVENT_TYPE_MOTION: {
         MotionEvent* motionEvent = factory->createMotionEvent();
         if (! motionEvent) return NO_MEMORY;
 
@@ -648,7 +648,7 @@
 void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
     keyEvent->initialize(
             mSharedMessage->deviceId,
-            mSharedMessage->nature,
+            mSharedMessage->source,
             mSharedMessage->key.action,
             mSharedMessage->key.flags,
             mSharedMessage->key.keyCode,
@@ -662,7 +662,7 @@
 void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
     motionEvent->initialize(
             mSharedMessage->deviceId,
-            mSharedMessage->nature,
+            mSharedMessage->source,
             mSharedMessage->motion.action,
             mSharedMessage->motion.edgeFlags,
             mSharedMessage->motion.metaState,
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 55504f2..3bc21fa 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -73,17 +73,17 @@
     status_t status;
 
     const int32_t deviceId = 1;
-    const int32_t nature = INPUT_EVENT_NATURE_KEY;
-    const int32_t action = KEY_EVENT_ACTION_DOWN;
-    const int32_t flags = KEY_EVENT_FLAG_FROM_SYSTEM;
+    const int32_t source = AINPUT_SOURCE_KEYBOARD;
+    const int32_t action = AKEY_EVENT_ACTION_DOWN;
+    const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
     const int32_t keyCode = AKEYCODE_ENTER;
     const int32_t scanCode = 13;
-    const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
+    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
     const int32_t repeatCount = 1;
     const nsecs_t downTime = 3;
     const nsecs_t eventTime = 4;
 
-    status = mPublisher->publishKeyEvent(deviceId, nature, action, flags,
+    status = mPublisher->publishKeyEvent(deviceId, source, action, flags,
             keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
     ASSERT_EQ(OK, status)
             << "publisher publishKeyEvent should return OK";
@@ -103,12 +103,12 @@
 
     ASSERT_TRUE(event != NULL)
             << "consumer should have returned non-NULL event";
-    ASSERT_EQ(INPUT_EVENT_TYPE_KEY, event->getType())
+    ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
             << "consumer should have returned a key event";
 
     KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
     EXPECT_EQ(deviceId, keyEvent->getDeviceId());
-    EXPECT_EQ(nature, keyEvent->getNature());
+    EXPECT_EQ(source, keyEvent->getSource());
     EXPECT_EQ(action, keyEvent->getAction());
     EXPECT_EQ(flags, keyEvent->getFlags());
     EXPECT_EQ(keyCode, keyEvent->getKeyCode());
@@ -136,10 +136,10 @@
     status_t status;
 
     const int32_t deviceId = 1;
-    const int32_t nature = INPUT_EVENT_NATURE_TOUCH;
-    const int32_t action = MOTION_EVENT_ACTION_MOVE;
-    const int32_t edgeFlags = MOTION_EVENT_EDGE_FLAG_TOP;
-    const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
+    const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    const int32_t action = AMOTION_EVENT_ACTION_MOVE;
+    const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
+    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
     const float xOffset = -10;
     const float yOffset = -20;
     const float xPrecision = 0.25;
@@ -159,10 +159,15 @@
             samplePointerCoords.editTop().y = 200 * i + j;
             samplePointerCoords.editTop().pressure = 0.5 * i + j;
             samplePointerCoords.editTop().size = 0.7 * i + j;
+            samplePointerCoords.editTop().touchMajor = 1.5 * i + j;
+            samplePointerCoords.editTop().touchMinor = 1.7 * i + j;
+            samplePointerCoords.editTop().toolMajor = 2.5 * i + j;
+            samplePointerCoords.editTop().toolMinor = 2.7 * i + j;
+            samplePointerCoords.editTop().orientation = 3.5 * i + j;
         }
     }
 
-    status = mPublisher->publishMotionEvent(deviceId, nature, action, edgeFlags,
+    status = mPublisher->publishMotionEvent(deviceId, source, action, edgeFlags,
             metaState, xOffset, yOffset, xPrecision, yPrecision,
             downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array());
     ASSERT_EQ(OK, status)
@@ -199,14 +204,14 @@
 
     ASSERT_TRUE(event != NULL)
             << "consumer should have returned non-NULL event";
-    ASSERT_EQ(INPUT_EVENT_TYPE_MOTION, event->getType())
+    ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
             << "consumer should have returned a motion event";
 
     size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
 
     MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
     EXPECT_EQ(deviceId, motionEvent->getDeviceId());
-    EXPECT_EQ(nature, motionEvent->getNature());
+    EXPECT_EQ(source, motionEvent->getSource());
     EXPECT_EQ(action, motionEvent->getAction());
     EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
     EXPECT_EQ(metaState, motionEvent->getMetaState());
@@ -241,6 +246,16 @@
                     motionEvent->getHistoricalPressure(i, sampleIndex));
             EXPECT_EQ(samplePointerCoords[offset].size,
                     motionEvent->getHistoricalSize(i, sampleIndex));
+            EXPECT_EQ(samplePointerCoords[offset].touchMajor,
+                    motionEvent->getHistoricalTouchMajor(i, sampleIndex));
+            EXPECT_EQ(samplePointerCoords[offset].touchMinor,
+                    motionEvent->getHistoricalTouchMinor(i, sampleIndex));
+            EXPECT_EQ(samplePointerCoords[offset].toolMajor,
+                    motionEvent->getHistoricalToolMajor(i, sampleIndex));
+            EXPECT_EQ(samplePointerCoords[offset].toolMinor,
+                    motionEvent->getHistoricalToolMinor(i, sampleIndex));
+            EXPECT_EQ(samplePointerCoords[offset].orientation,
+                    motionEvent->getHistoricalOrientation(i, sampleIndex));
         }
     }
 
@@ -255,6 +270,11 @@
         EXPECT_EQ(samplePointerCoords[offset].y + yOffset, motionEvent->getY(i));
         EXPECT_EQ(samplePointerCoords[offset].pressure, motionEvent->getPressure(i));
         EXPECT_EQ(samplePointerCoords[offset].size, motionEvent->getSize(i));
+        EXPECT_EQ(samplePointerCoords[offset].touchMajor, motionEvent->getTouchMajor(i));
+        EXPECT_EQ(samplePointerCoords[offset].touchMinor, motionEvent->getTouchMinor(i));
+        EXPECT_EQ(samplePointerCoords[offset].toolMajor, motionEvent->getToolMajor(i));
+        EXPECT_EQ(samplePointerCoords[offset].toolMinor, motionEvent->getToolMinor(i));
+        EXPECT_EQ(samplePointerCoords[offset].orientation, motionEvent->getOrientation(i));
     }
 
     status = mConsumer->sendFinishedSignal();
@@ -300,7 +320,7 @@
 
     const size_t pointerCount = 1;
     int32_t pointerIds[pointerCount] = { 0 };
-    PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0 } };
+    PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
 
     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerIds, pointerCoords);
@@ -381,7 +401,7 @@
     int32_t pointerIds[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, MOTION_EVENT_ACTION_DOWN,
+    status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
             0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
     ASSERT_EQ(OK, status);
 
@@ -398,7 +418,7 @@
     int32_t pointerIds[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, MOTION_EVENT_ACTION_MOVE,
+    status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
             0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
     ASSERT_EQ(OK, status);
 
@@ -425,7 +445,7 @@
     int32_t pointerIds[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, MOTION_EVENT_ACTION_MOVE,
+    status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
             0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
     ASSERT_EQ(OK, status);
 
diff --git a/native/android/input.cpp b/native/android/input.cpp
index a4dde51..4e1b6dcb 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -38,8 +38,8 @@
     return static_cast<const InputEvent*>(event)->getDeviceId();
 }
 
-int32_t AInputEvent_getNature(const AInputEvent* event) {
-    return static_cast<const InputEvent*>(event)->getNature();
+int32_t AInputEvent_getSource(const AInputEvent* event) {
+    return static_cast<const InputEvent*>(event)->getSource();
 }
 
 int32_t AKeyEvent_getAction(const AInputEvent* key_event) {
@@ -69,6 +69,7 @@
     return static_cast<const KeyEvent*>(key_event)->getDownTime();
 }
 
+
 int64_t AKeyEvent_getEventTime(const AInputEvent* key_event) {
     return static_cast<const KeyEvent*>(key_event)->getEventTime();
 }
@@ -141,6 +142,26 @@
     return static_cast<const MotionEvent*>(motion_event)->getSize(pointer_index);
 }
 
+float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getTouchMajor(pointer_index);
+}
+
+float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getTouchMinor(pointer_index);
+}
+
+float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getToolMajor(pointer_index);
+}
+
+float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getToolMinor(pointer_index);
+}
+
+float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getOrientation(pointer_index);
+}
+
 size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event) {
     return static_cast<const MotionEvent*>(motion_event)->getHistorySize();
 }
@@ -187,6 +208,37 @@
             pointer_index, history_index);
 }
 
+float AMotionEvent_getHistoricalTouchMajor(AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalTouchMajor(
+            pointer_index, history_index);
+}
+
+float AMotionEvent_getHistoricalTouchMinor(AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalTouchMinor(
+            pointer_index, history_index);
+}
+
+float AMotionEvent_getHistoricalToolMajor(AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalToolMajor(
+            pointer_index, history_index);
+}
+
+float AMotionEvent_getHistoricalToolMinor(AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalToolMinor(
+            pointer_index, history_index);
+}
+
+float AMotionEvent_getHistoricalOrientation(AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index) {
+    return static_cast<const MotionEvent*>(motion_event)->getHistoricalOrientation(
+            pointer_index, history_index);
+}
+
+
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
         ALooper_callbackFunc* callback, void* data) {
     queue->attachLooper(looper, callback, data);
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 25dd68e..ce79cd4 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -49,49 +49,21 @@
 #endif
 
 /*
- * Input device classes.
- */
-enum {
-    /* The input device is a keyboard. */
-    INPUT_DEVICE_CLASS_KEYBOARD      = 0x00000001,
-
-    /* The input device is an alpha-numeric keyboard (not just a dial pad). */
-    INPUT_DEVICE_CLASS_ALPHAKEY      = 0x00000002,
-
-    /* The input device is a touchscreen (either single-touch or multi-touch). */
-    INPUT_DEVICE_CLASS_TOUCHSCREEN   = 0x00000004,
-
-    /* The input device is a trackball. */
-    INPUT_DEVICE_CLASS_TRACKBALL     = 0x00000008,
-
-    /* The input device is a multi-touch touchscreen. */
-    INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
-
-    /* The input device is a directional pad. */
-    INPUT_DEVICE_CLASS_DPAD          = 0x00000020,
-
-    /* The input device is a gamepad (implies keyboard). */
-    INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040
-};
-
-/*
  * Key states (may be returned by queries about the current state of a
  * particular key code, scan code or switch).
- *
- * XXX should we call this BUTTON_STATE_XXX?
  */
 enum {
     /* The key state is unknown or the requested key itself is not supported. */
-    KEY_STATE_UNKNOWN = -1,
+    AKEY_STATE_UNKNOWN = -1,
 
     /* The key is up. */
-    KEY_STATE_UP = 0,
+    AKEY_STATE_UP = 0,
 
     /* The key is down. */
-    KEY_STATE_DOWN = 1,
+    AKEY_STATE_DOWN = 1,
 
     /* The key is down but is a virtual key press that is being emulated by the system. */
-    KEY_STATE_VIRTUAL = 2
+    AKEY_STATE_VIRTUAL = 2
 };
 
 /*
@@ -99,28 +71,28 @@
  */
 enum {
     /* No meta keys are pressed. */
-    META_NONE = 0,
+    AMETA_NONE = 0,
 
     /* This mask is used to check whether one of the ALT meta keys is pressed. */
-    META_ALT_ON = 0x02,
+    AMETA_ALT_ON = 0x02,
 
     /* This mask is used to check whether the left ALT meta key is pressed. */
-    META_ALT_LEFT_ON = 0x10,
+    AMETA_ALT_LEFT_ON = 0x10,
 
     /* This mask is used to check whether the right ALT meta key is pressed. */
-    META_ALT_RIGHT_ON = 0x20,
+    AMETA_ALT_RIGHT_ON = 0x20,
 
     /* This mask is used to check whether one of the SHIFT meta keys is pressed. */
-    META_SHIFT_ON = 0x01,
+    AMETA_SHIFT_ON = 0x01,
 
     /* This mask is used to check whether the left SHIFT meta key is pressed. */
-    META_SHIFT_LEFT_ON = 0x40,
+    AMETA_SHIFT_LEFT_ON = 0x40,
 
     /* This mask is used to check whether the right SHIFT meta key is pressed. */
-    META_SHIFT_RIGHT_ON = 0x80,
+    AMETA_SHIFT_RIGHT_ON = 0x80,
 
     /* This mask is used to check whether the SYM meta key is pressed. */
-    META_SYM_ON = 0x04
+    AMETA_SYM_ON = 0x04
 };
 
 /*
@@ -137,10 +109,10 @@
  */
 enum {
     /* Indicates that the input event is a key event. */
-    INPUT_EVENT_TYPE_KEY = 1,
+    AINPUT_EVENT_TYPE_KEY = 1,
 
     /* Indicates that the input event is a motion event. */
-    INPUT_EVENT_TYPE_MOTION = 2
+    AINPUT_EVENT_TYPE_MOTION = 2
 };
 
 /*
@@ -148,16 +120,16 @@
  */
 enum {
     /* The key has been pressed down. */
-    KEY_EVENT_ACTION_DOWN = 0,
+    AKEY_EVENT_ACTION_DOWN = 0,
 
     /* The key has been released. */
-    KEY_EVENT_ACTION_UP = 1,
+    AKEY_EVENT_ACTION_UP = 1,
 
     /* Multiple duplicate key events have occurred in a row, or a complex string is
      * being delivered.  The repeat_count property of the key event contains the number
      * of times the given key code should be executed.
      */
-    KEY_EVENT_ACTION_MULTIPLE = 2
+    AKEY_EVENT_ACTION_MULTIPLE = 2
 };
 
 /*
@@ -165,25 +137,25 @@
  */
 enum {
     /* This mask is set if the device woke because of this key event. */
-    KEY_EVENT_FLAG_WOKE_HERE = 0x1,
+    AKEY_EVENT_FLAG_WOKE_HERE = 0x1,
 
     /* This mask is set if the key event was generated by a software keyboard. */
-    KEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2,
+    AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2,
 
     /* This mask is set if we don't want the key event to cause us to leave touch mode. */
-    KEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4,
+    AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4,
 
     /* This mask is set if an event was known to come from a trusted part
      * of the system.  That is, the event is known to come from the user,
      * and could not have been spoofed by a third party component. */
-    KEY_EVENT_FLAG_FROM_SYSTEM = 0x8,
+    AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8,
 
     /* This mask is used for compatibility, to identify enter keys that are
      * coming from an IME whose enter key has been auto-labelled "next" or
      * "done".  This allows TextView to dispatch these as normal enter keys
      * for old applications, but still do the appropriate action when
      * receiving them. */
-    KEY_EVENT_FLAG_EDITOR_ACTION = 0x10,
+    AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10,
 
     /* When associated with up key events, this indicates that the key press
      * has been canceled.  Typically this is used with virtual touch screen
@@ -193,26 +165,26 @@
      * key.  Note that for this to work, the application can not perform an
      * action for a key until it receives an up or the long press timeout has
      * expired. */
-    KEY_EVENT_FLAG_CANCELED = 0x20,
+    AKEY_EVENT_FLAG_CANCELED = 0x20,
 
     /* This key event was generated by a virtual (on-screen) hard key area.
      * Typically this is an area of the touchscreen, outside of the regular
      * display, dedicated to "hardware" buttons. */
-    KEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40,
+    AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40,
 
     /* This flag is set for the first key repeat that occurs after the
      * long press timeout. */
-    KEY_EVENT_FLAG_LONG_PRESS = 0x80,
+    AKEY_EVENT_FLAG_LONG_PRESS = 0x80,
 
-    /* Set when a key event has KEY_EVENT_FLAG_CANCELED set because a long
+    /* Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long
      * press action was executed while it was down. */
-    KEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100,
+    AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100,
 
-    /* Set for KEY_EVENT_ACTION_UP when this event's key code is still being
+    /* Set for AKEY_EVENT_ACTION_UP when this event's key code is still being
      * tracked from its initial down.  That is, somebody requested that tracking
      * started on the key down and a long press has not caused
      * the tracking to be canceled. */
-    KEY_EVENT_FLAG_TRACKING = 0x200
+    AKEY_EVENT_FLAG_TRACKING = 0x200
 };
 
 /*
@@ -220,57 +192,57 @@
  */
 
 /* Bit shift for the action bits holding the pointer index as
- * defined by MOTION_EVENT_ACTION_POINTER_INDEX_MASK.
+ * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK.
  */
-#define MOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8
+#define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8
 
 enum {
     /* Bit mask of the parts of the action code that are the action itself.
      */
-    MOTION_EVENT_ACTION_MASK = 0xff,
+    AMOTION_EVENT_ACTION_MASK = 0xff,
 
     /* Bits in the action code that represent a pointer index, used with
-     * MOTION_EVENT_ACTION_POINTER_DOWN and MOTION_EVENT_ACTION_POINTER_UP.  Shifting
-     * down by MOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer
+     * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP.  Shifting
+     * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer
      * index where the data for the pointer going up or down can be found.
      */
-    MOTION_EVENT_ACTION_POINTER_INDEX_MASK  = 0xff00,
+    AMOTION_EVENT_ACTION_POINTER_INDEX_MASK  = 0xff00,
 
     /* A pressed gesture has started, the motion contains the initial starting location.
      */
-    MOTION_EVENT_ACTION_DOWN = 0,
+    AMOTION_EVENT_ACTION_DOWN = 0,
 
     /* A pressed gesture has finished, the motion contains the final release location
      * as well as any intermediate points since the last down or move event.
      */
-    MOTION_EVENT_ACTION_UP = 1,
+    AMOTION_EVENT_ACTION_UP = 1,
 
-    /* A change has happened during a press gesture (between MOTION_EVENT_ACTION_DOWN and
-     * MOTION_EVENT_ACTION_UP).  The motion contains the most recent point, as well as
+    /* A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and
+     * AMOTION_EVENT_ACTION_UP).  The motion contains the most recent point, as well as
      * any intermediate points since the last down or move event.
      */
-    MOTION_EVENT_ACTION_MOVE = 2,
+    AMOTION_EVENT_ACTION_MOVE = 2,
 
     /* The current gesture has been aborted.
      * You will not receive any more points in it.  You should treat this as
      * an up event, but not perform any action that you normally would.
      */
-    MOTION_EVENT_ACTION_CANCEL = 3,
+    AMOTION_EVENT_ACTION_CANCEL = 3,
 
     /* A movement has happened outside of the normal bounds of the UI element.
      * This does not provide a full gesture, but only the initial location of the movement/touch.
      */
-    MOTION_EVENT_ACTION_OUTSIDE = 4,
+    AMOTION_EVENT_ACTION_OUTSIDE = 4,
 
     /* A non-primary pointer has gone down.
-     * The bits in MOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
+     * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
      */
-    MOTION_EVENT_ACTION_POINTER_DOWN = 5,
+    AMOTION_EVENT_ACTION_POINTER_DOWN = 5,
 
     /* A non-primary pointer has gone up.
-     * The bits in MOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
+     * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed.
      */
-    MOTION_EVENT_ACTION_POINTER_UP = 6
+    AMOTION_EVENT_ACTION_POINTER_UP = 6
 };
 
 /*
@@ -278,39 +250,50 @@
  */
 enum {
     /* No edges intersected */
-    MOTION_EVENT_EDGE_FLAG_NONE = 0,
+    AMOTION_EVENT_EDGE_FLAG_NONE = 0,
 
     /* Flag indicating the motion event intersected the top edge of the screen. */
-    MOTION_EVENT_EDGE_FLAG_TOP = 0x01,
+    AMOTION_EVENT_EDGE_FLAG_TOP = 0x01,
 
     /* Flag indicating the motion event intersected the bottom edge of the screen. */
-    MOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02,
+    AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02,
 
     /* Flag indicating the motion event intersected the left edge of the screen. */
-    MOTION_EVENT_EDGE_FLAG_LEFT = 0x04,
+    AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04,
 
     /* Flag indicating the motion event intersected the right edge of the screen. */
-    MOTION_EVENT_EDGE_FLAG_RIGHT = 0x08
+    AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08
 };
 
 /*
- * Specifies the logical nature of an input event.
- * For example, the nature distinguishes between motion events that represent touches and
- * those that represent trackball moves.
+ * Input sources.
  *
- * XXX This concept is tentative.  Another idea would be to associate events with logical
- *     controllers rather than physical devices.   The interpretation of an event would
- *     be made with respect to the nature of the controller that is considered the logical
- *     source of an event.  The decoupling is beneficial since multiple physical (and virtual)
- *     devices could be responsible for producing events that would be associated with
- *     various logical controllers.  For example, the hard keyboard, on screen keyboard,
- *     and peripheral keyboard could be mapped onto a single logical "keyboard" controller
- *     (or treated independently, if desired).
+ * The appropriate interpretation for an input event depends on its source.
+ * Refer to the documentation on android.view.InputDevice for more details about input sources
+ * and their correct interpretation.
  */
 enum {
-    INPUT_EVENT_NATURE_KEY = 1,
-    INPUT_EVENT_NATURE_TOUCH = 2,
-    INPUT_EVENT_NATURE_TRACKBALL = 3
+    AINPUT_SOURCE_CLASS_MASK = 0x000000ff,
+
+    AINPUT_SOURCE_CLASS_BUTTON = 0x00000001,
+    AINPUT_SOURCE_CLASS_POINTER = 0x00000002,
+    AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004,
+    AINPUT_SOURCE_CLASS_POSITION = 0x00000008,
+    AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010,
+};
+
+enum {
+    AINPUT_SOURCE_UNKNOWN = 0x00000000,
+
+    AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON,
+    AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON,
+    AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON,
+    AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,
+    AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER,
+    AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
+    AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
+    AINPUT_SOURCE_JOYSTICK_LEFT = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
+    AINPUT_SOURCE_JOYSTICK_RIGHT = 0x02000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
 };
 
 /*
@@ -337,8 +320,8 @@
  */
 int32_t AInputEvent_getDeviceId(const AInputEvent* event);
 
-/* Get the input event nature. */
-int32_t AInputEvent_getNature(const AInputEvent* event);
+/* Get the input event source. */
+int32_t AInputEvent_getSource(const AInputEvent* event);
 
 /*** Accessors for key events only. ***/
 
@@ -466,11 +449,41 @@
  * determine fat touch events. */
 float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index);
 
+/* Get the current length of the major axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index. */
+float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index);
+
+/* Get the current length of the minor axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index. */
+float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index);
+
+/* Get the current length of the major axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact. */
+float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index);
+
+/* Get the current length of the minor axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact. */
+float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index);
+
+/* Get the current orientation of the touch area and tool area in radians clockwise from
+ * vertical for the given pointer index.
+ * An angle of 0 degrees indicates that the major axis of contact is oriented
+ * upwards, is perfectly circular or is of unknown orientation.  A positive angle
+ * indicates that the major axis of contact is oriented to the right.  A negative angle
+ * indicates that the major axis of contact is oriented to the left.
+ * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * (finger pointing fully right). */
+float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
+
 /* Get the number of historical points in this event.  These are movements that
  * have occurred between this event and the previous event.  This only applies
- * to MOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0.
+ * to AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0.
  * Historical samples are indexed from oldest to newest. */
-size_t AMotionEvent_get_history_size(const AInputEvent* motion_event);
+size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event);
 
 /* Get the time that a historical movement occurred between this event and
  * the previous event, in the java.lang.System.nanoTime() time base. */
@@ -527,6 +540,47 @@
 float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
+/* Get the historical length of the major axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index that
+ * occurred between this event and the previous motion event. */
+float AMotionEvent_getHistoricalTouchMajor(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
+
+/* Get the historical length of the minor axis of an ellipse that describes the touch area
+ * at the point of contact for the given pointer index that
+ * occurred between this event and the previous motion event. */
+float AMotionEvent_getHistoricalTouchMinor(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
+
+/* Get the historical length of the major axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact. */
+float AMotionEvent_getHistoricalToolMajor(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
+
+/* Get the historical length of the minor axis of an ellipse that describes the size
+ * of the approaching tool for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * The tool area represents the estimated size of the finger or pen that is
+ * touching the device independent of its actual touch area at the point of contact. */
+float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
+
+/* Get the historical orientation of the touch area and tool area in radians clockwise from
+ * vertical for the given pointer index that
+ * occurred between this event and the previous motion event.
+ * An angle of 0 degrees indicates that the major axis of contact is oriented
+ * upwards, is perfectly circular or is of unknown orientation.  A positive angle
+ * indicates that the major axis of contact is oriented to the right.  A negative angle
+ * indicates that the major axis of contact is oriented to the left.
+ * The full range is from -PI/4 radians (finger pointing fully left) to PI/4 radians
+ * (finger pointing fully right). */
+float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
+        size_t history_index);
+
+
 /*
  * Input queue
  *
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index cdae27c..3c60a98 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -77,9 +77,9 @@
     private static native boolean nativeHasKeys(int[] keyCodes, boolean[] keyExists);
     private static native void nativeRegisterInputChannel(InputChannel inputChannel);
     private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
-    private static native int nativeInjectKeyEvent(KeyEvent event, int nature,
+    private static native int nativeInjectKeyEvent(KeyEvent event,
             int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
-    private static native int nativeInjectMotionEvent(MotionEvent event, int nature,
+    private static native int nativeInjectMotionEvent(MotionEvent event,
             int injectorPid, int injectorUid, boolean sync, int timeoutMillis);
     private static native void nativeSetInputWindows(InputWindow[] windows);
     private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
@@ -229,14 +229,13 @@
      * to be dispatched before it can determine whether input event injection will be
      * permitted based on the current input focus.
      * @param event The event to inject.
-     * @param nature The nature of the event.
      * @param injectorPid The pid of the injecting application.
      * @param injectorUid The uid of the injecting application.
      * @param sync If true, waits for the event to be completed before returning.
      * @param timeoutMillis The injection timeout in milliseconds.
      * @return One of the INPUT_EVENT_INJECTION_XXX constants.
      */
-    public int injectKeyEvent(KeyEvent event, int nature, int injectorPid, int injectorUid,
+    public int injectKeyEvent(KeyEvent event, int injectorPid, int injectorUid,
             boolean sync, int timeoutMillis) {
         if (event == null) {
             throw new IllegalArgumentException("event must not be null");
@@ -248,7 +247,7 @@
             throw new IllegalArgumentException("timeoutMillis must be positive");
         }
         
-        return nativeInjectKeyEvent(event, nature, injectorPid, injectorUid,
+        return nativeInjectKeyEvent(event, injectorPid, injectorUid,
                 sync, timeoutMillis);
     }
     
@@ -258,7 +257,6 @@
      * to be dispatched before it can determine whether input event injection will be
      * permitted based on the current input focus.
      * @param event The event to inject.
-     * @param nature The nature of the event.
      * @param sync If true, waits for the event to be completed before returning.
      * @param injectorPid The pid of the injecting application.
      * @param injectorUid The uid of the injecting application.
@@ -266,7 +264,7 @@
      * @param timeoutMillis The injection timeout in milliseconds.
      * @return One of the INPUT_EVENT_INJECTION_XXX constants.
      */
-    public int injectMotionEvent(MotionEvent event, int nature, int injectorPid, int injectorUid,
+    public int injectMotionEvent(MotionEvent event, int injectorPid, int injectorUid,
             boolean sync, int timeoutMillis) {
         if (event == null) {
             throw new IllegalArgumentException("event must not be null");
@@ -278,7 +276,7 @@
             throw new IllegalArgumentException("timeoutMillis must be positive");
         }
         
-        return nativeInjectMotionEvent(event, nature, injectorPid, injectorUid,
+        return nativeInjectMotionEvent(event, injectorPid, injectorUid,
                 sync, timeoutMillis);
     }
     
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index c6e5cd2..37a2a58 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -102,6 +102,7 @@
 import android.view.IWindowManager;
 import android.view.IWindowSession;
 import android.view.InputChannel;
+import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -2017,6 +2018,8 @@
             + ", surface=" + win.mSurface);
 
         final long origId = Binder.clearCallingIdentity();
+        
+        win.disposeInputChannel();
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(
                 TAG, "Remove " + win + ": mSurface=" + win.mSurface
@@ -2077,8 +2080,6 @@
     }
 
     private void removeWindowInnerLocked(Session session, WindowState win) {
-        mInputMonitor.windowIsBeingRemovedLw(win);
-
         win.mRemoved = true;
 
         if (mInputMethodTarget == win) {
@@ -2157,6 +2158,8 @@
                 win.mAppToken.updateReportedVisibilityLocked();
             }
         }
+        
+        mInputMonitor.updateInputWindowsLw();
     }
 
     private static void logSurface(WindowState w, String msg, RuntimeException where) {
@@ -2907,7 +2910,6 @@
                         if (win.isVisibleNow()) {
                             applyAnimationLocked(win,
                                     WindowManagerPolicy.TRANSIT_EXIT, false);
-                            mInputMonitor.windowIsBeingRemovedLw(win);
                             changed = true;
                         }
                     }
@@ -2925,6 +2927,7 @@
                     }
                 }
 
+                mInputMonitor.updateInputWindowsLw();
             } else {
                 Slog.w(TAG, "Attempted to remove non-existing token: " + token);
             }
@@ -5111,7 +5114,7 @@
             final int N = windows.size();
             for (int i = N - 1; i >= 0; i--) {
                 final WindowState child = (WindowState) windows.get(i);
-                if (child.mInputChannel == null) {
+                if (child.mInputChannel == null || child.mRemoved) {
                     // Skip this window because it cannot possibly receive input.
                     continue;
                 }
@@ -5288,11 +5291,6 @@
             }
         }
         
-        public void windowIsBeingRemovedLw(WindowState window) {
-            // Window is being removed.
-            updateInputWindowsLw();
-        }
-        
         public void pauseDispatchingLw(WindowToken window) {
             if (! window.paused) {
                 if (DEBUG_INPUT) {
@@ -5410,19 +5408,24 @@
         int metaState = ev.getMetaState();
         int deviceId = ev.getDeviceId();
         int scancode = ev.getScanCode();
+        int source = ev.getSource();
+        
+        if (source == InputDevice.SOURCE_UNKNOWN) {
+            source = InputDevice.SOURCE_KEYBOARD;
+        }
 
         if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
         if (downTime == 0) downTime = eventTime;
 
         KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
-                deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM);
+                deviceId, scancode, KeyEvent.FLAG_FROM_SYSTEM, source);
 
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
         final int result = mInputManager.injectKeyEvent(newEvent,
-                InputQueue.INPUT_EVENT_NATURE_KEY, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
+                pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -5442,8 +5445,13 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result = mInputManager.injectMotionEvent(ev,
-                InputQueue.INPUT_EVENT_NATURE_TOUCH, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
+        MotionEvent newEvent = MotionEvent.obtain(ev);
+        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
+            newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+        }
+        
+        final int result = mInputManager.injectMotionEvent(newEvent,
+                pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -5463,8 +5471,13 @@
         final int uid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         
-        final int result = mInputManager.injectMotionEvent(ev,
-                InputQueue.INPUT_EVENT_NATURE_TRACKBALL, pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
+        MotionEvent newEvent = MotionEvent.obtain(ev);
+        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
+            newEvent.setSource(InputDevice.SOURCE_TRACKBALL);
+        }
+        
+        final int result = mInputManager.injectMotionEvent(newEvent,
+                pid, uid, sync, INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
         return reportInjectionResult(result);
@@ -6960,6 +6973,8 @@
         }
 
         void removeLocked() {
+            disposeInputChannel();
+            
             if (mAttachedWindow != null) {
                 mAttachedWindow.mChildWindows.remove(this);
             }
@@ -6971,7 +6986,9 @@
                 // Ignore if it has already been removed (usually because
                 // we are doing this as part of processing a death note.)
             }
-            
+        }
+        
+        void disposeInputChannel() {
             if (mInputChannel != null) {
                 mInputManager.unregisterInputChannel(mInputChannel);
                 
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 26e105a..bc052a0 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -354,7 +354,7 @@
 
     void releaseTouchedWindowLd();
 
-    int32_t waitForTrackballEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
+    int32_t waitForNonTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
     int32_t waitForTouchEventTargets(MotionEvent* motionEvent, uint32_t policyFlags,
             int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets);
@@ -1222,14 +1222,17 @@
     return injectionResult;
 }
 
+enum InjectionPermission {
+    INJECTION_PERMISSION_UNKNOWN,
+    INJECTION_PERMISSION_GRANTED,
+    INJECTION_PERMISSION_DENIED
+};
+
 int32_t NativeInputManager::waitForTouchedWindowLd(MotionEvent* motionEvent, uint32_t policyFlags,
         int32_t injectorPid, int32_t injectorUid, Vector<InputTarget>& outTargets,
         InputWindow*& outTouchedWindow) {
     nsecs_t startTime = now();
 
-    int32_t injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
-    int32_t action = motionEvent->getAction();
-
     // For security reasons, we defer updating the touch state until we are sure that
     // event injection will be allowed.
     //
@@ -1255,8 +1258,13 @@
     //       instead of POLICY_FLAG_WOKE_HERE...
     //
     bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
+
+    int32_t action = motionEvent->getAction();
+
     bool firstIteration = true;
     ANRTimer anrTimer;
+    int32_t injectionResult;
+    InjectionPermission injectionPermission;
     for (;;) {
         if (firstIteration) {
             firstIteration = false;
@@ -1265,7 +1273,8 @@
                 LOGW("Dropping event because the dispatcher timed out waiting to identify "
                         "the window that should receive it.");
                 injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT;
-                break;
+                injectionPermission = INJECTION_PERMISSION_UNKNOWN;
+                break; // timed out, exit wait loop
             }
         }
 
@@ -1273,6 +1282,7 @@
         if (! mDispatchEnabled) {
             LOGI("Dropping event because input dispatch is disabled.");
             injectionResult = INPUT_EVENT_INJECTION_FAILED;
+            injectionPermission = INJECTION_PERMISSION_UNKNOWN;
             break; // failed, exit wait loop
         }
 
@@ -1286,7 +1296,9 @@
         }
 
         // Update the touch state as needed based on the properties of the touch event.
-        if (action == MOTION_EVENT_ACTION_DOWN) {
+        if (action == AMOTION_EVENT_ACTION_DOWN) {
+            /* Case 1: ACTION_DOWN */
+
             InputWindow* newTouchedWindow = NULL;
             mTempTouchedOutsideWindows.clear();
 
@@ -1348,12 +1360,14 @@
 
                 LOGI("Dropping event because there is no touched window or focused application.");
                 injectionResult = INPUT_EVENT_INJECTION_FAILED;
+                injectionPermission = INJECTION_PERMISSION_UNKNOWN;
                 break; // failed, exit wait loop
             }
 
             // Check permissions.
             if (! checkInjectionPermission(newTouchedWindow, injectorPid, injectorUid)) {
                 injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
+                injectionPermission = INJECTION_PERMISSION_DENIED;
                 break; // failed, exit wait loop
             }
 
@@ -1374,18 +1388,33 @@
             if (newTouchedWindow->hasWallpaper) {
                 mTouchedWallpaperWindows.appendVector(mWallpaperWindows);
             }
+
+            injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
+            injectionPermission = INJECTION_PERMISSION_GRANTED;
             break; // done
         } else {
+            /* Case 2: Everything but ACTION_DOWN */
+
             // Check permissions.
             if (! checkInjectionPermission(mTouchedWindow, injectorPid, injectorUid)) {
                 injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
+                injectionPermission = INJECTION_PERMISSION_DENIED;
+                break; // failed, exit wait loop
+            }
+
+            // If the pointer is not currently down, then ignore the event.
+            if (! mTouchDown) {
+                LOGI("Dropping event because the pointer is not down.");
+                injectionResult = INPUT_EVENT_INJECTION_FAILED;
+                injectionPermission = INJECTION_PERMISSION_GRANTED;
                 break; // failed, exit wait loop
             }
 
             // If there is no currently touched window then fail.
-            if (! mTouchedWindow || ! mTouchDown) {
-                LOGI("Dropping event because touched window is no longer valid.");
+            if (! mTouchedWindow) {
+                LOGW("Dropping event because there is no touched window to receive it.");
                 injectionResult = INPUT_EVENT_INJECTION_FAILED;
+                injectionPermission = INJECTION_PERMISSION_GRANTED;
                 break; // failed, exit wait loop
             }
 
@@ -1399,16 +1428,14 @@
             }
 
             // Success!
+            injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
+            injectionPermission = INJECTION_PERMISSION_GRANTED;
             break; // done
         }
     }
 
     // Output targets.
-    bool havePermission;
     if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED) {
-        // Injection succeeded so the injector must have permission.
-        havePermission = true;
-
         size_t numWallpaperWindows = mTouchedWallpaperWindows.size();
         for (size_t i = 0; i < numWallpaperWindows; i++) {
             addTarget(mTouchedWallpaperWindows[i], 0, 0, outTargets);
@@ -1423,25 +1450,23 @@
                 anrTimer.getTimeSpentWaitingForApplication(), outTargets);
         outTouchedWindow = mTouchedWindow;
     } else {
-        if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED
-                && checkInjectionPermission(NULL, injectorPid, injectorUid)) {
-            // Injection failed but the injector does have permission to inject events.
-            // While we might not have found a valid target for the injected event, we
-            // still want to update the dispatch state to take it into account.
-            havePermission = true;
-        } else {
-            // Injector does not have permission to inject events.
-            // We make sure to leave the dispatch state unchanged.
-            havePermission = false;
-        }
         outTouchedWindow = NULL;
     }
     mTempTouchedOutsideWindows.clear();
 
-    // Update final pieces of touch state now that we know for sure whether the injector
-    // had permission to perform the injection.
-    if (havePermission) {
-        if (action == MOTION_EVENT_ACTION_DOWN) {
+    // Check injection permission once and for all.
+    if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
+        if (checkInjectionPermission(action == AMOTION_EVENT_ACTION_DOWN ? NULL : mTouchedWindow,
+                injectorPid, injectorUid)) {
+            injectionPermission = INJECTION_PERMISSION_GRANTED;
+        } else {
+            injectionPermission = INJECTION_PERMISSION_DENIED;
+        }
+    }
+
+    // Update final pieces of touch state if the injector had permission.
+    if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
+        if (action == AMOTION_EVENT_ACTION_DOWN) {
             if (mTouchDown) {
                 // This is weird.  We got a down but we thought it was already down!
                 LOGW("Pointer down received while already down.");
@@ -1454,10 +1479,12 @@
                 // be holding on to an earlier target from a previous touch down.  Release it.
                 releaseTouchedWindowLd();
             }
-        } else if (action == MOTION_EVENT_ACTION_UP) {
+        } else if (action == AMOTION_EVENT_ACTION_UP) {
             mTouchDown = false;
             releaseTouchedWindowLd();
         }
+    } else {
+        LOGW("Not updating touch focus because injection was denied.");
     }
 
 #if DEBUG_FOCUS
@@ -1557,26 +1584,21 @@
             policyFlags, injectorPid, injectorUid);
 #endif
 
-    switch (motionEvent->getNature()) {
-    case INPUT_EVENT_NATURE_TRACKBALL:
-        return waitForTrackballEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
-                outTargets);
-
-    case INPUT_EVENT_NATURE_TOUCH:
+    int32_t source = motionEvent->getSource();
+    if (source & AINPUT_SOURCE_CLASS_POINTER) {
         return waitForTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
                 outTargets);
-
-    default:
-        assert(false);
-        return INPUT_EVENT_INJECTION_FAILED;
+    } else {
+        return waitForNonTouchEventTargets(motionEvent, policyFlags, injectorPid, injectorUid,
+                outTargets);
     }
 }
 
-int32_t NativeInputManager::waitForTrackballEventTargets(MotionEvent* motionEvent,
+int32_t NativeInputManager::waitForNonTouchEventTargets(MotionEvent* motionEvent,
         uint32_t policyFlags, int32_t injectorPid, int32_t injectorUid,
         Vector<InputTarget>& outTargets) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-    LOGD("waitForTrackballEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
+    LOGD("waitForNonTouchEventTargets - policyFlags=%d, injectorPid=%d, injectorUid=%d",
             policyFlags, injectorPid, injectorUid);
 #endif
 
@@ -1622,10 +1644,10 @@
 
     int32_t eventType;
     switch (motionEvent->getAction()) {
-    case MOTION_EVENT_ACTION_DOWN:
+    case AMOTION_EVENT_ACTION_DOWN:
         eventType = POWER_MANAGER_TOUCH_EVENT;
         break;
-    case MOTION_EVENT_ACTION_UP:
+    case AMOTION_EVENT_ACTION_UP:
         eventType = POWER_MANAGER_TOUCH_UP_EVENT;
         break;
     default:
@@ -1852,7 +1874,7 @@
 static jint android_server_InputManager_nativeGetScanCodeState(JNIEnv* env, jclass clazz,
         jint deviceId, jint deviceClasses, jint scanCode) {
     if (checkInputManagerUnitialized(env)) {
-        return KEY_STATE_UNKNOWN;
+        return AKEY_STATE_UNKNOWN;
     }
 
     return gNativeInputManager->getInputManager()->getScanCodeState(
@@ -1862,7 +1884,7 @@
 static jint android_server_InputManager_nativeGetKeyCodeState(JNIEnv* env, jclass clazz,
         jint deviceId, jint deviceClasses, jint keyCode) {
     if (checkInputManagerUnitialized(env)) {
-        return KEY_STATE_UNKNOWN;
+        return AKEY_STATE_UNKNOWN;
     }
 
     return gNativeInputManager->getInputManager()->getKeyCodeState(
@@ -1872,7 +1894,7 @@
 static jint android_server_InputManager_nativeGetSwitchState(JNIEnv* env, jclass clazz,
         jint deviceId, jint deviceClasses, jint sw) {
     if (checkInputManagerUnitialized(env)) {
-        return KEY_STATE_UNKNOWN;
+        return AKEY_STATE_UNKNOWN;
     }
 
     return gNativeInputManager->getInputManager()->getSwitchState(deviceId, deviceClasses, sw);
@@ -1963,28 +1985,28 @@
 }
 
 static jint android_server_InputManager_nativeInjectKeyEvent(JNIEnv* env, jclass clazz,
-        jobject keyEventObj, jint nature, jint injectorPid, jint injectorUid,
+        jobject keyEventObj, jint injectorPid, jint injectorUid,
         jboolean sync, jint timeoutMillis) {
     if (checkInputManagerUnitialized(env)) {
         return INPUT_EVENT_INJECTION_FAILED;
     }
 
     KeyEvent keyEvent;
-    android_view_KeyEvent_toNative(env, keyEventObj, nature, & keyEvent);
+    android_view_KeyEvent_toNative(env, keyEventObj, & keyEvent);
 
     return gNativeInputManager->getInputManager()->injectInputEvent(& keyEvent,
             injectorPid, injectorUid, sync, timeoutMillis);
 }
 
 static jint android_server_InputManager_nativeInjectMotionEvent(JNIEnv* env, jclass clazz,
-        jobject motionEventObj, jint nature, jint injectorPid, jint injectorUid,
+        jobject motionEventObj, jint injectorPid, jint injectorUid,
         jboolean sync, jint timeoutMillis) {
     if (checkInputManagerUnitialized(env)) {
         return INPUT_EVENT_INJECTION_FAILED;
     }
 
     MotionEvent motionEvent;
-    android_view_MotionEvent_toNative(env, motionEventObj, nature, & motionEvent);
+    android_view_MotionEvent_toNative(env, motionEventObj, & motionEvent);
 
     return gNativeInputManager->getInputManager()->injectInputEvent(& motionEvent,
             injectorPid, injectorUid, sync, timeoutMillis);
@@ -2050,9 +2072,9 @@
             (void*) android_server_InputManager_nativeRegisterInputChannel },
     { "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
             (void*) android_server_InputManager_nativeUnregisterInputChannel },
-    { "nativeInjectKeyEvent", "(Landroid/view/KeyEvent;IIIZI)I",
+    { "nativeInjectKeyEvent", "(Landroid/view/KeyEvent;IIZI)I",
             (void*) android_server_InputManager_nativeInjectKeyEvent },
-    { "nativeInjectMotionEvent", "(Landroid/view/MotionEvent;IIIZI)I",
+    { "nativeInjectMotionEvent", "(Landroid/view/MotionEvent;IIZI)I",
             (void*) android_server_InputManager_nativeInjectMotionEvent },
     { "nativeSetInputWindows", "([Lcom/android/server/InputWindow;)V",
             (void*) android_server_InputManager_nativeSetInputWindows },