Merge "Import revised translations."
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 2012fcc..b7b5a8d 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -28,6 +28,10 @@
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 
+#ifdef HAVE_ANDROID_OS
+class SkMatrix;
+#endif
+
 /*
  * Additional private constants not defined in ndk/ui/input.h.
  */
@@ -79,6 +83,10 @@
 
 namespace android {
 
+#ifdef HAVE_ANDROID_OS
+class Parcel;
+#endif
+
 /*
  * Flags that flow alongside events in the input dispatch system to help with certain
  * policy decisions such as waking from device sleep.
@@ -162,15 +170,61 @@
  * Pointer coordinate data.
  */
 struct PointerCoords {
-    float x;
-    float y;
-    float pressure;
-    float size;
-    float touchMajor;
-    float touchMinor;
-    float toolMajor;
-    float toolMinor;
-    float orientation;
+    static const size_t MAX_AXES = 15; // 15 so that sizeof(PointerCoords) == 16 * 4 == 64
+
+    // Bitfield of axes that are present in this structure.
+    uint32_t bits; // 32bits are enough for now, can raise to 64bit when needed
+
+    // Values of axes that are stored in this structure packed in order by axis id
+    // for each axis that is present in the structure according to 'bits'.
+    float values[MAX_AXES];
+
+    inline void clear() {
+        bits = 0;
+    }
+
+    inline float getAxisValue(int32_t axis) const {
+        uint32_t axisBit = 1 << axis;
+        if (!(bits & axisBit)) {
+            return 0;
+        }
+        uint32_t index = __builtin_popcount(bits & (axisBit - 1));
+        return values[index];
+    }
+
+    inline void setAxisValue(int32_t axis, float value) {
+        uint32_t axisBit = 1 << axis;
+        uint32_t index = __builtin_popcount(bits & (axisBit - 1));
+        if (!(bits & axisBit)) {
+            uint32_t count = __builtin_popcount(bits);
+            if (count >= MAX_AXES) {
+                tooManyAxes(axis);
+                return;
+            }
+            bits |= axisBit;
+            for (uint32_t i = count; i > index; i--) {
+                values[i] = values[i - 1];
+            }
+        }
+        values[index] = value;
+    }
+
+    inline float* editAxisValue(int32_t axis) {
+        uint32_t axisBit = 1 << axis;
+        if (!(bits & axisBit)) {
+            return NULL;
+        }
+        uint32_t index = __builtin_popcount(bits & (axisBit - 1));
+        return &values[index];
+    }
+
+#ifdef HAVE_ANDROID_OS
+    status_t readFromParcel(Parcel* parcel);
+    status_t writeToParcel(Parcel* parcel) const;
+#endif
+
+private:
+    void tooManyAxes(int axis);
 };
 
 /*
@@ -185,12 +239,13 @@
     inline int32_t getDeviceId() const { return mDeviceId; }
 
     inline int32_t getSource() const { return mSource; }
-    
+
+    inline void setSource(int32_t source) { mSource = source; }
+
 protected:
     void initialize(int32_t deviceId, int32_t source);
     void initialize(const InputEvent& from);
 
-private:
     int32_t mDeviceId;
     int32_t mSource;
 };
@@ -241,7 +296,7 @@
             nsecs_t eventTime);
     void initialize(const KeyEvent& from);
 
-private:
+protected:
     int32_t mAction;
     int32_t mFlags;
     int32_t mKeyCode;
@@ -263,12 +318,18 @@
 
     inline int32_t getAction() const { return mAction; }
 
+    inline void setAction(int32_t action) { mAction = action; }
+
     inline int32_t getFlags() const { return mFlags; }
 
     inline int32_t getEdgeFlags() const { return mEdgeFlags; }
 
+    inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; }
+
     inline int32_t getMetaState() const { return mMetaState; }
 
+    inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
+
     inline float getXOffset() const { return mXOffset; }
 
     inline float getYOffset() const { return mYOffset; }
@@ -285,48 +346,54 @@
 
     inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
 
+    const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
+
+    float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
+
     inline float getRawX(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).x;
+        return getRawAxisValue(AINPUT_MOTION_AXIS_X, pointerIndex);
     }
 
     inline float getRawY(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).y;
+        return getRawAxisValue(AINPUT_MOTION_AXIS_Y, pointerIndex);
     }
 
+    float getAxisValue(int32_t axis, size_t pointerIndex) const;
+
     inline float getX(size_t pointerIndex) const {
-        return getRawX(pointerIndex) + mXOffset;
+        return getAxisValue(AINPUT_MOTION_AXIS_X, pointerIndex);
     }
 
     inline float getY(size_t pointerIndex) const {
-        return getRawY(pointerIndex) + mYOffset;
+        return getAxisValue(AINPUT_MOTION_AXIS_Y, pointerIndex);
     }
 
     inline float getPressure(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).pressure;
+        return getAxisValue(AINPUT_MOTION_AXIS_PRESSURE, pointerIndex);
     }
 
     inline float getSize(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).size;
+        return getAxisValue(AINPUT_MOTION_AXIS_SIZE, pointerIndex);
     }
 
     inline float getTouchMajor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).touchMajor;
+        return getAxisValue(AINPUT_MOTION_AXIS_TOUCH_MAJOR, pointerIndex);
     }
 
     inline float getTouchMinor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).touchMinor;
+        return getAxisValue(AINPUT_MOTION_AXIS_TOUCH_MINOR, pointerIndex);
     }
 
     inline float getToolMajor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).toolMajor;
+        return getAxisValue(AINPUT_MOTION_AXIS_TOOL_MAJOR, pointerIndex);
     }
 
     inline float getToolMinor(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).toolMinor;
+        return getAxisValue(AINPUT_MOTION_AXIS_TOOL_MINOR, pointerIndex);
     }
 
     inline float getOrientation(size_t pointerIndex) const {
-        return getCurrentPointerCoords(pointerIndex).orientation;
+        return getAxisValue(AINPUT_MOTION_AXIS_ORIENTATION, pointerIndex);
     }
 
     inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; }
@@ -335,48 +402,67 @@
         return mSampleEventTimes[historicalIndex];
     }
 
+    const PointerCoords* getHistoricalRawPointerCoords(
+            size_t pointerIndex, size_t historicalIndex) const;
+
+    float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
+            size_t historicalIndex) const;
+
     inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).x;
+        return getHistoricalRawAxisValue(
+                AINPUT_MOTION_AXIS_X, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).y;
+        return getHistoricalRawAxisValue(
+                AINPUT_MOTION_AXIS_Y, pointerIndex, historicalIndex);
     }
 
+    float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const;
+
     inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalRawX(pointerIndex, historicalIndex) + mXOffset;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_X, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalRawY(pointerIndex, historicalIndex) + mYOffset;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_Y, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).pressure;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_PRESSURE, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).size;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_SIZE, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMajor;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).touchMinor;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMajor;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).toolMinor;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_TOOL_MINOR, pointerIndex, historicalIndex);
     }
 
     inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const {
-        return getHistoricalPointerCoords(pointerIndex, historicalIndex).orientation;
+        return getHistoricalAxisValue(
+                AINPUT_MOTION_AXIS_ORIENTATION, pointerIndex, historicalIndex);
     }
 
     void initialize(
@@ -396,12 +482,23 @@
             const int32_t* pointerIds,
             const PointerCoords* pointerCoords);
 
+    void copyFrom(const MotionEvent* other, bool keepHistory);
+
     void addSample(
             nsecs_t eventTime,
             const PointerCoords* pointerCoords);
 
     void offsetLocation(float xOffset, float yOffset);
 
+    void scale(float scaleFactor);
+
+#ifdef HAVE_ANDROID_OS
+    void transform(const SkMatrix* matrix);
+
+    status_t readFromParcel(Parcel* parcel);
+    status_t writeToParcel(Parcel* parcel) const;
+#endif
+
     // Low-level accessors.
     inline const int32_t* getPointerIds() const { return mPointerIds.array(); }
     inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
@@ -409,7 +506,7 @@
             return mSamplePointerCoords.array();
     }
 
-private:
+protected:
     int32_t mAction;
     int32_t mFlags;
     int32_t mEdgeFlags;
@@ -422,15 +519,6 @@
     Vector<int32_t> mPointerIds;
     Vector<nsecs_t> mSampleEventTimes;
     Vector<PointerCoords> mSamplePointerCoords;
-
-    inline const PointerCoords& getCurrentPointerCoords(size_t pointerIndex) const {
-        return mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
-    }
-
-    inline const PointerCoords& getHistoricalPointerCoords(
-            size_t pointerIndex, size_t historicalIndex) const {
-        return mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
-    }
 };
 
 /*
@@ -486,11 +574,11 @@
     inline const String8 getName() const { return mName; }
     inline uint32_t getSources() const { return mSources; }
 
-    const MotionRange* getMotionRange(int32_t rangeType) const;
+    const MotionRange* getMotionRange(int32_t axis) const;
 
     void addSource(uint32_t source);
-    void addMotionRange(int32_t rangeType, float min, float max, float flat, float fuzz);
-    void addMotionRange(int32_t rangeType, const MotionRange& range);
+    void addMotionRange(int32_t axis, float min, float max, float flat, float fuzz);
+    void addMotionRange(int32_t axis, const MotionRange& range);
 
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 0d55f08..f9990bb 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -60,7 +60,12 @@
 	libEGL \
 	libpixelflinger \
 	libhardware \
-	libhardware_legacy
+	libhardware_legacy \
+	libskia \
+	libbinder
+
+LOCAL_C_INCLUDES := \
+    external/skia/include/core
 
 LOCAL_MODULE:= libui
 
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index b8d59e6..90b954e 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -15,6 +15,16 @@
 
 #include <ui/Input.h>
 
+#include <math.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <binder/Parcel.h>
+
+#include "SkPoint.h"
+#include "SkMatrix.h"
+#include "SkScalar.h"
+#endif
+
 namespace android {
 
 static const char* CONFIGURATION_FILE_DIR[] = {
@@ -237,6 +247,41 @@
     mEventTime = from.mEventTime;
 }
 
+
+// --- PointerCoords ---
+
+#ifdef HAVE_ANDROID_OS
+status_t PointerCoords::readFromParcel(Parcel* parcel) {
+    bits = parcel->readInt32();
+
+    uint32_t count = __builtin_popcount(bits);
+    if (count > MAX_AXES) {
+        return BAD_VALUE;
+    }
+
+    for (uint32_t i = 0; i < count; i++) {
+        values[i] = parcel->readInt32();
+    }
+    return OK;
+}
+
+status_t PointerCoords::writeToParcel(Parcel* parcel) const {
+    parcel->writeInt32(bits);
+
+    uint32_t count = __builtin_popcount(bits);
+    for (uint32_t i = 0; i < count; i++) {
+        parcel->writeInt32(values[i]);
+    }
+    return OK;
+}
+#endif
+
+void PointerCoords::tooManyAxes(int axis) {
+    LOGW("Could not set value for axis %d because the PointerCoords structure is full and "
+            "cannot contain more than %d axis values.", axis, int(MAX_AXES));
+}
+
+
 // --- MotionEvent ---
 
 void MotionEvent::initialize(
@@ -272,6 +317,33 @@
     addSample(eventTime, pointerCoords);
 }
 
+void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
+    InputEvent::initialize(other->mDeviceId, other->mSource);
+    mAction = other->mAction;
+    mFlags = other->mFlags;
+    mEdgeFlags = other->mEdgeFlags;
+    mMetaState = other->mMetaState;
+    mXOffset = other->mXOffset;
+    mYOffset = other->mYOffset;
+    mXPrecision = other->mXPrecision;
+    mYPrecision = other->mYPrecision;
+    mDownTime = other->mDownTime;
+    mPointerIds = other->mPointerIds;
+
+    if (keepHistory) {
+        mSampleEventTimes = other->mSampleEventTimes;
+        mSamplePointerCoords = other->mSamplePointerCoords;
+    } else {
+        mSampleEventTimes.clear();
+        mSampleEventTimes.push(other->getEventTime());
+        mSamplePointerCoords.clear();
+        size_t pointerCount = other->getPointerCount();
+        size_t historySize = other->getHistorySize();
+        mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array()
+                + (historySize * pointerCount), pointerCount);
+    }
+}
+
 void MotionEvent::addSample(
         int64_t eventTime,
         const PointerCoords* pointerCoords) {
@@ -279,11 +351,224 @@
     mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
 }
 
+const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
+    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
+}
+
+float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
+    return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+}
+
+float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
+    float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+    switch (axis) {
+    case AINPUT_MOTION_AXIS_X:
+        value += mXOffset;
+        break;
+    case AINPUT_MOTION_AXIS_Y:
+        value += mYOffset;
+        break;
+    }
+    return value;
+}
+
+const PointerCoords* MotionEvent::getHistoricalRawPointerCoords(
+        size_t pointerIndex, size_t historicalIndex) const {
+    return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex];
+}
+
+float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
+        size_t historicalIndex) const {
+    return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+}
+
+float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
+        size_t historicalIndex) const {
+    float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+    switch (axis) {
+    case AINPUT_MOTION_AXIS_X:
+        value += mXOffset;
+        break;
+    case AINPUT_MOTION_AXIS_Y:
+        value += mYOffset;
+        break;
+    }
+    return value;
+}
+
 void MotionEvent::offsetLocation(float xOffset, float yOffset) {
     mXOffset += xOffset;
     mYOffset += yOffset;
 }
 
+static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
+    float* value = c.editAxisValue(axis);
+    if (value) {
+        *value *= scaleFactor;
+    }
+}
+
+void MotionEvent::scale(float scaleFactor) {
+    mXOffset *= scaleFactor;
+    mYOffset *= scaleFactor;
+    mXPrecision *= scaleFactor;
+    mYPrecision *= scaleFactor;
+
+    size_t numSamples = mSamplePointerCoords.size();
+    for (size_t i = 0; i < numSamples; i++) {
+        PointerCoords& c = mSamplePointerCoords.editItemAt(i);
+        // No need to scale pressure or size since they are normalized.
+        // No need to scale orientation since it is meaningless to do so.
+        scaleAxisValue(c, AINPUT_MOTION_AXIS_X, scaleFactor);
+        scaleAxisValue(c, AINPUT_MOTION_AXIS_Y, scaleFactor);
+        scaleAxisValue(c, AINPUT_MOTION_AXIS_TOUCH_MAJOR, scaleFactor);
+        scaleAxisValue(c, AINPUT_MOTION_AXIS_TOUCH_MINOR, scaleFactor);
+        scaleAxisValue(c, AINPUT_MOTION_AXIS_TOOL_MAJOR, scaleFactor);
+        scaleAxisValue(c, AINPUT_MOTION_AXIS_TOOL_MINOR, scaleFactor);
+    }
+}
+
+#ifdef HAVE_ANDROID_OS
+static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
+    // Construct and transform a vector oriented at the specified clockwise angle from vertical.
+    // Coordinate system: down is increasing Y, right is increasing X.
+    SkPoint vector;
+    vector.fX = SkFloatToScalar(sinf(angleRadians));
+    vector.fY = SkFloatToScalar(-cosf(angleRadians));
+    matrix->mapVectors(& vector, 1);
+
+    // Derive the transformed vector's clockwise angle from vertical.
+    float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
+    if (result < - M_PI_2) {
+        result += M_PI;
+    } else if (result > M_PI_2) {
+        result -= M_PI;
+    }
+    return result;
+}
+
+void MotionEvent::transform(const SkMatrix* matrix) {
+    float oldXOffset = mXOffset;
+    float oldYOffset = mYOffset;
+
+    // The tricky part of this implementation is to preserve the value of
+    // rawX and rawY.  So we apply the transformation to the first point
+    // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
+    SkPoint point;
+    float rawX = getRawX(0);
+    float rawY = getRawY(0);
+    matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
+            & point);
+    float newX = SkScalarToFloat(point.fX);
+    float newY = SkScalarToFloat(point.fY);
+    float newXOffset = newX - rawX;
+    float newYOffset = newY - rawY;
+
+    mXOffset = newXOffset;
+    mYOffset = newYOffset;
+
+    // Apply the transformation to all samples.
+    size_t numSamples = mSamplePointerCoords.size();
+    for (size_t i = 0; i < numSamples; i++) {
+        PointerCoords& c = mSamplePointerCoords.editItemAt(i);
+        float* xPtr = c.editAxisValue(AINPUT_MOTION_AXIS_X);
+        float* yPtr = c.editAxisValue(AINPUT_MOTION_AXIS_Y);
+        if (xPtr && yPtr) {
+            float x = *xPtr + oldXOffset;
+            float y = *yPtr + oldYOffset;
+            matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point);
+            *xPtr = SkScalarToFloat(point.fX) - newXOffset;
+            *yPtr = SkScalarToFloat(point.fY) - newYOffset;
+        }
+
+        float* orientationPtr = c.editAxisValue(AINPUT_MOTION_AXIS_ORIENTATION);
+        if (orientationPtr) {
+            *orientationPtr = transformAngle(matrix, *orientationPtr);
+        }
+    }
+}
+
+status_t MotionEvent::readFromParcel(Parcel* parcel) {
+    size_t pointerCount = parcel->readInt32();
+    size_t sampleCount = parcel->readInt32();
+    if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
+        return BAD_VALUE;
+    }
+
+    mDeviceId = parcel->readInt32();
+    mSource = parcel->readInt32();
+    mAction = parcel->readInt32();
+    mFlags = parcel->readInt32();
+    mEdgeFlags = parcel->readInt32();
+    mMetaState = parcel->readInt32();
+    mXOffset = parcel->readFloat();
+    mYOffset = parcel->readFloat();
+    mXPrecision = parcel->readFloat();
+    mYPrecision = parcel->readFloat();
+    mDownTime = parcel->readInt64();
+
+    mPointerIds.clear();
+    mPointerIds.setCapacity(pointerCount);
+    mSampleEventTimes.clear();
+    mSampleEventTimes.setCapacity(sampleCount);
+    mSamplePointerCoords.clear();
+    mSamplePointerCoords.setCapacity(sampleCount * pointerCount);
+
+    for (size_t i = 0; i < pointerCount; i++) {
+        mPointerIds.push(parcel->readInt32());
+    }
+
+    while (sampleCount-- > 0) {
+        mSampleEventTimes.push(parcel->readInt64());
+        for (size_t i = 0; i < pointerCount; i++) {
+            mSamplePointerCoords.push();
+            status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel);
+            if (!status) {
+                return status;
+            }
+        }
+    }
+    return OK;
+}
+
+status_t MotionEvent::writeToParcel(Parcel* parcel) const {
+    size_t pointerCount = mPointerIds.size();
+    size_t sampleCount = mSampleEventTimes.size();
+
+    parcel->writeInt32(pointerCount);
+    parcel->writeInt32(sampleCount);
+
+    parcel->writeInt32(mDeviceId);
+    parcel->writeInt32(mSource);
+    parcel->writeInt32(mAction);
+    parcel->writeInt32(mFlags);
+    parcel->writeInt32(mEdgeFlags);
+    parcel->writeInt32(mMetaState);
+    parcel->writeFloat(mXOffset);
+    parcel->writeFloat(mYOffset);
+    parcel->writeFloat(mXPrecision);
+    parcel->writeFloat(mYPrecision);
+    parcel->writeInt64(mDownTime);
+
+    for (size_t i = 0; i < pointerCount; i++) {
+        parcel->writeInt32(mPointerIds.itemAt(i));
+    }
+
+    const PointerCoords* pc = mSamplePointerCoords.array();
+    for (size_t h = 0; h < sampleCount; h++) {
+        parcel->writeInt64(mSampleEventTimes.itemAt(h));
+        for (size_t i = 0; i < pointerCount; i++) {
+            status_t status = (pc++)->writeToParcel(parcel);
+            if (!status) {
+                return status;
+            }
+        }
+    }
+    return OK;
+}
+#endif
+
+
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
@@ -307,8 +592,8 @@
     mMotionRanges.clear();
 }
 
-const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t rangeType) const {
-    ssize_t index = mMotionRanges.indexOfKey(rangeType);
+const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange(int32_t axis) const {
+    ssize_t index = mMotionRanges.indexOfKey(axis);
     return index >= 0 ? & mMotionRanges.valueAt(index) : NULL;
 }
 
@@ -316,14 +601,14 @@
     mSources |= source;
 }
 
-void InputDeviceInfo::addMotionRange(int32_t rangeType, float min, float max,
+void InputDeviceInfo::addMotionRange(int32_t axis, float min, float max,
         float flat, float fuzz) {
     MotionRange range = { min, max, flat, fuzz };
-    addMotionRange(rangeType, range);
+    addMotionRange(axis, range);
 }
 
-void InputDeviceInfo::addMotionRange(int32_t rangeType, const MotionRange& range) {
-    mMotionRanges.add(rangeType, range);
+void InputDeviceInfo::addMotionRange(int32_t axis, const MotionRange& range) {
+    mMotionRanges.add(axis, range);
 }
 
 } // namespace android
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 903fcaf..1819a8b 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -159,15 +159,17 @@
         sampleEventTimes.push(i + 10);
         for (size_t j = 0; j < pointerCount; j++) {
             samplePointerCoords.push();
-            samplePointerCoords.editTop().x = 100 * i + j;
-            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;
+            PointerCoords& pc = samplePointerCoords.editTop();
+            pc.clear();
+            pc.setAxisValue(AINPUT_MOTION_AXIS_X, 100 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_Y, 200 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_PRESSURE, 0.5 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_SIZE, 0.7 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_TOUCH_MAJOR, 1.5 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_TOUCH_MINOR, 1.7 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_TOOL_MAJOR, 2.5 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_TOOL_MAJOR, 2.7 * i + j);
+            pc.setAxisValue(AINPUT_MOTION_AXIS_ORIENTATION, 3.5 * i + j);
         }
     }
 
@@ -239,27 +241,27 @@
         for (size_t i = 0; i < pointerCount; i++) {
             SCOPED_TRACE(i);
             size_t offset = sampleIndex * pointerCount + i;
-            EXPECT_EQ(samplePointerCoords[offset].x,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_X),
                     motionEvent->getHistoricalRawX(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].y,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_Y),
                     motionEvent->getHistoricalRawY(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].x + xOffset,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_X) + xOffset,
                     motionEvent->getHistoricalX(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].y + yOffset,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_Y) + yOffset,
                     motionEvent->getHistoricalY(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].pressure,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_PRESSURE),
                     motionEvent->getHistoricalPressure(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].size,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_SIZE),
                     motionEvent->getHistoricalSize(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].touchMajor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOUCH_MAJOR),
                     motionEvent->getHistoricalTouchMajor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].touchMinor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOUCH_MINOR),
                     motionEvent->getHistoricalTouchMinor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].toolMajor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOOL_MAJOR),
                     motionEvent->getHistoricalToolMajor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].toolMinor,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOOL_MINOR),
                     motionEvent->getHistoricalToolMinor(i, sampleIndex));
-            EXPECT_EQ(samplePointerCoords[offset].orientation,
+            EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_ORIENTATION),
                     motionEvent->getHistoricalOrientation(i, sampleIndex));
         }
     }
@@ -269,17 +271,28 @@
     for (size_t i = 0; i < pointerCount; i++) {
         SCOPED_TRACE(i);
         size_t offset = lastSampleIndex * pointerCount + i;
-        EXPECT_EQ(samplePointerCoords[offset].x, motionEvent->getRawX(i));
-        EXPECT_EQ(samplePointerCoords[offset].y, motionEvent->getRawY(i));
-        EXPECT_EQ(samplePointerCoords[offset].x + xOffset, motionEvent->getX(i));
-        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));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_X),
+                motionEvent->getRawX(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_Y),
+                motionEvent->getRawY(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_X) + xOffset,
+                motionEvent->getX(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_Y) + yOffset,
+                motionEvent->getY(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_PRESSURE),
+                motionEvent->getPressure(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_SIZE),
+                motionEvent->getSize(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOUCH_MAJOR),
+                motionEvent->getTouchMajor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOUCH_MINOR),
+                motionEvent->getTouchMinor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOOL_MAJOR),
+                motionEvent->getToolMajor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_TOOL_MINOR),
+                motionEvent->getToolMinor(i));
+        EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AINPUT_MOTION_AXIS_ORIENTATION),
+                motionEvent->getOrientation(i));
     }
 
     status = mConsumer->sendFinishedSignal(false);
@@ -328,7 +341,8 @@
 
     const size_t pointerCount = 1;
     int32_t pointerIds[pointerCount] = { 0 };
-    PointerCoords pointerCoords[pointerCount] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
+    PointerCoords pointerCoords[pointerCount];
+    pointerCoords[0].clear();
 
     status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             pointerCount, pointerIds, pointerCoords);