Merge "Remove useless code."
diff --git a/include/ui/Input.h b/include/ui/Input.h
index c7ebf56..ba1c6b4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -157,14 +157,6 @@
 };
 
 /*
- * Button state.
- */
-enum {
-    // Primary button pressed (left mouse button).
-    BUTTON_STATE_PRIMARY = 1 << 0,
-};
-
-/*
  * Describes the basic configuration of input devices that are present.
  */
 struct InputConfiguration {
@@ -235,6 +227,29 @@
 };
 
 /*
+ * Pointer property data.
+ */
+struct PointerProperties {
+    // The id of the pointer.
+    int32_t id;
+
+    // The pointer tool type.
+    int32_t toolType;
+
+    inline void clear() {
+        id = -1;
+        toolType = 0;
+    }
+
+    bool operator==(const PointerProperties& other) const;
+    inline bool operator!=(const PointerProperties& other) const {
+        return !(*this == other);
+    }
+
+    void copyFrom(const PointerProperties& other);
+};
+
+/*
  * Input events.
  */
 class InputEvent : public AInputEvent {
@@ -346,6 +361,8 @@
 
     inline void setMetaState(int32_t metaState) { mMetaState = metaState; }
 
+    inline int32_t getButtonState() const { return mButtonState; }
+
     inline float getXOffset() const { return mXOffset; }
 
     inline float getYOffset() const { return mYOffset; }
@@ -356,9 +373,21 @@
 
     inline nsecs_t getDownTime() const { return mDownTime; }
 
-    inline size_t getPointerCount() const { return mPointerIds.size(); }
+    inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
 
-    inline int32_t getPointerId(size_t pointerIndex) const { return mPointerIds[pointerIndex]; }
+    inline size_t getPointerCount() const { return mPointerProperties.size(); }
+
+    inline const PointerProperties* getPointerProperties(size_t pointerIndex) const {
+        return &mPointerProperties[pointerIndex];
+    }
+
+    inline int32_t getPointerId(size_t pointerIndex) const {
+        return mPointerProperties[pointerIndex].id;
+    }
+
+    inline int32_t getToolType(size_t pointerIndex) const {
+        return mPointerProperties[pointerIndex].toolType;
+    }
 
     inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
 
@@ -490,6 +519,7 @@
             int32_t flags,
             int32_t edgeFlags,
             int32_t metaState,
+            int32_t buttonState,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -497,7 +527,7 @@
             nsecs_t downTime,
             nsecs_t eventTime,
             size_t pointerCount,
-            const int32_t* pointerIds,
+            const PointerProperties* pointerProperties,
             const PointerCoords* pointerCoords);
 
     void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -523,7 +553,9 @@
     }
 
     // Low-level accessors.
-    inline const int32_t* getPointerIds() const { return mPointerIds.array(); }
+    inline const PointerProperties* getPointerProperties() const {
+        return mPointerProperties.array();
+    }
     inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); }
     inline const PointerCoords* getSamplePointerCoords() const {
             return mSamplePointerCoords.array();
@@ -534,12 +566,13 @@
     int32_t mFlags;
     int32_t mEdgeFlags;
     int32_t mMetaState;
+    int32_t mButtonState;
     float mXOffset;
     float mYOffset;
     float mXPrecision;
     float mYPrecision;
     nsecs_t mDownTime;
-    Vector<int32_t> mPointerIds;
+    Vector<PointerProperties> mPointerProperties;
     Vector<nsecs_t> mSampleEventTimes;
     Vector<PointerCoords> mSamplePointerCoords;
 };
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 119db81..95e4447 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -136,6 +136,7 @@
             int32_t action;
             int32_t flags;
             int32_t metaState;
+            int32_t buttonState;
             int32_t edgeFlags;
             nsecs_t downTime;
             float xOffset;
@@ -143,7 +144,7 @@
             float xPrecision;
             float yPrecision;
             size_t pointerCount;
-            int32_t pointerIds[MAX_POINTERS];
+            PointerProperties pointerProperties[MAX_POINTERS];
             size_t sampleCount;
             SampleData sampleData[0]; // variable length
         } motion;
@@ -221,6 +222,7 @@
             int32_t flags,
             int32_t edgeFlags,
             int32_t metaState,
+            int32_t buttonState,
             float xOffset,
             float yOffset,
             float xPrecision,
@@ -228,7 +230,7 @@
             nsecs_t downTime,
             nsecs_t eventTime,
             size_t pointerCount,
-            const int32_t* pointerIds,
+            const PointerProperties* pointerProperties,
             const PointerCoords* pointerCoords);
 
     /* Appends a motion sample to a motion event unless already consumed.
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index d811dd7..1ba38a7 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -373,6 +373,19 @@
 }
 
 
+// --- PointerProperties ---
+
+bool PointerProperties::operator==(const PointerProperties& other) const {
+    return id == other.id
+            && toolType == other.toolType;
+}
+
+void PointerProperties::copyFrom(const PointerProperties& other) {
+    id = other.id;
+    toolType = other.toolType;
+}
+
+
 // --- MotionEvent ---
 
 void MotionEvent::initialize(
@@ -382,6 +395,7 @@
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
+        int32_t buttonState,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -389,20 +403,21 @@
         nsecs_t downTime,
         nsecs_t eventTime,
         size_t pointerCount,
-        const int32_t* pointerIds,
+        const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
     InputEvent::initialize(deviceId, source);
     mAction = action;
     mFlags = flags;
     mEdgeFlags = edgeFlags;
     mMetaState = metaState;
+    mButtonState = buttonState;
     mXOffset = xOffset;
     mYOffset = yOffset;
     mXPrecision = xPrecision;
     mYPrecision = yPrecision;
     mDownTime = downTime;
-    mPointerIds.clear();
-    mPointerIds.appendArray(pointerIds, pointerCount);
+    mPointerProperties.clear();
+    mPointerProperties.appendArray(pointerProperties, pointerCount);
     mSampleEventTimes.clear();
     mSamplePointerCoords.clear();
     addSample(eventTime, pointerCoords);
@@ -414,12 +429,13 @@
     mFlags = other->mFlags;
     mEdgeFlags = other->mEdgeFlags;
     mMetaState = other->mMetaState;
+    mButtonState = other->mButtonState;
     mXOffset = other->mXOffset;
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
     mYPrecision = other->mYPrecision;
     mDownTime = other->mDownTime;
-    mPointerIds = other->mPointerIds;
+    mPointerProperties = other->mPointerProperties;
 
     if (keepHistory) {
         mSampleEventTimes = other->mSampleEventTimes;
@@ -484,9 +500,9 @@
 }
 
 ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
-    size_t pointerCount = mPointerIds.size();
+    size_t pointerCount = mPointerProperties.size();
     for (size_t i = 0; i < pointerCount; i++) {
-        if (mPointerIds.itemAt(i) == pointerId) {
+        if (mPointerProperties.itemAt(i).id == pointerId) {
             return i;
         }
     }
@@ -583,21 +599,25 @@
     mFlags = parcel->readInt32();
     mEdgeFlags = parcel->readInt32();
     mMetaState = parcel->readInt32();
+    mButtonState = parcel->readInt32();
     mXOffset = parcel->readFloat();
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
     mYPrecision = parcel->readFloat();
     mDownTime = parcel->readInt64();
 
-    mPointerIds.clear();
-    mPointerIds.setCapacity(pointerCount);
+    mPointerProperties.clear();
+    mPointerProperties.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());
+        mPointerProperties.push();
+        PointerProperties& properties = mPointerProperties.editTop();
+        properties.id = parcel->readInt32();
+        properties.toolType = parcel->readInt32();
     }
 
     while (sampleCount-- > 0) {
@@ -614,7 +634,7 @@
 }
 
 status_t MotionEvent::writeToParcel(Parcel* parcel) const {
-    size_t pointerCount = mPointerIds.size();
+    size_t pointerCount = mPointerProperties.size();
     size_t sampleCount = mSampleEventTimes.size();
 
     parcel->writeInt32(pointerCount);
@@ -626,6 +646,7 @@
     parcel->writeInt32(mFlags);
     parcel->writeInt32(mEdgeFlags);
     parcel->writeInt32(mMetaState);
+    parcel->writeInt32(mButtonState);
     parcel->writeFloat(mXOffset);
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
@@ -633,7 +654,9 @@
     parcel->writeInt64(mDownTime);
 
     for (size_t i = 0; i < pointerCount; i++) {
-        parcel->writeInt32(mPointerIds.itemAt(i));
+        const PointerProperties& properties = mPointerProperties.itemAt(i);
+        parcel->writeInt32(properties.id);
+        parcel->writeInt32(properties.toolType);
     }
 
     const PointerCoords* pc = mSamplePointerCoords.array();
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 93d0d1f..ffdfe66 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -366,6 +366,7 @@
         int32_t flags,
         int32_t edgeFlags,
         int32_t metaState,
+        int32_t buttonState,
         float xOffset,
         float yOffset,
         float xPrecision,
@@ -373,16 +374,17 @@
         nsecs_t downTime,
         nsecs_t eventTime,
         size_t pointerCount,
-        const int32_t* pointerIds,
+        const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
     LOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
-            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, xOffset=%f, yOffset=%f, "
+            "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
+            "xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
             "pointerCount=%d",
             mChannel->getName().string(),
-            deviceId, source, action, flags, edgeFlags, metaState, xOffset, yOffset,
-            xPrecision, yPrecision, downTime, eventTime, pointerCount);
+            deviceId, source, action, flags, edgeFlags, metaState, buttonState,
+            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
 
     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
@@ -400,6 +402,7 @@
     mSharedMessage->motion.flags = flags;
     mSharedMessage->motion.edgeFlags = edgeFlags;
     mSharedMessage->motion.metaState = metaState;
+    mSharedMessage->motion.buttonState = buttonState;
     mSharedMessage->motion.xOffset = xOffset;
     mSharedMessage->motion.yOffset = yOffset;
     mSharedMessage->motion.xPrecision = xPrecision;
@@ -411,7 +414,7 @@
     mSharedMessage->motion.sampleData[0].eventTime = eventTime;
 
     for (size_t i = 0; i < pointerCount; i++) {
-        mSharedMessage->motion.pointerIds[i] = pointerIds[i];
+        mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
         mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
     }
 
@@ -694,6 +697,7 @@
             mSharedMessage->motion.flags,
             mSharedMessage->motion.edgeFlags,
             mSharedMessage->motion.metaState,
+            mSharedMessage->motion.buttonState,
             mSharedMessage->motion.xOffset,
             mSharedMessage->motion.yOffset,
             mSharedMessage->motion.xPrecision,
@@ -701,7 +705,7 @@
             mSharedMessage->motion.downTime,
             mSharedMessage->motion.sampleData[0].eventTime,
             mSharedMessage->motion.pointerCount,
-            mSharedMessage->motion.pointerIds,
+            mSharedMessage->motion.pointerProperties,
             mSharedMessage->motion.sampleData[0].coords);
 
     size_t sampleCount = mSharedMessage->motion.sampleCount;
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
index b77489e..e48d5b7 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -232,7 +232,14 @@
 const float MotionEventTest::Y_OFFSET = 1.1f;
 
 void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
-    int32_t pointerIds[] = { 1, 2 };
+    PointerProperties pointerProperties[2];
+    pointerProperties[0].clear();
+    pointerProperties[0].id = 1;
+    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+    pointerProperties[1].clear();
+    pointerProperties[1].id = 2;
+    pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS;
+
     PointerCoords pointerCoords[2];
     pointerCoords[0].clear();
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10);
@@ -256,10 +263,10 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
     event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
-            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON,
+            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
             X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
             ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
-            2, pointerIds, pointerCoords);
+            2, pointerProperties, pointerCoords);
 
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -311,6 +318,7 @@
     ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
     ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
     ASSERT_EQ(AMETA_ALT_ON, event->getMetaState());
+    ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, event->getButtonState());
     ASSERT_EQ(X_OFFSET, event->getXOffset());
     ASSERT_EQ(Y_OFFSET, event->getYOffset());
     ASSERT_EQ(2.0f, event->getXPrecision());
@@ -319,7 +327,9 @@
 
     ASSERT_EQ(2U, event->getPointerCount());
     ASSERT_EQ(1, event->getPointerId(0));
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0));
     ASSERT_EQ(2, event->getPointerId(1));
+    ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1));
 
     ASSERT_EQ(2U, event->getHistorySize());
 
@@ -534,19 +544,20 @@
     const float ROTATION = ARC * 2;
 
     const size_t pointerCount = 11;
-    int pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
     for (size_t i = 0; i < pointerCount; i++) {
         float angle = float(i * ARC * PI_180);
-        pointerIds[i] = i;
+        pointerProperties[i].clear();
+        pointerProperties[i].id = i;
         pointerCoords[i].clear();
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, sinf(angle) * RADIUS + 3);
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, -cosf(angle) * RADIUS + 2);
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0,
-            0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0,
+            0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 6e18a4f..fcc4cad 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -156,13 +156,19 @@
     const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
     const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
     const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+    const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
     const float xOffset = -10;
     const float yOffset = -20;
     const float xPrecision = 0.25;
     const float yPrecision = 0.5;
     const nsecs_t downTime = 3;
     const size_t pointerCount = 3;
-    const int32_t pointerIds[pointerCount] = { 2, 0, 1 };
+    PointerProperties pointerProperties[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerProperties[i].id = (i + 2) % pointerCount;
+        pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+    }
 
     Vector<nsecs_t> sampleEventTimes;
     Vector<PointerCoords> samplePointerCoords;
@@ -186,8 +192,9 @@
     }
 
     status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
-            metaState, xOffset, yOffset, xPrecision, yPrecision,
-            downTime, sampleEventTimes[0], pointerCount, pointerIds, samplePointerCoords.array());
+            metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
+            downTime, sampleEventTimes[0], pointerCount,
+            pointerProperties, samplePointerCoords.array());
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
@@ -234,6 +241,7 @@
     EXPECT_EQ(flags, motionEvent->getFlags());
     EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
     EXPECT_EQ(metaState, motionEvent->getMetaState());
+    EXPECT_EQ(buttonState, motionEvent->getButtonState());
     EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
     EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
     EXPECT_EQ(downTime, motionEvent->getDownTime());
@@ -243,7 +251,8 @@
 
     for (size_t i = 0; i < pointerCount; i++) {
         SCOPED_TRACE(i);
-        EXPECT_EQ(pointerIds[i], motionEvent->getPointerId(i));
+        EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
+        EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
     }
 
     for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
@@ -352,17 +361,20 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = 1;
-    int32_t pointerIds[pointerCount] = { 0 };
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
-    pointerCoords[0].clear();
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(INVALID_OPERATION, status)
             << "publisher publishMotionEvent should return INVALID_OPERATION because ";
                     "the publisher was not reset";
@@ -373,11 +385,11 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = 0;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -387,11 +399,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS + 1;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerIds, pointerCoords);
+    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -432,11 +448,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status);
 
     status = mPublisher->appendMotionSample(0, pointerCoords);
@@ -449,11 +469,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status);
 
     status = mPublisher->sendDispatchSignal();
@@ -476,11 +500,15 @@
     ASSERT_NO_FATAL_FAILURE(Initialize());
 
     const size_t pointerCount = MAX_POINTERS;
-    int32_t pointerIds[pointerCount];
+    PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
+    for (size_t i = 0; i < pointerCount; i++) {
+        pointerProperties[i].clear();
+        pointerCoords[i].clear();
+    }
 
     status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
-            0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerIds, pointerCoords);
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status);
 
     for (int count = 1;; count++) {
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index ad4a308..cfb013e 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -454,6 +454,20 @@
     return dest;
 }
 
+static void calc_tar_checksum(char* buf) {
+    // [ 148 :   8 ] checksum -- to be calculated with this field as space chars
+    memset(buf + 148, ' ', 8);
+
+    uint16_t sum = 0;
+    for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
+        sum += *p;
+    }
+
+    // Now write the real checksum value:
+    // [ 148 :   8 ]  checksum: 6 octal digits [leading zeroes], NUL, SPC
+    sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
+}
+
 int write_tarfile(const String8& packageName, const String8& domain,
         const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
 {
@@ -462,12 +476,18 @@
     if (*relstart == '/') relstart++;     // won't be true when path == rootpath
     String8 relpath(relstart);
 
+    // If relpath is empty, it means this is the top of one of the standard named
+    // domain directories, so we should just skip it
+    if (relpath.length() == 0) {
+        return 0;
+    }
+
     // Too long a name for the ustar format?
     //    "apps/" + packagename + '/' + domainpath < 155 chars
     //    relpath < 100 chars
+    bool needExtended = false;
     if ((5 + packageName.length() + 1 + domain.length() >= 155) || (relpath.length() >= 100)) {
-        LOGE("Filename [%s] too long, skipping", relpath.string());
-        return -1;
+        needExtended = true;
     }
 
     int err = 0;
@@ -478,6 +498,9 @@
         return err;
     }
 
+    String8 fullname;   // for pax later on
+    String8 prefix;
+
     const int isdir = S_ISDIR(s.st_mode);
 
     // !!! TODO: use mmap when possible to avoid churning the buffer cache
@@ -491,48 +514,29 @@
 
     // read/write up to this much at a time.
     const size_t BUFSIZE = 32 * 1024;
-
     char* buf = new char[BUFSIZE];
+    char* paxHeader = buf + 512;    // use a different chunk of it as separate scratch
+    char* paxData = buf + 1024;
+
     if (buf == NULL) {
         LOGE("Out of mem allocating transfer buffer");
         err = ENOMEM;
-        goto done;
+        goto cleanup;
     }
 
     // Good to go -- first construct the standard tar header at the start of the buffer
     memset(buf, 0, 512);    // tar header is 512 bytes
+    memset(paxHeader, 0, 512);
 
     // Magic fields for the ustar file format
     strcat(buf + 257, "ustar");
     strcat(buf + 263, "00");
 
-    {
-        // Prefix and main relative path.  Path lengths have been preflighted.
-
-        // [ 345 : 155 ] filename path prefix [ustar]
-        //
-        // packagename and domain can each be empty.
-        char* cp = buf + 345;
-        if (packageName.length() > 0) {
-            // it's an app; so prefix with "apps/packagename/"
-            cp = strcpy_ptr(cp, "apps/");
-            cp = strcpy_ptr(cp, packageName.string());
-        }
-
-        if (domain.length() > 0) {
-            // only need a / if there was a package name
-            if (packageName.length() > 0) *cp++ = '/';
-            cp = strcpy_ptr(cp, domain.string());
-        }
-
-        // [   0 : 100 ]; file name/path
-        strncpy(buf, relpath.string(), 100);
-
-        LOGI("   Name: %s/%s", buf + 345, buf);
-    }
+    // [ 265 : 32 ] user name, ignored on restore
+    // [ 297 : 32 ] group name, ignored on restore
 
     // [ 100 :   8 ] file mode
-    snprintf(buf + 100, 8, "0%o", s.st_mode);
+    snprintf(buf + 100, 8, "%06o ", s.st_mode & ~S_IFMT);
 
     // [ 108 :   8 ] uid -- ignored in Android format; uids are remapped at restore time
     // [ 116 :   8 ] gid -- ignored in Android format
@@ -540,14 +544,15 @@
     snprintf(buf + 116, 8, "0%lo", s.st_gid);
 
     // [ 124 :  12 ] file size in bytes
-    snprintf(buf + 124, 12, "0%llo", s.st_size);
+    if (s.st_size > 077777777777LL) {
+        // very large files need a pax extended size header
+        needExtended = true;
+    }
+    snprintf(buf + 124, 12, "%011llo", (isdir) ? 0LL : s.st_size);
 
     // [ 136 :  12 ] last mod time as a UTC time_t
     snprintf(buf + 136, 12, "%0lo", s.st_mtime);
 
-    // [ 148 :   8 ] checksum -- to be calculated with this field as space chars
-    memset(buf + 148, ' ', 8);
-
     // [ 156 :   1 ] link/file type
     uint8_t type;
     if (isdir) {
@@ -562,19 +567,89 @@
 
     // [ 157 : 100 ] name of linked file [not implemented]
 
-    // Now go back and calculate the header checksum
     {
-        uint16_t sum = 0;
-        for (uint8_t* p = (uint8_t*) buf; p < ((uint8_t*)buf) + 512; p++) {
-            sum += *p;
+        // Prefix and main relative path.  Path lengths have been preflighted.
+        if (packageName.length() > 0) {
+            prefix = "apps/";
+            prefix += packageName;
+        }
+        if (domain.length() > 0) {
+            prefix.appendPath(domain);
         }
 
-        // Now write the real checksum value:
-        // [ 148 :   8 ]  checksum: 6 octal digits [leading zeroes], NUL, SPC
-        sprintf(buf + 148, "%06o", sum); // the trailing space is already in place
+        // pax extended means we don't put in a prefix field, and put a different
+        // string in the basic name field.  We can also construct the full path name
+        // out of the substrings we've now built.
+        fullname = prefix;
+        fullname.appendPath(relpath);
+
+        // ustar:
+        //    [   0 : 100 ]; file name/path
+        //    [ 345 : 155 ] filename path prefix
+        // We only use the prefix area if fullname won't fit in the path
+        if (fullname.length() > 100) {
+            strncpy(buf, relpath.string(), 100);
+            strncpy(buf + 345, prefix.string(), 155);
+        } else {
+            strncpy(buf, fullname.string(), 100);
+        }
     }
 
-    // Write the 512-byte tar file header block to the output
+    // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
+
+    LOGI("   Name: %s", fullname.string());
+
+    // If we're using a pax extended header, build & write that here; lengths are
+    // already preflighted
+    if (needExtended) {
+        // construct the pax extended header data block
+        memset(paxData, 0, BUFSIZE - (paxData - buf));
+        char* p = paxData;
+        int len;
+
+        // size header -- calc len in digits by actually rendering the number
+        // to a string - brute force but simple
+        len = sprintf(p, "%lld", s.st_size) + 8;  // 8 for "1 size=" and final LF
+        if (len >= 10) len++;
+
+        memset(p, 0, 512);
+        p += sprintf(p, "%d size=%lld\n", len, s.st_size);
+
+        // fullname was generated above with the ustar paths
+        len = fullname.length() + 8;        // 8 for "1 path=" and final LF
+        if (len >= 10) len++;
+        if (len >= 100) len++;
+        p += sprintf(p, "%d path=%s\n", len, fullname.string());
+
+        // Now we know how big the pax data is
+        int paxLen = p - paxData;
+
+        // Now build the pax *header* templated on the ustar header
+        memcpy(paxHeader, buf, 512);
+
+        String8 leaf = fullname.getPathLeaf();
+        memset(paxHeader, 0, 100);                  // rewrite the name area
+        snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
+        memset(paxHeader + 345, 0, 155);            // rewrite the prefix area
+        strncpy(paxHeader + 345, prefix.string(), 155);
+
+        paxHeader[156] = 'x';                       // mark it as a pax extended header
+
+        // [ 124 :  12 ] size of pax extended header data
+        memset(paxHeader + 124, 0, 12);
+        snprintf(paxHeader + 124, 12, "%011o", p - paxData);
+
+        // Checksum and write the pax block header
+        calc_tar_checksum(paxHeader);
+        writer->WriteEntityData(paxHeader, 512);
+
+        // Now write the pax data itself
+        int paxblocks = (paxLen + 511) / 512;
+        writer->WriteEntityData(paxData, 512 * paxblocks);
+    }
+
+    // Checksum and write the 512-byte ustar file header block to the output
+    calc_tar_checksum(buf);
     writer->WriteEntityData(buf, 512);
 
     // Now write the file data itself, for real files.  We honor tar's convention that