Add new axes for joysticks and mouse wheels.

Added API on InputDevice to query the set of axes available.
Added API on KeyEvent and MotionEvent to convert keycodes and axes
to symbolic name strings for diagnostic purposes.
Added API on KeyEvent to query if a given key code is a gamepad button.
Added a new "axis" element to key layout files to specify the
mapping between raw absolute axis values and motion axis ids.
Expanded the axis bitfield to 64bits to allow for future growth.
Modified the Makefile for keyboard prebuilts to run the keymap
validation tool during the build.
Added layouts for two game controllers.
Added default actions for game pad button keys.
Added more tests.
Fixed a bunch of bugs.

Change-Id: I73f9166c3b3c5bcf4970845b58088ad467525525
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7abbce6..def1161 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -44,6 +44,7 @@
     private int mKeyboardType;
 
     private final SparseArray<MotionRange> mMotionRanges = new SparseArray<MotionRange>();
+    private int[] mMotionAxes;
 
     /**
      * A mask for input source classes.
@@ -359,12 +360,31 @@
      *
      * @see MotionEvent#AXIS_X
      * @see MotionEvent#AXIS_Y
+     * @see #getSupportedAxes()
      */
     public MotionRange getMotionRange(int axis) {
         return mMotionRanges.get(axis);
     }
 
-    // Called by native code.
+    /**
+     * Gets the axis ids of all motion axes supported by this device.
+     * @return The axis ids of all motion axes supported by this device.
+     *
+     * @see #getMotionRange(int)
+     */
+    public int[] getMotionAxes() {
+        synchronized (this) {
+            if (mMotionAxes == null) {
+                final int count = mMotionRanges.size();
+                mMotionAxes = new int[count];
+                for (int i = 0; i < count; i++) {
+                    mMotionAxes[i] = mMotionRanges.keyAt(i);
+                }
+            }
+            return mMotionAxes;
+        }
+    }
+
     private void addMotionRange(int axis, float min, float max, float flat, float fuzz) {
         mMotionRanges.append(axis, new MotionRange(min, max, flat, fuzz));
     }
@@ -388,33 +408,35 @@
         }
 
         /**
-         * Gets the minimum value for the axis.
-         * @return The (inclusive) minimum value.
+         * Gets the inclusive minimum value for the axis.
+         * @return The inclusive minimum value.
          */
         public float getMin() {
             return mMin;
         }
 
         /**
-         * Gets the maximum value for the axis.
-         * @return The (inclusive) maximum value.
+         * Gets the inclusive maximum value for the axis.
+         * @return The inclusive maximum value.
          */
         public float getMax() {
             return mMax;
         }
 
         /**
-         * Gets the range of the axis (difference between maximum and minimum plus one).
+         * Gets the range of the axis (difference between maximum and minimum).
          * @return The range of values.
          */
         public float getRange() {
-            return mMax - mMin + 1;
+            return mMax - mMin;
         }
 
         /**
          * Gets the extent of the center flat position with respect to this axis.
+         * <p>
          * For example, a flat value of 8 means that the center position is between -8 and +8.
          * This value is mainly useful for calibrating self-centering devices.
+         * </p>
          * @return The extent of the center flat position.
          */
         public float getFlat() {
@@ -423,8 +445,10 @@
 
         /**
          * Gets the error tolerance for input device measurements with respect to this axis.
+         * <p>
          * For example, a value of 2 indicates that the measured value may be up to +/- 2 units
          * away from the actual value due to noise and device sensitivity limitations.
+         * </p>
          * @return The error tolerance.
          */
         public float getFuzz() {
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 3f6a04b..81d5a6e 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -21,6 +21,7 @@
 import android.text.method.MetaKeyKeyListener;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.KeyCharacterMap;
 import android.view.KeyCharacterMap.KeyData;
@@ -582,213 +583,214 @@
     //  those new codes.  This is intended to maintain a consistent
     //  set of key code definitions across all Android devices.
 
-    // Symbolic names of all keys indexed by keycode.
-    // There should be exactly LAST_KEYCODE + 1 entries in this table.
-    private static final String[] KEYCODE_SYMBOLIC_NAMES = new String[] {
-        "KEYCODE_UNKNOWN",
-        "KEYCODE_SOFT_LEFT",
-        "KEYCODE_SOFT_RIGHT",
-        "KEYCODE_HOME",
-        "KEYCODE_BACK",
-        "KEYCODE_CALL",
-        "KEYCODE_ENDCALL",
-        "KEYCODE_0",
-        "KEYCODE_1",
-        "KEYCODE_2",
-        "KEYCODE_3",
-        "KEYCODE_4",
-        "KEYCODE_5",
-        "KEYCODE_6",
-        "KEYCODE_7",
-        "KEYCODE_8",
-        "KEYCODE_9",
-        "KEYCODE_STAR",
-        "KEYCODE_POUND",
-        "KEYCODE_DPAD_UP",
-        "KEYCODE_DPAD_DOWN",
-        "KEYCODE_DPAD_LEFT",
-        "KEYCODE_DPAD_RIGHT",
-        "KEYCODE_DPAD_CENTER",
-        "KEYCODE_VOLUME_UP",
-        "KEYCODE_VOLUME_DOWN",
-        "KEYCODE_POWER",
-        "KEYCODE_CAMERA",
-        "KEYCODE_CLEAR",
-        "KEYCODE_A",
-        "KEYCODE_B",
-        "KEYCODE_C",
-        "KEYCODE_D",
-        "KEYCODE_E",
-        "KEYCODE_F",
-        "KEYCODE_G",
-        "KEYCODE_H",
-        "KEYCODE_I",
-        "KEYCODE_J",
-        "KEYCODE_K",
-        "KEYCODE_L",
-        "KEYCODE_M",
-        "KEYCODE_N",
-        "KEYCODE_O",
-        "KEYCODE_P",
-        "KEYCODE_Q",
-        "KEYCODE_R",
-        "KEYCODE_S",
-        "KEYCODE_T",
-        "KEYCODE_U",
-        "KEYCODE_V",
-        "KEYCODE_W",
-        "KEYCODE_X",
-        "KEYCODE_Y",
-        "KEYCODE_Z",
-        "KEYCODE_COMMA",
-        "KEYCODE_PERIOD",
-        "KEYCODE_ALT_LEFT",
-        "KEYCODE_ALT_RIGHT",
-        "KEYCODE_SHIFT_LEFT",
-        "KEYCODE_SHIFT_RIGHT",
-        "KEYCODE_TAB",
-        "KEYCODE_SPACE",
-        "KEYCODE_SYM",
-        "KEYCODE_EXPLORER",
-        "KEYCODE_ENVELOPE",
-        "KEYCODE_ENTER",
-        "KEYCODE_DEL",
-        "KEYCODE_GRAVE",
-        "KEYCODE_MINUS",
-        "KEYCODE_EQUALS",
-        "KEYCODE_LEFT_BRACKET",
-        "KEYCODE_RIGHT_BRACKET",
-        "KEYCODE_BACKSLASH",
-        "KEYCODE_SEMICOLON",
-        "KEYCODE_APOSTROPHE",
-        "KEYCODE_SLASH",
-        "KEYCODE_AT",
-        "KEYCODE_NUM",
-        "KEYCODE_HEADSETHOOK",
-        "KEYCODE_FOCUS",
-        "KEYCODE_PLUS",
-        "KEYCODE_MENU",
-        "KEYCODE_NOTIFICATION",
-        "KEYCODE_SEARCH",
-        "KEYCODE_MEDIA_PLAY_PAUSE",
-        "KEYCODE_MEDIA_STOP",
-        "KEYCODE_MEDIA_NEXT",
-        "KEYCODE_MEDIA_PREVIOUS",
-        "KEYCODE_MEDIA_REWIND",
-        "KEYCODE_MEDIA_FAST_FORWARD",
-        "KEYCODE_MUTE",
-        "KEYCODE_PAGE_UP",
-        "KEYCODE_PAGE_DOWN",
-        "KEYCODE_PICTSYMBOLS",
-        "KEYCODE_SWITCH_CHARSET",
-        "KEYCODE_BUTTON_A",
-        "KEYCODE_BUTTON_B",
-        "KEYCODE_BUTTON_C",
-        "KEYCODE_BUTTON_X",
-        "KEYCODE_BUTTON_Y",
-        "KEYCODE_BUTTON_Z",
-        "KEYCODE_BUTTON_L1",
-        "KEYCODE_BUTTON_R1",
-        "KEYCODE_BUTTON_L2",
-        "KEYCODE_BUTTON_R2",
-        "KEYCODE_BUTTON_THUMBL",
-        "KEYCODE_BUTTON_THUMBR",
-        "KEYCODE_BUTTON_START",
-        "KEYCODE_BUTTON_SELECT",
-        "KEYCODE_BUTTON_MODE",
-        "KEYCODE_ESCAPE",
-        "KEYCODE_FORWARD_DEL",
-        "KEYCODE_CTRL_LEFT",
-        "KEYCODE_CTRL_RIGHT",
-        "KEYCODE_CAPS_LOCK",
-        "KEYCODE_SCROLL_LOCK",
-        "KEYCODE_META_LEFT",
-        "KEYCODE_META_RIGHT",
-        "KEYCODE_FUNCTION",
-        "KEYCODE_SYSRQ",
-        "KEYCODE_BREAK",
-        "KEYCODE_MOVE_HOME",
-        "KEYCODE_MOVE_END",
-        "KEYCODE_INSERT",
-        "KEYCODE_FORWARD",
-        "KEYCODE_MEDIA_PLAY",
-        "KEYCODE_MEDIA_PAUSE",
-        "KEYCODE_MEDIA_CLOSE",
-        "KEYCODE_MEDIA_EJECT",
-        "KEYCODE_MEDIA_RECORD",
-        "KEYCODE_F1",
-        "KEYCODE_F2",
-        "KEYCODE_F3",
-        "KEYCODE_F4",
-        "KEYCODE_F5",
-        "KEYCODE_F6",
-        "KEYCODE_F7",
-        "KEYCODE_F8",
-        "KEYCODE_F9",
-        "KEYCODE_F10",
-        "KEYCODE_F11",
-        "KEYCODE_F12",
-        "KEYCODE_NUM_LOCK",
-        "KEYCODE_NUMPAD_0",
-        "KEYCODE_NUMPAD_1",
-        "KEYCODE_NUMPAD_2",
-        "KEYCODE_NUMPAD_3",
-        "KEYCODE_NUMPAD_4",
-        "KEYCODE_NUMPAD_5",
-        "KEYCODE_NUMPAD_6",
-        "KEYCODE_NUMPAD_7",
-        "KEYCODE_NUMPAD_8",
-        "KEYCODE_NUMPAD_9",
-        "KEYCODE_NUMPAD_DIVIDE",
-        "KEYCODE_NUMPAD_MULTIPLY",
-        "KEYCODE_MUMPAD_SUBTRACT",
-        "KEYCODE_NUMPAD_ADD",
-        "KEYCODE_NUMPAD_DOT",
-        "KEYCODE_NUMPAD_COMMA",
-        "KEYCODE_NUMPAD_ENTER",
-        "KEYCODE_NUMPAD_EQUALS",
-        "KEYCODE_NUMPAD_LEFT_PAREN",
-        "KEYCODE_NUMPAD_RIGHT_PAREN",
-        "KEYCODE_VOLUME_MUTE",
-        "KEYCODE_INFO",
-        "KEYCODE_CHANNEL_UP",
-        "KEYCODE_CHANNEL_DOWN",
-        "KEYCODE_ZOOM_IN",
-        "KEYCODE_ZOOM_OUT",
-        "KEYCODE_TV",
-        "KEYCODE_WINDOW",
-        "KEYCODE_GUIDE",
-        "KEYCODE_DVR",
-        "KEYCODE_BOOKMARK",
-        "KEYCODE_CAPTIONS",
-        "KEYCODE_SETTINGS",
-        "KEYCODE_TV_POWER",
-        "KEYCODE_TV_INPUT",
-        "KEYCODE_STB_INPUT",
-        "KEYCODE_STB_POWER",
-        "KEYCODE_AVR_POWER",
-        "KEYCODE_AVR_INPUT",
-        "KEYCODE_PROG_RED",
-        "KEYCODE_PROG_GREEN",
-        "KEYCODE_PROG_YELLOW",
-        "KEYCODE_PROG_BLUE",
-        "KEYCODE_APP_SWITCH",
-        "KEYCODE_BUTTON_1",
-        "KEYCODE_BUTTON_2",
-        "KEYCODE_BUTTON_3",
-        "KEYCODE_BUTTON_4",
-        "KEYCODE_BUTTON_5",
-        "KEYCODE_BUTTON_6",
-        "KEYCODE_BUTTON_7",
-        "KEYCODE_BUTTON_8",
-        "KEYCODE_BUTTON_9",
-        "KEYCODE_BUTTON_10",
-        "KEYCODE_BUTTON_11",
-        "KEYCODE_BUTTON_12",
-        "KEYCODE_BUTTON_13",
-        "KEYCODE_BUTTON_14",
-        "KEYCODE_BUTTON_15",
-        "KEYCODE_BUTTON_16",
+    // Symbolic names of all key codes.
+    private static final SparseArray<String> KEYCODE_SYMBOLIC_NAMES = new SparseArray<String>();
+    private static void populateKeycodeSymbolicNames() {
+        SparseArray<String> names = KEYCODE_SYMBOLIC_NAMES;
+        names.append(KEYCODE_UNKNOWN, "KEYCODE_UNKNOWN");
+        names.append(KEYCODE_SOFT_LEFT, "KEYCODE_SOFT_LEFT");
+        names.append(KEYCODE_SOFT_RIGHT, "KEYCODE_SOFT_RIGHT");
+        names.append(KEYCODE_HOME, "KEYCODE_HOME");
+        names.append(KEYCODE_BACK, "KEYCODE_BACK");
+        names.append(KEYCODE_CALL, "KEYCODE_CALL");
+        names.append(KEYCODE_ENDCALL, "KEYCODE_ENDCALL");
+        names.append(KEYCODE_0, "KEYCODE_0");
+        names.append(KEYCODE_1, "KEYCODE_1");
+        names.append(KEYCODE_2, "KEYCODE_2");
+        names.append(KEYCODE_3, "KEYCODE_3");
+        names.append(KEYCODE_4, "KEYCODE_4");
+        names.append(KEYCODE_5, "KEYCODE_5");
+        names.append(KEYCODE_6, "KEYCODE_6");
+        names.append(KEYCODE_7, "KEYCODE_7");
+        names.append(KEYCODE_8, "KEYCODE_8");
+        names.append(KEYCODE_9, "KEYCODE_9");
+        names.append(KEYCODE_STAR, "KEYCODE_STAR");
+        names.append(KEYCODE_POUND, "KEYCODE_POUND");
+        names.append(KEYCODE_DPAD_UP, "KEYCODE_DPAD_UP");
+        names.append(KEYCODE_DPAD_DOWN, "KEYCODE_DPAD_DOWN");
+        names.append(KEYCODE_DPAD_LEFT, "KEYCODE_DPAD_LEFT");
+        names.append(KEYCODE_DPAD_RIGHT, "KEYCODE_DPAD_RIGHT");
+        names.append(KEYCODE_DPAD_CENTER, "KEYCODE_DPAD_CENTER");
+        names.append(KEYCODE_VOLUME_UP, "KEYCODE_VOLUME_UP");
+        names.append(KEYCODE_VOLUME_DOWN, "KEYCODE_VOLUME_DOWN");
+        names.append(KEYCODE_POWER, "KEYCODE_POWER");
+        names.append(KEYCODE_CAMERA, "KEYCODE_CAMERA");
+        names.append(KEYCODE_CLEAR, "KEYCODE_CLEAR");
+        names.append(KEYCODE_A, "KEYCODE_A");
+        names.append(KEYCODE_B, "KEYCODE_B");
+        names.append(KEYCODE_C, "KEYCODE_C");
+        names.append(KEYCODE_D, "KEYCODE_D");
+        names.append(KEYCODE_E, "KEYCODE_E");
+        names.append(KEYCODE_F, "KEYCODE_F");
+        names.append(KEYCODE_G, "KEYCODE_G");
+        names.append(KEYCODE_H, "KEYCODE_H");
+        names.append(KEYCODE_I, "KEYCODE_I");
+        names.append(KEYCODE_J, "KEYCODE_J");
+        names.append(KEYCODE_K, "KEYCODE_K");
+        names.append(KEYCODE_L, "KEYCODE_L");
+        names.append(KEYCODE_M, "KEYCODE_M");
+        names.append(KEYCODE_N, "KEYCODE_N");
+        names.append(KEYCODE_O, "KEYCODE_O");
+        names.append(KEYCODE_P, "KEYCODE_P");
+        names.append(KEYCODE_Q, "KEYCODE_Q");
+        names.append(KEYCODE_R, "KEYCODE_R");
+        names.append(KEYCODE_S, "KEYCODE_S");
+        names.append(KEYCODE_T, "KEYCODE_T");
+        names.append(KEYCODE_U, "KEYCODE_U");
+        names.append(KEYCODE_V, "KEYCODE_V");
+        names.append(KEYCODE_W, "KEYCODE_W");
+        names.append(KEYCODE_X, "KEYCODE_X");
+        names.append(KEYCODE_Y, "KEYCODE_Y");
+        names.append(KEYCODE_Z, "KEYCODE_Z");
+        names.append(KEYCODE_COMMA, "KEYCODE_COMMA");
+        names.append(KEYCODE_PERIOD, "KEYCODE_PERIOD");
+        names.append(KEYCODE_ALT_LEFT, "KEYCODE_ALT_LEFT");
+        names.append(KEYCODE_ALT_RIGHT, "KEYCODE_ALT_RIGHT");
+        names.append(KEYCODE_SHIFT_LEFT, "KEYCODE_SHIFT_LEFT");
+        names.append(KEYCODE_SHIFT_RIGHT, "KEYCODE_SHIFT_RIGHT");
+        names.append(KEYCODE_TAB, "KEYCODE_TAB");
+        names.append(KEYCODE_SPACE, "KEYCODE_SPACE");
+        names.append(KEYCODE_SYM, "KEYCODE_SYM");
+        names.append(KEYCODE_EXPLORER, "KEYCODE_EXPLORER");
+        names.append(KEYCODE_ENVELOPE, "KEYCODE_ENVELOPE");
+        names.append(KEYCODE_ENTER, "KEYCODE_ENTER");
+        names.append(KEYCODE_DEL, "KEYCODE_DEL");
+        names.append(KEYCODE_GRAVE, "KEYCODE_GRAVE");
+        names.append(KEYCODE_MINUS, "KEYCODE_MINUS");
+        names.append(KEYCODE_EQUALS, "KEYCODE_EQUALS");
+        names.append(KEYCODE_LEFT_BRACKET, "KEYCODE_LEFT_BRACKET");
+        names.append(KEYCODE_RIGHT_BRACKET, "KEYCODE_RIGHT_BRACKET");
+        names.append(KEYCODE_BACKSLASH, "KEYCODE_BACKSLASH");
+        names.append(KEYCODE_SEMICOLON, "KEYCODE_SEMICOLON");
+        names.append(KEYCODE_APOSTROPHE, "KEYCODE_APOSTROPHE");
+        names.append(KEYCODE_SLASH, "KEYCODE_SLASH");
+        names.append(KEYCODE_AT, "KEYCODE_AT");
+        names.append(KEYCODE_NUM, "KEYCODE_NUM");
+        names.append(KEYCODE_HEADSETHOOK, "KEYCODE_HEADSETHOOK");
+        names.append(KEYCODE_FOCUS, "KEYCODE_FOCUS");
+        names.append(KEYCODE_PLUS, "KEYCODE_PLUS");
+        names.append(KEYCODE_MENU, "KEYCODE_MENU");
+        names.append(KEYCODE_NOTIFICATION, "KEYCODE_NOTIFICATION");
+        names.append(KEYCODE_SEARCH, "KEYCODE_SEARCH");
+        names.append(KEYCODE_MEDIA_PLAY_PAUSE, "KEYCODE_MEDIA_PLAY_PAUSE");
+        names.append(KEYCODE_MEDIA_STOP, "KEYCODE_MEDIA_STOP");
+        names.append(KEYCODE_MEDIA_NEXT, "KEYCODE_MEDIA_NEXT");
+        names.append(KEYCODE_MEDIA_PREVIOUS, "KEYCODE_MEDIA_PREVIOUS");
+        names.append(KEYCODE_MEDIA_REWIND, "KEYCODE_MEDIA_REWIND");
+        names.append(KEYCODE_MEDIA_FAST_FORWARD, "KEYCODE_MEDIA_FAST_FORWARD");
+        names.append(KEYCODE_MUTE, "KEYCODE_MUTE");
+        names.append(KEYCODE_PAGE_UP, "KEYCODE_PAGE_UP");
+        names.append(KEYCODE_PAGE_DOWN, "KEYCODE_PAGE_DOWN");
+        names.append(KEYCODE_PICTSYMBOLS, "KEYCODE_PICTSYMBOLS");
+        names.append(KEYCODE_SWITCH_CHARSET, "KEYCODE_SWITCH_CHARSET");
+        names.append(KEYCODE_BUTTON_A, "KEYCODE_BUTTON_A");
+        names.append(KEYCODE_BUTTON_B, "KEYCODE_BUTTON_B");
+        names.append(KEYCODE_BUTTON_C, "KEYCODE_BUTTON_C");
+        names.append(KEYCODE_BUTTON_X, "KEYCODE_BUTTON_X");
+        names.append(KEYCODE_BUTTON_Y, "KEYCODE_BUTTON_Y");
+        names.append(KEYCODE_BUTTON_Z, "KEYCODE_BUTTON_Z");
+        names.append(KEYCODE_BUTTON_L1, "KEYCODE_BUTTON_L1");
+        names.append(KEYCODE_BUTTON_R1, "KEYCODE_BUTTON_R1");
+        names.append(KEYCODE_BUTTON_L2, "KEYCODE_BUTTON_L2");
+        names.append(KEYCODE_BUTTON_R2, "KEYCODE_BUTTON_R2");
+        names.append(KEYCODE_BUTTON_THUMBL, "KEYCODE_BUTTON_THUMBL");
+        names.append(KEYCODE_BUTTON_THUMBR, "KEYCODE_BUTTON_THUMBR");
+        names.append(KEYCODE_BUTTON_START, "KEYCODE_BUTTON_START");
+        names.append(KEYCODE_BUTTON_SELECT, "KEYCODE_BUTTON_SELECT");
+        names.append(KEYCODE_BUTTON_MODE, "KEYCODE_BUTTON_MODE");
+        names.append(KEYCODE_ESCAPE, "KEYCODE_ESCAPE");
+        names.append(KEYCODE_FORWARD_DEL, "KEYCODE_FORWARD_DEL");
+        names.append(KEYCODE_CTRL_LEFT, "KEYCODE_CTRL_LEFT");
+        names.append(KEYCODE_CTRL_RIGHT, "KEYCODE_CTRL_RIGHT");
+        names.append(KEYCODE_CAPS_LOCK, "KEYCODE_CAPS_LOCK");
+        names.append(KEYCODE_SCROLL_LOCK, "KEYCODE_SCROLL_LOCK");
+        names.append(KEYCODE_META_LEFT, "KEYCODE_META_LEFT");
+        names.append(KEYCODE_META_RIGHT, "KEYCODE_META_RIGHT");
+        names.append(KEYCODE_FUNCTION, "KEYCODE_FUNCTION");
+        names.append(KEYCODE_SYSRQ, "KEYCODE_SYSRQ");
+        names.append(KEYCODE_BREAK, "KEYCODE_BREAK");
+        names.append(KEYCODE_MOVE_HOME, "KEYCODE_MOVE_HOME");
+        names.append(KEYCODE_MOVE_END, "KEYCODE_MOVE_END");
+        names.append(KEYCODE_INSERT, "KEYCODE_INSERT");
+        names.append(KEYCODE_FORWARD, "KEYCODE_FORWARD");
+        names.append(KEYCODE_MEDIA_PLAY, "KEYCODE_MEDIA_PLAY");
+        names.append(KEYCODE_MEDIA_PAUSE, "KEYCODE_MEDIA_PAUSE");
+        names.append(KEYCODE_MEDIA_CLOSE, "KEYCODE_MEDIA_CLOSE");
+        names.append(KEYCODE_MEDIA_EJECT, "KEYCODE_MEDIA_EJECT");
+        names.append(KEYCODE_MEDIA_RECORD, "KEYCODE_MEDIA_RECORD");
+        names.append(KEYCODE_F1, "KEYCODE_F1");
+        names.append(KEYCODE_F2, "KEYCODE_F2");
+        names.append(KEYCODE_F3, "KEYCODE_F3");
+        names.append(KEYCODE_F4, "KEYCODE_F4");
+        names.append(KEYCODE_F5, "KEYCODE_F5");
+        names.append(KEYCODE_F6, "KEYCODE_F6");
+        names.append(KEYCODE_F7, "KEYCODE_F7");
+        names.append(KEYCODE_F8, "KEYCODE_F8");
+        names.append(KEYCODE_F9, "KEYCODE_F9");
+        names.append(KEYCODE_F10, "KEYCODE_F10");
+        names.append(KEYCODE_F11, "KEYCODE_F11");
+        names.append(KEYCODE_F12, "KEYCODE_F12");
+        names.append(KEYCODE_NUM_LOCK, "KEYCODE_NUM_LOCK");
+        names.append(KEYCODE_NUMPAD_0, "KEYCODE_NUMPAD_0");
+        names.append(KEYCODE_NUMPAD_1, "KEYCODE_NUMPAD_1");
+        names.append(KEYCODE_NUMPAD_2, "KEYCODE_NUMPAD_2");
+        names.append(KEYCODE_NUMPAD_3, "KEYCODE_NUMPAD_3");
+        names.append(KEYCODE_NUMPAD_4, "KEYCODE_NUMPAD_4");
+        names.append(KEYCODE_NUMPAD_5, "KEYCODE_NUMPAD_5");
+        names.append(KEYCODE_NUMPAD_6, "KEYCODE_NUMPAD_6");
+        names.append(KEYCODE_NUMPAD_7, "KEYCODE_NUMPAD_7");
+        names.append(KEYCODE_NUMPAD_8, "KEYCODE_NUMPAD_8");
+        names.append(KEYCODE_NUMPAD_9, "KEYCODE_NUMPAD_9");
+        names.append(KEYCODE_NUMPAD_DIVIDE, "KEYCODE_NUMPAD_DIVIDE");
+        names.append(KEYCODE_NUMPAD_MULTIPLY, "KEYCODE_NUMPAD_MULTIPLY");
+        names.append(KEYCODE_NUMPAD_SUBTRACT, "KEYCODE_NUMPAD_SUBTRACT");
+        names.append(KEYCODE_NUMPAD_ADD, "KEYCODE_NUMPAD_ADD");
+        names.append(KEYCODE_NUMPAD_DOT, "KEYCODE_NUMPAD_DOT");
+        names.append(KEYCODE_NUMPAD_COMMA, "KEYCODE_NUMPAD_COMMA");
+        names.append(KEYCODE_NUMPAD_ENTER, "KEYCODE_NUMPAD_ENTER");
+        names.append(KEYCODE_NUMPAD_EQUALS, "KEYCODE_NUMPAD_EQUALS");
+        names.append(KEYCODE_NUMPAD_LEFT_PAREN, "KEYCODE_NUMPAD_LEFT_PAREN");
+        names.append(KEYCODE_NUMPAD_RIGHT_PAREN, "KEYCODE_NUMPAD_RIGHT_PAREN");
+        names.append(KEYCODE_VOLUME_MUTE, "KEYCODE_VOLUME_MUTE");
+        names.append(KEYCODE_INFO, "KEYCODE_INFO");
+        names.append(KEYCODE_CHANNEL_UP, "KEYCODE_CHANNEL_UP");
+        names.append(KEYCODE_CHANNEL_DOWN, "KEYCODE_CHANNEL_DOWN");
+        names.append(KEYCODE_ZOOM_IN, "KEYCODE_ZOOM_IN");
+        names.append(KEYCODE_ZOOM_OUT, "KEYCODE_ZOOM_OUT");
+        names.append(KEYCODE_TV, "KEYCODE_TV");
+        names.append(KEYCODE_WINDOW, "KEYCODE_WINDOW");
+        names.append(KEYCODE_GUIDE, "KEYCODE_GUIDE");
+        names.append(KEYCODE_DVR, "KEYCODE_DVR");
+        names.append(KEYCODE_BOOKMARK, "KEYCODE_BOOKMARK");
+        names.append(KEYCODE_CAPTIONS, "KEYCODE_CAPTIONS");
+        names.append(KEYCODE_SETTINGS, "KEYCODE_SETTINGS");
+        names.append(KEYCODE_TV_POWER, "KEYCODE_TV_POWER");
+        names.append(KEYCODE_TV_INPUT, "KEYCODE_TV_INPUT");
+        names.append(KEYCODE_STB_INPUT, "KEYCODE_STB_INPUT");
+        names.append(KEYCODE_STB_POWER, "KEYCODE_STB_POWER");
+        names.append(KEYCODE_AVR_POWER, "KEYCODE_AVR_POWER");
+        names.append(KEYCODE_AVR_INPUT, "KEYCODE_AVR_INPUT");
+        names.append(KEYCODE_PROG_RED, "KEYCODE_PROG_RED");
+        names.append(KEYCODE_PROG_GREEN, "KEYCODE_PROG_GREEN");
+        names.append(KEYCODE_PROG_YELLOW, "KEYCODE_PROG_YELLOW");
+        names.append(KEYCODE_PROG_BLUE, "KEYCODE_PROG_BLUE");
+        names.append(KEYCODE_APP_SWITCH, "KEYCODE_APP_SWITCH");
+        names.append(KEYCODE_BUTTON_1, "KEYCODE_BUTTON_1");
+        names.append(KEYCODE_BUTTON_2, "KEYCODE_BUTTON_2");
+        names.append(KEYCODE_BUTTON_3, "KEYCODE_BUTTON_3");
+        names.append(KEYCODE_BUTTON_4, "KEYCODE_BUTTON_4");
+        names.append(KEYCODE_BUTTON_5, "KEYCODE_BUTTON_5");
+        names.append(KEYCODE_BUTTON_6, "KEYCODE_BUTTON_6");
+        names.append(KEYCODE_BUTTON_7, "KEYCODE_BUTTON_7");
+        names.append(KEYCODE_BUTTON_8, "KEYCODE_BUTTON_8");
+        names.append(KEYCODE_BUTTON_9, "KEYCODE_BUTTON_9");
+        names.append(KEYCODE_BUTTON_10, "KEYCODE_BUTTON_10");
+        names.append(KEYCODE_BUTTON_11, "KEYCODE_BUTTON_11");
+        names.append(KEYCODE_BUTTON_12, "KEYCODE_BUTTON_12");
+        names.append(KEYCODE_BUTTON_13, "KEYCODE_BUTTON_13");
+        names.append(KEYCODE_BUTTON_14, "KEYCODE_BUTTON_14");
+        names.append(KEYCODE_BUTTON_15, "KEYCODE_BUTTON_15");
+        names.append(KEYCODE_BUTTON_16, "KEYCODE_BUTTON_16");
     };
 
     // Symbolic names of all metakeys in bit order from least significant to most significant.
@@ -1250,14 +1252,7 @@
     }
 
     static {
-        if (META_SYMBOLIC_NAMES.length != 32) {
-            throw new IllegalStateException(
-                    "META_SYMBOLIC_NAMES array should contain exactly 32 entries.");
-        }
-        if (KEYCODE_SYMBOLIC_NAMES.length != LAST_KEYCODE + 1) {
-            throw new IllegalStateException(
-                    "KEYCODE_SYMBOLIC_NAMES array is out of sync with the keycode constants.");
-        }
+        populateKeycodeSymbolicNames();
     }
 
     private KeyEvent() {
@@ -1653,6 +1648,49 @@
         return native_hasDefaultAction(mKeyCode);
     }
 
+    /**
+     * Returns true if the specified keycode is a gamepad button.
+     * @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.
+     */
+    public static final boolean isGamepadButton(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_BUTTON_A:
+            case KeyEvent.KEYCODE_BUTTON_B:
+            case KeyEvent.KEYCODE_BUTTON_C:
+            case KeyEvent.KEYCODE_BUTTON_X:
+            case KeyEvent.KEYCODE_BUTTON_Y:
+            case KeyEvent.KEYCODE_BUTTON_Z:
+            case KeyEvent.KEYCODE_BUTTON_L1:
+            case KeyEvent.KEYCODE_BUTTON_R1:
+            case KeyEvent.KEYCODE_BUTTON_L2:
+            case KeyEvent.KEYCODE_BUTTON_R2:
+            case KeyEvent.KEYCODE_BUTTON_THUMBL:
+            case KeyEvent.KEYCODE_BUTTON_THUMBR:
+            case KeyEvent.KEYCODE_BUTTON_START:
+            case KeyEvent.KEYCODE_BUTTON_SELECT:
+            case KeyEvent.KEYCODE_BUTTON_MODE:
+            case KeyEvent.KEYCODE_BUTTON_1:
+            case KeyEvent.KEYCODE_BUTTON_2:
+            case KeyEvent.KEYCODE_BUTTON_3:
+            case KeyEvent.KEYCODE_BUTTON_4:
+            case KeyEvent.KEYCODE_BUTTON_5:
+            case KeyEvent.KEYCODE_BUTTON_6:
+            case KeyEvent.KEYCODE_BUTTON_7:
+            case KeyEvent.KEYCODE_BUTTON_8:
+            case KeyEvent.KEYCODE_BUTTON_9:
+            case KeyEvent.KEYCODE_BUTTON_10:
+            case KeyEvent.KEYCODE_BUTTON_11:
+            case KeyEvent.KEYCODE_BUTTON_12:
+            case KeyEvent.KEYCODE_BUTTON_13:
+            case KeyEvent.KEYCODE_BUTTON_14:
+            case KeyEvent.KEYCODE_BUTTON_15:
+            case KeyEvent.KEYCODE_BUTTON_16:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     public final int getDeviceId() {
@@ -2554,7 +2592,7 @@
 
     /**
      * Returns a string that represents the symbolic name of the specified action
-     * such as "ACTION_DOWN", or "35" (if unknown).
+     * such as "ACTION_DOWN", or an equivalent numeric constant such as "35" if unknown.
      *
      * @param action The action.
      * @return The symbolic name of the specified action.
@@ -2575,52 +2613,51 @@
 
     /**
      * Returns a string that represents the symbolic name of the specified keycode
-     * such as "KEYCODE_A", "KEYCODE_DPAD_UP", or "1001" (if unknown).
+     * such as "KEYCODE_A", "KEYCODE_DPAD_UP", or an equivalent numeric constant
+     * such as "1001" if unknown.
      *
      * @param keyCode The key code.
      * @return The symbolic name of the specified keycode.
      *
      * @see KeyCharacterMap#getDisplayLabel
-     * @hide
      */
     public static String keyCodeToString(int keyCode) {
-        if (keyCode >= 0 && keyCode < KEYCODE_SYMBOLIC_NAMES.length) {
-            return KEYCODE_SYMBOLIC_NAMES[keyCode];
-        }
-        return Integer.toString(keyCode);
+        String symbolicName = KEYCODE_SYMBOLIC_NAMES.get(keyCode);
+        return symbolicName != null ? symbolicName : Integer.toString(keyCode);
     }
 
     /**
-     * Gets a keycode by its symbolic name such as "KEYCODE_A" or "1001" (if unknown).
+     * Gets a keycode by its symbolic name such as "KEYCODE_A" or an equivalent
+     * numeric constant such as "1001".
      *
      * @param symbolicName The symbolic name of the keycode.
-     * @return The keycode or -1 if not found.
+     * @return The keycode or {@link #KEYCODE_UNKNOWN} if not found.
      * @see #keycodeToString
-     * @hide
      */
     public static int keyCodeFromString(String symbolicName) {
         if (symbolicName == null) {
             throw new IllegalArgumentException("symbolicName must not be null");
         }
 
-        final int count = KEYCODE_SYMBOLIC_NAMES.length;
+        final int count = KEYCODE_SYMBOLIC_NAMES.size();
         for (int i = 0; i < count; i++) {
-            if (symbolicName.equals(KEYCODE_SYMBOLIC_NAMES[i])) {
+            if (symbolicName.equals(KEYCODE_SYMBOLIC_NAMES.valueAt(i))) {
                 return i;
             }
         }
 
         try {
-            return Integer.parseInt(symbolicName,10);
+            return Integer.parseInt(symbolicName, 10);
         } catch (NumberFormatException ex) {
-            return -1;
+            return KEYCODE_UNKNOWN;
         }
     }
 
     /**
      * Returns a string that represents the symbolic name of the specified combined meta
      * key modifier state flags such as "0", "META_SHIFT_ON",
-     * "META_ALT_ON|META_SHIFT_ON" or "0x10000000" (if unknown).
+     * "META_ALT_ON|META_SHIFT_ON" or an equivalent numeric constant such as "0x10000000"
+     * if unknown.
      *
      * @param metaState The meta state.
      * @return The symbolic name of the specified combined meta state flags.
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 6673be2..a1326d2 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.util.SparseArray;
 
 /**
  * Object used to report movement (mouse, pen, finger, trackball) events.  This
@@ -263,10 +264,22 @@
 
     /**
      * Constant used to identify the X axis of a motion event.
-     *
-     * The interpretation of the X axis varies by input source.
-     * It may represent the X position of the center of the touch contact area,
-     * a relative horizontal displacement of a trackball or joystick, or something else.
+     * <p>
+     * <ul>
+     * <li>For a touch screen, reports the absolute X screen position of the center of
+     * the touch contact area.  The units are display pixels.
+     * <li>For a touch pad, reports the absolute X surface position of the center of the touch
+     * contact area.  The units are device-specific because the touch pad is not necessarily
+     * associated with a display.  Use {@link InputDevice#getMotionRange(int)} to query
+     * the effective range of values.
+     * <li>For a mouse, reports the absolute X screen position of the mouse pointer.
+     * The units are display pixels.
+     * <li>For a trackball, reports the relative horizontal displacement of the trackball.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     * <li>For a joystick, reports the absolute X position of the joystick.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     * </ul>
+     * </p>
      *
      * @see #getX(int)
      * @see #getHistoricalX(int, int)
@@ -277,10 +290,21 @@
 
     /**
      * Constant used to identify the Y axis of a motion event.
-     * 
-     * The interpretation of the Y axis varies by input source.
-     * It may represent the Y position of the center of the touch contact area,
-     * a relative vertical displacement of a trackball or joystick, or something else.
+     * <p>
+     * <ul>
+     * <li>For a touch screen, reports the absolute Y screen position of the center of
+     * the touch contact area.  The units are display pixels.
+     * <li>For a touch pad, reports the absolute Y surface position of the center of the touch
+     * contact area.  The units are device-dependent; use {@link InputDevice#getMotionRange(int)}
+     * to query the effective range of values.
+     * <li>For a mouse, reports the absolute Y screen position of the mouse pointer.
+     * The units are display pixels.
+     * <li>For a trackball, reports the relative vertical displacement of the trackball.
+     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+     * <li>For a joystick, reports the absolute Y position of the joystick.
+     * The value is normalized to a range from -1.0 (up or far) to 1.0 (down or near).
+     * </ul>
+     * </p>
      *
      * @see #getY(int)
      * @see #getHistoricalY(int, int)
@@ -291,12 +315,18 @@
 
     /**
      * Constant used to identify the Pressure axis of a motion event.
-     *
-     * The pressure axis specifies a normalized value that describes the approximate
-     * pressure applied to the device by a finger or other tool.
-     * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure),
-     * although values higher than 1 may be generated depending on the calibration of
-     * the input device.
+     * <p>
+     * <ul>
+     * <li>For a touch screen or touch pad, reports the approximate pressure applied to the device
+     * by a finger or other tool.  The value is normalized to a range from
+     * 0 (no pressure at all) to 1 (normal pressure), although values higher than 1
+     * may be generated depending on the calibration of the input device.
+     * <li>For a trackball, the value is set to 1 if the trackball button is pressed
+     * or 0 otherwise.
+     * <li>For a mouse, the value is set to 1 if the primary mouse button is pressed
+     * or 0 otherwise.
+     * </ul>
+     * </p>
      *
      * @see #getPressure(int)
      * @see #getHistoricalPressure(int, int)
@@ -307,17 +337,16 @@
 
     /**
      * Constant used to identify the Size axis of a motion event.
-     *
-     * The size axis specifies a normalized value that describes the approximate size
-     * of the pointer touch area in relation to the maximum detectable size for the device.
-     * It 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.
-     *
-     * To obtain calibrated size information in terms of pixels, use
-     * {@link #AXIS_TOUCH_MAJOR} or {@link #AXIS_TOOL_MAJOR} instead.
+     * <p>
+     * <ul>
+     * <li>For a touch screen or touch pad, reports the approximate size of the contact area in
+     * relation to the maximum detectable size for the device.  The value is normalized
+     * to a range from 0 (smallest detectable size) to 1 (largest detectable size),
+     * although it is not a linear scale.  This value is of very limited use.
+     * To obtain calibrated size information, use
+     * {@link #AXIS_TOUCH_MAJOR} or {@link #AXIS_TOOL_MAJOR}.
+     * </ul>
+     * </p>
      *
      * @see #getSize(int)
      * @see #getHistoricalSize(int, int)
@@ -328,11 +357,17 @@
 
     /**
      * Constant used to identify the TouchMajor axis of a motion event.
-     *
-     * The touch major axis specifies the length of the major axis of an ellipse that
-     * describes the touch area at the point of contact.
-     * If the device is a touch screen, the length is reported in pixels, otherwise it is
-     * reported in device-specific units.
+     * <p>
+     * <ul>
+     * <li>For a touch screen, reports the length of the major axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are display pixels.
+     * <li>For a touch pad, reports the length of the major axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are device-dependent; use {@link InputDevice#getMotionRange(int)}
+     * to query the effective range of values.
+     * </ul>
+     * </p>
      *
      * @see #getTouchMajor(int)
      * @see #getHistoricalTouchMajor(int, int)
@@ -343,11 +378,19 @@
 
     /**
      * Constant used to identify the TouchMinor axis of a motion event.
-     *
-     * The touch major axis specifies the length of the minor axis of an ellipse that
-     * describes the touch area at the point of contact.
-     * If the device is a touch screen, the length is reported in pixels, otherwise it is
-     * reported in device-specific units.
+     * <p>
+     * <ul>
+     * <li>For a touch screen, reports the length of the minor axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are display pixels.
+     * <li>For a touch pad, reports the length of the minor axis of an ellipse that
+     * represents the touch area at the point of contact.
+     * The units are device-dependent; use {@link InputDevice#getMotionRange(int)}
+     * to query the effective range of values.
+     * </ul>
+     * </p><p>
+     * When the touch is circular, the major and minor axis lengths will be equal to one another.
+     * </p>
      *
      * @see #getTouchMinor(int)
      * @see #getHistoricalTouchMinor(int, int)
@@ -358,13 +401,21 @@
 
     /**
      * Constant used to identify the ToolMajor axis of a motion event.
-     *
-     * The tool major axis specifies 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.
-     * If the device is a touch screen, the length is reported in pixels, otherwise it is
-     * reported in device-specific units.
+     * <p>
+     * <ul>
+     * <li>For a touch screen, reports the length of the major axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * <li>For a touch pad, reports the length of the major axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * The units are device-dependent; use {@link InputDevice#getMotionRange(int)}
+     * to query the effective range of values.
+     * </ul>
+     * </p><p>
+     * When the touch is circular, the major and minor axis lengths will be equal to one another.
+     * </p><p>
+     * The tool size may be larger than the touch size since the tool may not be fully
+     * in contact with the touch sensor.
+     * </p>
      *
      * @see #getToolMajor(int)
      * @see #getHistoricalToolMajor(int, int)
@@ -375,13 +426,21 @@
 
     /**
      * Constant used to identify the ToolMinor axis of a motion event.
-     *
-     * The tool minor axis specifies 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.
-     * If the device is a touch screen, the length is reported in pixels, otherwise it is
-     * reported in device-specific units.
+     * <p>
+     * <ul>
+     * <li>For a touch screen, reports the length of the minor axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * <li>For a touch pad, reports the length of the minor axis of an ellipse that
+     * represents the size of the approaching finger or tool used to make contact.
+     * The units are device-dependent; use {@link InputDevice#getMotionRange(int)}
+     * to query the effective range of values.
+     * </ul>
+     * </p><p>
+     * When the touch is circular, the major and minor axis lengths will be equal to one another.
+     * </p><p>
+     * The tool size may be larger than the touch size since the tool may not be fully
+     * in contact with the touch sensor.
+     * </p>
      *
      * @see #getToolMinor(int)
      * @see #getHistoricalToolMinor(int, int)
@@ -392,15 +451,18 @@
 
     /**
      * Constant used to identify the Orientation axis of a motion event.
-     *
-     * The orientation axis specifies the orientation of the touch area and tool area in
-     * radians clockwise from vertical relative to the vertical plane of the device.
-     * An angle of 0 degrees indicates that the major axis of contact is oriented
+     * <p>
+     * <ul>
+     * <li>For a touch screen or touch pad, reports the orientation of the finger
+     * or tool in radians relative to the vertical plane of the device.
+     * An angle of 0 radians 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/2 radians (finger pointing fully left) to PI/2 radians
      * (finger pointing fully right).
+     * </ul>
+     * </p>
      *
      * @see #getOrientation(int)
      * @see #getHistoricalOrientation(int, int)
@@ -409,6 +471,399 @@
      */
     public static final int AXIS_ORIENTATION = 8;
 
+    /**
+     * Constant used to identify the Vertical Scroll axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a mouse, reports the relative movement of vertical scroll wheel.
+     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+     * </ul>
+     * </p><p>
+     * This axis should be used to scroll views vertically.
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_VSCROLL = 9;
+
+    /**
+     * Constant used to identify the Horizontal Scroll axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a mouse, reports the relative movement of horizontal scroll wheel.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     * </ul>
+     * </p><p>
+     * This axis should be used to scroll views horizontally.
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_HSCROLL = 10;
+
+    /**
+     * Constant used to identify the Z axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute Z position of the joystick.
+     * The value is normalized to a range from -1.0 (high) to 1.0 (low).
+     * <em>On game pads with two analog joysticks, this axis is often reinterpreted
+     * to report the absolute X position of the second joystick instead.</em>
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_Z = 11;
+
+    /**
+     * Constant used to identify the X Rotation axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute rotation angle about the X axis.
+     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RX = 12;
+
+    /**
+     * Constant used to identify the Y Rotation axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute rotation angle about the Y axis.
+     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RY = 13;
+
+    /**
+     * Constant used to identify the Z Rotation axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute rotation angle about the Z axis.
+     * The value is normalized to a range from -1.0 (counter-clockwise) to 1.0 (clockwise).
+     * <em>On game pads with two analog joysticks, this axis is often reinterpreted
+     * to report the absolute Y position of the second joystick instead.</em>
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RZ = 14;
+
+    /**
+     * Constant used to identify the Hat X axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute X position of the directional hat control.
+     * The value is normalized to a range from -1.0 (left) to 1.0 (right).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_HAT_X = 15;
+
+    /**
+     * Constant used to identify the Hat Y axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute Y position of the directional hat control.
+     * The value is normalized to a range from -1.0 (up) to 1.0 (down).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_HAT_Y = 16;
+
+    /**
+     * Constant used to identify the Left Trigger axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the left trigger control.
+     * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_LTRIGGER = 17;
+
+    /**
+     * Constant used to identify the Right Trigger axis of a motion event.
+     * <p>
+     * <ul>
+     * <li>For a joystick, reports the absolute position of the right trigger control.
+     * The value is normalized to a range from 0.0 (released) to 1.0 (fully pressed).
+     * </ul>
+     * </p>
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_RTRIGGER = 18;
+
+    /**
+     * Constant used to identify the Generic 1 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_1 = 32;
+
+    /**
+     * Constant used to identify the Generic 2 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_2 = 33;
+
+    /**
+     * Constant used to identify the Generic 3 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_3 = 34;
+
+    /**
+     * Constant used to identify the Generic 4 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_4 = 35;
+
+    /**
+     * Constant used to identify the Generic 5 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_5 = 36;
+
+    /**
+     * Constant used to identify the Generic 6 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_6 = 37;
+
+    /**
+     * Constant used to identify the Generic 7 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_7 = 38;
+
+    /**
+     * Constant used to identify the Generic 8 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_8 = 39;
+
+    /**
+     * Constant used to identify the Generic 9 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_9 = 40;
+
+    /**
+     * Constant used to identify the Generic 10 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_10 = 41;
+
+    /**
+     * Constant used to identify the Generic 11 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_11 = 42;
+
+    /**
+     * Constant used to identify the Generic 12 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_12 = 43;
+
+    /**
+     * Constant used to identify the Generic 13 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_13 = 44;
+
+    /**
+     * Constant used to identify the Generic 14 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_14 = 45;
+
+    /**
+     * Constant used to identify the Generic 15 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_15 = 46;
+
+    /**
+     * Constant used to identify the Generic 16 axis of a motion event.
+     * The interpretation of a generic axis is device-specific.
+     *
+     * @see #getAxisValue(int, int)
+     * @see #getHistoricalAxisValue(int, int, int)
+     * @see MotionEvent.PointerCoords#getAxisValue(int)
+     * @see InputDevice#getMotionRange
+     */
+    public static final int AXIS_GENERIC_16 = 47;
+
+    // NOTE: If you add a new axis here you must also add it to:
+    //  native/include/android/input.h
+    //  frameworks/base/include/ui/KeycodeLabels.h
+
+    // Symbolic names of all axes.
+    private static final SparseArray<String> AXIS_SYMBOLIC_NAMES = new SparseArray<String>();
+    private static void populateAxisSymbolicNames() {
+        SparseArray<String> names = AXIS_SYMBOLIC_NAMES;
+        names.append(AXIS_X, "AXIS_X");
+        names.append(AXIS_Y, "AXIS_Y");
+        names.append(AXIS_PRESSURE, "AXIS_PRESSURE");
+        names.append(AXIS_SIZE, "AXIS_SIZE");
+        names.append(AXIS_TOUCH_MAJOR, "AXIS_TOUCH_MAJOR");
+        names.append(AXIS_TOUCH_MINOR, "AXIS_TOUCH_MINOR");
+        names.append(AXIS_TOOL_MAJOR, "AXIS_TOOL_MAJOR");
+        names.append(AXIS_TOOL_MINOR, "AXIS_TOOL_MINOR");
+        names.append(AXIS_ORIENTATION, "AXIS_ORIENTATION");
+        names.append(AXIS_VSCROLL, "AXIS_VSCROLL");
+        names.append(AXIS_HSCROLL, "AXIS_HSCROLL");
+        names.append(AXIS_Z, "AXIS_Z");
+        names.append(AXIS_RX, "AXIS_RX");
+        names.append(AXIS_RY, "AXIS_RY");
+        names.append(AXIS_RZ, "AXIS_RZ");
+        names.append(AXIS_HAT_X, "AXIS_HAT_X");
+        names.append(AXIS_HAT_Y, "AXIS_HAT_Y");
+        names.append(AXIS_LTRIGGER, "AXIS_LTRIGGER");
+        names.append(AXIS_RTRIGGER, "AXIS_RTRIGGER");
+        names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
+        names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
+        names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");
+        names.append(AXIS_GENERIC_4, "AXIS_GENERIC_4");
+        names.append(AXIS_GENERIC_5, "AXIS_GENERIC_5");
+        names.append(AXIS_GENERIC_6, "AXIS_GENERIC_6");
+        names.append(AXIS_GENERIC_7, "AXIS_GENERIC_7");
+        names.append(AXIS_GENERIC_8, "AXIS_GENERIC_8");
+        names.append(AXIS_GENERIC_9, "AXIS_GENERIC_9");
+        names.append(AXIS_GENERIC_10, "AXIS_GENERIC_10");
+        names.append(AXIS_GENERIC_11, "AXIS_GENERIC_11");
+        names.append(AXIS_GENERIC_12, "AXIS_GENERIC_12");
+        names.append(AXIS_GENERIC_13, "AXIS_GENERIC_13");
+        names.append(AXIS_GENERIC_14, "AXIS_GENERIC_14");
+        names.append(AXIS_GENERIC_15, "AXIS_GENERIC_15");
+        names.append(AXIS_GENERIC_16, "AXIS_GENERIC_16");
+    }
+
+    static {
+        populateAxisSymbolicNames();
+    }
+
     // Private value for history pos that obtains the current sample.
     private static final int HISTORY_CURRENT = -0x80000000;
 
@@ -1081,7 +1536,7 @@
      * 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
+     * An angle of 0 radians 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.
@@ -1737,34 +2192,40 @@
 
     /**
      * Returns a string that represents the symbolic name of the specified axis
-     * such as "AXIS_X" or an equivalent numeric constants such as "42" if unknown.
+     * such as "AXIS_X" or an equivalent numeric constant such as "42" if unknown.
      *
      * @param axis The axis
      * @return The symbolic name of the specified axis.
-     * @hide
      */
     public static String axisToString(int axis) {
-        switch (axis) {
-            case AXIS_X:
-                return "AXIS_X";
-            case AXIS_Y:
-                return "AXIS_Y";
-            case AXIS_PRESSURE:
-                return "AXIS_PRESSURE";
-            case AXIS_SIZE:
-                return "AXIS_SIZE";
-            case AXIS_TOUCH_MAJOR:
-                return "AXIS_TOUCH_MAJOR";
-            case AXIS_TOUCH_MINOR:
-                return "AXIS_TOUCH_MINOR";
-            case AXIS_TOOL_MAJOR:
-                return "AXIS_TOOL_MAJOR";
-            case AXIS_TOOL_MINOR:
-                return "AXIS_TOOL_MINOR";
-            case AXIS_ORIENTATION:
-                return "AXIS_ORIENTATION";
-            default:
-                return Integer.toString(axis);
+        String symbolicName = AXIS_SYMBOLIC_NAMES.get(axis);
+        return symbolicName != null ? symbolicName : Integer.toString(axis);
+    }
+
+    /**
+     * Gets an axis by its symbolic name such as "KEYCODE_A" or an
+     * equivalent numeric constant such as "1001".
+     *
+     * @param symbolicName The symbolic name of the axis.
+     * @return The axis or -1 if not found.
+     * @see #keycodeToString
+     */
+    public static int axisFromString(String symbolicName) {
+        if (symbolicName == null) {
+            throw new IllegalArgumentException("symbolicName must not be null");
+        }
+
+        final int count = AXIS_SYMBOLIC_NAMES.size();
+        for (int i = 0; i < count; i++) {
+            if (symbolicName.equals(AXIS_SYMBOLIC_NAMES.valueAt(i))) {
+                return i;
+            }
+        }
+
+        try {
+            return Integer.parseInt(symbolicName, 10);
+        } catch (NumberFormatException ex) {
+            return -1;
         }
     }
 
@@ -1803,7 +2264,7 @@
      */
     public static final class PointerCoords {
         private static final int INITIAL_PACKED_AXIS_VALUES = 8;
-        private int mPackedAxisBits; // 32bits are enough for now, can raise to 64bit when needed
+        private long mPackedAxisBits;
         private float[] mPackedAxisValues;
 
         /**
@@ -1823,20 +2284,14 @@
         }
 
         /**
-         * The X coordinate of the pointer movement.
-         * The interpretation of the X axis varies by input source.
-         * It may represent the X position of the center of the touch contact area,
-         * a relative horizontal displacement of a trackball or joystick, or something else.
+         * The X component of the pointer movement.
          *
          * @see MotionEvent#AXIS_X
          */
         public float x;
         
         /**
-         * The Y coordinate of the pointer movement.
-         * The interpretation of the Y axis varies by input source.
-         * It may represent the Y position of the center of the touch contact area,
-         * a relative vertical displacement of a trackball or joystick, or something else.
+         * The Y component of the pointer movement.
          *
          * @see MotionEvent#AXIS_Y
          */
@@ -1912,7 +2367,7 @@
         
         /**
          * 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
+         * An angle of 0 radians 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.
@@ -1947,11 +2402,11 @@
          * @param other The pointer coords object to copy.
          */
         public void copyFrom(PointerCoords other) {
-            final int bits = other.mPackedAxisBits;
+            final long bits = other.mPackedAxisBits;
             mPackedAxisBits = bits;
             if (bits != 0) {
                 final float[] otherValues = other.mPackedAxisValues;
-                final int count = Integer.bitCount(bits);
+                final int count = Long.bitCount(bits);
                 float[] values = mPackedAxisValues;
                 if (values == null || count > values.length) {
                     values = new float[otherValues.length];
@@ -2001,12 +2456,15 @@
                 case AXIS_ORIENTATION:
                     return orientation;
                 default: {
-                    final int bits = mPackedAxisBits;
-                    final int axisBit = 1 << axis;
+                    if (axis < 0 || axis > 63) {
+                        throw new IllegalArgumentException("Axis out of range.");
+                    }
+                    final long bits = mPackedAxisBits;
+                    final long axisBit = 1L << axis;
                     if ((bits & axisBit) == 0) {
                         return 0;
                     }
-                    final int index = Integer.bitCount(bits & (axisBit - 1));
+                    final int index = Long.bitCount(bits & (axisBit - 1L));
                     return mPackedAxisValues[index];
                 }
             }
@@ -2051,16 +2509,19 @@
                     orientation = value;
                     break;
                 default: {
-                    final int bits = mPackedAxisBits;
-                    final int axisBit = 1 << axis;
-                    final int index = Integer.bitCount(bits & (axisBit - 1));
+                    if (axis < 0 || axis > 63) {
+                        throw new IllegalArgumentException("Axis out of range.");
+                    }
+                    final long bits = mPackedAxisBits;
+                    final long axisBit = 1L << axis;
+                    final int index = Long.bitCount(bits & (axisBit - 1L));
                     float[] values = mPackedAxisValues;
                     if ((bits & axisBit) == 0) {
                         if (values == null) {
                             values = new float[INITIAL_PACKED_AXIS_VALUES];
                             mPackedAxisValues = values;
                         } else {
-                            final int count = Integer.bitCount(bits);
+                            final int count = Long.bitCount(bits);
                             if (count < values.length) {
                                 if (index != count) {
                                     System.arraycopy(values, index, values, index + 1,
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ec1a373..39f99b8 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -2496,7 +2496,6 @@
 
         // Deliver the event to the view.
         if (mView.dispatchGenericMotionEvent(event)) {
-            ensureTouchMode(false);
             if (isJoystick) {
                 updateJoystickDirection(event, false);
             }
@@ -2525,8 +2524,16 @@
         final int metaState = event.getMetaState();
         final int deviceId = event.getDeviceId();
         final int source = event.getSource();
-        final int xDirection = joystickAxisValueToDirection(event.getX());
-        final int yDirection = joystickAxisValueToDirection(event.getY());
+
+        int xDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_X));
+        if (xDirection == 0) {
+            xDirection = joystickAxisValueToDirection(event.getX());
+        }
+
+        int yDirection = joystickAxisValueToDirection(event.getAxisValue(MotionEvent.AXIS_HAT_Y));
+        if (yDirection == 0) {
+            yDirection = joystickAxisValueToDirection(event.getY());
+        }
 
         if (xDirection != mLastJoystickXDirection) {
             if (mLastJoystickXKeyCode != 0) {
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 0b765fd..4a6857c 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -327,7 +327,10 @@
                 .append(" ToolMajor=").append(coords.toolMajor, 3)
                 .append(" ToolMinor=").append(coords.toolMinor, 3)
                 .append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1)
-                .append("deg").toString());
+                .append("deg")
+                .append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1)
+                .append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1)
+                .toString());
     }
 
     public void addTouchEvent(MotionEvent event) {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 069e40b..5ba1cff 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -207,8 +207,7 @@
     outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
             env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
 
-    uint32_t bits = env->GetIntField(pointerCoordsObj,
-            gPointerCoordsClassInfo.mPackedAxisBits);
+    uint64_t bits = env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits);
     if (bits) {
         jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
                 gPointerCoordsClassInfo.mPackedAxisValues));
@@ -219,7 +218,7 @@
             uint32_t index = 0;
             do {
                 uint32_t axis = __builtin_ctz(bits);
-                uint32_t axisBit = 1 << axis;
+                uint64_t axisBit = 1LL << axis;
                 bits &= ~axisBit;
                 outRawPointerCoords->setAxisValue(axis, values[index++]);
             } while (bits);
@@ -272,21 +271,21 @@
     env->SetFloatField(outPointerCoordsObj, gPointerCoordsClassInfo.orientation,
             rawPointerCoords->getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
 
-    const uint32_t unpackedAxisBits = 0
-            | (1 << AMOTION_EVENT_AXIS_X)
-            | (1 << AMOTION_EVENT_AXIS_Y)
-            | (1 << AMOTION_EVENT_AXIS_PRESSURE)
-            | (1 << AMOTION_EVENT_AXIS_SIZE)
-            | (1 << AMOTION_EVENT_AXIS_TOUCH_MAJOR)
-            | (1 << AMOTION_EVENT_AXIS_TOUCH_MINOR)
-            | (1 << AMOTION_EVENT_AXIS_TOOL_MAJOR)
-            | (1 << AMOTION_EVENT_AXIS_TOOL_MINOR)
-            | (1 << AMOTION_EVENT_AXIS_ORIENTATION);
+    const uint64_t unpackedAxisBits = 0
+            | (1LL << AMOTION_EVENT_AXIS_X)
+            | (1LL << AMOTION_EVENT_AXIS_Y)
+            | (1LL << AMOTION_EVENT_AXIS_PRESSURE)
+            | (1LL << AMOTION_EVENT_AXIS_SIZE)
+            | (1LL << AMOTION_EVENT_AXIS_TOUCH_MAJOR)
+            | (1LL << AMOTION_EVENT_AXIS_TOUCH_MINOR)
+            | (1LL << AMOTION_EVENT_AXIS_TOOL_MAJOR)
+            | (1LL << AMOTION_EVENT_AXIS_TOOL_MINOR)
+            | (1LL << AMOTION_EVENT_AXIS_ORIENTATION);
 
-    uint32_t outBits = 0;
-    uint32_t remainingBits = rawPointerCoords->bits & ~unpackedAxisBits;
+    uint64_t outBits = 0;
+    uint64_t remainingBits = rawPointerCoords->bits & ~unpackedAxisBits;
     if (remainingBits) {
-        uint32_t packedAxesCount = __builtin_popcount(remainingBits);
+        uint32_t packedAxesCount = __builtin_popcountll(remainingBits);
         jfloatArray outValuesArray = obtainPackedAxisValuesArray(env, packedAxesCount,
                 outPointerCoordsObj);
         if (!outValuesArray) {
@@ -300,7 +299,7 @@
         uint32_t index = 0;
         do {
             uint32_t axis = __builtin_ctz(remainingBits);
-            uint32_t axisBit = 1 << axis;
+            uint64_t axisBit = 1LL << axis;
             remainingBits &= ~axisBit;
             outBits |= axisBit;
             outValues[index++] = rawPointerCoords->getAxisValue(axis);
@@ -309,7 +308,7 @@
         env->ReleasePrimitiveArrayCritical(outValuesArray, outValues, 0);
         env->DeleteLocalRef(outValuesArray);
     }
-    env->SetIntField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits);
+    env->SetLongField(outPointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits, outBits);
 }
 
 
@@ -758,7 +757,7 @@
     FIND_CLASS(gPointerCoordsClassInfo.clazz, "android/view/MotionEvent$PointerCoords");
 
     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisBits, gPointerCoordsClassInfo.clazz,
-            "mPackedAxisBits", "I");
+            "mPackedAxisBits", "J");
     GET_FIELD_ID(gPointerCoordsClassInfo.mPackedAxisValues, gPointerCoordsClassInfo.clazz,
             "mPackedAxisValues", "[F");
     GET_FIELD_ID(gPointerCoordsClassInfo.x, gPointerCoordsClassInfo.clazz,