Merge "fix build" into gingerbread-plus-aosp
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index 05cd96d..3d42856 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -267,6 +267,12 @@
 #ifdef EV_SW
     int32_t         mSwitches[SW_MAX + 1];
 #endif
+
+    static const int INPUT_BUFFER_SIZE = 64;
+    struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
+    int32_t mInputBufferIndex;
+    int32_t mInputBufferCount;
+    int32_t mInputDeviceIndex;
 };
 
 }; // namespace android
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index d3495fe..2505cb0 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -554,6 +554,8 @@
     // All registered connections mapped by receive pipe file descriptor.
     KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
 
+    ssize_t getConnectionIndex(const sp<InputChannel>& inputChannel);
+
     // Active connections are connections that have a non-empty outbound queue.
     // We don't use a ref-counted pointer here because we explicitly abort connections
     // during unregistration which causes the connection's outbound queue to be cleared
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 71c6c51..56d2765 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -480,10 +480,6 @@
         inline void clear() {
             fields = 0;
         }
-
-        inline bool isDirty() {
-            return fields != 0;
-        }
     } mAccumulator;
 
     float mXScale;
@@ -702,7 +698,7 @@
         } historyData[AVERAGING_HISTORY_SIZE];
     } mAveragingTouchFilter;
 
-    struct JumpTouchFilterState {
+    struct JumpyTouchFilterState {
         uint32_t jumpyPointsDropped;
     } mJumpyTouchFilter;
 
@@ -765,10 +761,6 @@
         inline void clear() {
             fields = 0;
         }
-
-        inline bool isDirty() {
-            return fields != 0;
-        }
     } mAccumulator;
 
     bool mDown;
@@ -804,7 +796,8 @@
             FIELD_ABS_MT_WIDTH_MAJOR = 16,
             FIELD_ABS_MT_WIDTH_MINOR = 32,
             FIELD_ABS_MT_ORIENTATION = 64,
-            FIELD_ABS_MT_TRACKING_ID = 128
+            FIELD_ABS_MT_TRACKING_ID = 128,
+            FIELD_ABS_MT_PRESSURE = 256,
         };
 
         uint32_t pointerCount;
@@ -819,6 +812,7 @@
             int32_t absMTWidthMinor;
             int32_t absMTOrientation;
             int32_t absMTTrackingId;
+            int32_t absMTPressure;
 
             inline void clear() {
                 fields = 0;
@@ -829,10 +823,6 @@
             pointerCount = 0;
             pointers[0].clear();
         }
-
-        inline bool isDirty() {
-            return pointerCount != 0;
-        }
     } mAccumulator;
 
     void initialize();
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index b1284fe..a3c34d0 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -99,6 +99,7 @@
     , mDevicesById(0), mNumDevicesById(0)
     , mOpeningDevices(0), mClosingDevices(0)
     , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
+    , mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
 {
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
 #ifdef EV_SW
@@ -341,13 +342,6 @@
     outEvent->value = 0;
     outEvent->when = 0;
 
-    status_t err;
-
-    int i;
-    int res;
-    int pollres;
-    struct input_event iev;
-
     // Note that we only allow one caller to getEvent(), so don't need
     // to do locking here...  only when adding/removing devices.
 
@@ -356,9 +350,8 @@
         mOpened = true;
     }
 
-    while(1) {
-
-        // First, report any devices that had last been added/removed.
+    for (;;) {
+        // Report any devices that had last been added/removed.
         if (mClosingDevices != NULL) {
             device_t* device = mClosingDevices;
             LOGV("Reporting device closed: id=0x%x, name=%s\n",
@@ -388,77 +381,96 @@
             return true;
         }
 
-        release_wake_lock(WAKE_LOCK_ID);
+        // Grab the next input event.
+        for (;;) {
+            // Consume buffered input events, if any.
+            if (mInputBufferIndex < mInputBufferCount) {
+                const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
+                const device_t* device = mDevices[mInputDeviceIndex];
 
-        pollres = poll(mFDs, mFDCount, -1);
-
-        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
-
-        if (pollres <= 0) {
-            if (errno != EINTR) {
-                LOGW("select failed (errno=%d)\n", errno);
-                usleep(100000);
-            }
-            continue;
-        }
-
-        //printf("poll %d, returned %d\n", mFDCount, pollres);
-
-        // mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
-        for(i = 1; i < mFDCount; i++) {
-            if(mFDs[i].revents) {
-                LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
-                if(mFDs[i].revents & POLLIN) {
-                    res = read(mFDs[i].fd, &iev, sizeof(iev));
-                    if (res == sizeof(iev)) {
-                        device_t* device = mDevices[i];
-                        LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
-                             device->path.string(),
-                             (int) iev.time.tv_sec, (int) iev.time.tv_usec,
-                             iev.type, iev.code, iev.value);
-                        if (device->id == mFirstKeyboardId) {
-                            outEvent->deviceId = 0;
-                        } else {
-                            outEvent->deviceId = device->id;
-                        }
-                        outEvent->type = iev.type;
-                        outEvent->scanCode = iev.code;
-                        if (iev.type == EV_KEY) {
-                            err = device->layoutMap->map(iev.code,
-                                    & outEvent->keyCode, & outEvent->flags);
-                            LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
-                                iev.code, outEvent->keyCode, outEvent->flags, err);
-                            if (err != 0) {
-                                outEvent->keyCode = AKEYCODE_UNKNOWN;
-                                outEvent->flags = 0;
-                            }
-                        } else {
-                            outEvent->keyCode = iev.code;
-                        }
-                        outEvent->value = iev.value;
-
-                        // Use an event timestamp in the same timebase as
-                        // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
-                        // as expected by the rest of the system.
-                        outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
-                        return true;
-                    } else {
-                        if (res<0) {
-                            LOGW("could not get event (errno=%d)", errno);
-                        } else {
-                            LOGE("could not get event (wrong size: %d)", res);
-                        }
-                        continue;
+                LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
+                     (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
+                if (device->id == mFirstKeyboardId) {
+                    outEvent->deviceId = 0;
+                } else {
+                    outEvent->deviceId = device->id;
+                }
+                outEvent->type = iev.type;
+                outEvent->scanCode = iev.code;
+                if (iev.type == EV_KEY) {
+                    status_t err = device->layoutMap->map(iev.code,
+                            & outEvent->keyCode, & outEvent->flags);
+                    LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
+                        iev.code, outEvent->keyCode, outEvent->flags, err);
+                    if (err != 0) {
+                        outEvent->keyCode = AKEYCODE_UNKNOWN;
+                        outEvent->flags = 0;
                     }
+                } else {
+                    outEvent->keyCode = iev.code;
+                }
+                outEvent->value = iev.value;
+
+                // Use an event timestamp in the same timebase as
+                // java.lang.System.nanoTime() and android.os.SystemClock.uptimeMillis()
+                // as expected by the rest of the system.
+                outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
+                return true;
+            }
+
+            // Finish reading all events from devices identified in previous poll().
+            // This code assumes that mInputDeviceIndex is initially 0 and that the
+            // revents member of pollfd is initialized to 0 when the device is first added.
+            // Since mFDs[0] is used for inotify, we process regular events starting at index 1.
+            mInputDeviceIndex += 1;
+            if (mInputDeviceIndex >= mFDCount) {
+                mInputDeviceIndex = 0;
+                break;
+            }
+
+            const struct pollfd &pfd = mFDs[mInputDeviceIndex];
+            if (pfd.revents & POLLIN) {
+                int32_t readSize = read(pfd.fd, mInputBufferData,
+                        sizeof(struct input_event) * INPUT_BUFFER_SIZE);
+                if (readSize < 0) {
+                    if (errno != EAGAIN && errno != EINTR) {
+                        LOGW("could not get event (errno=%d)", errno);
+                    }
+                } else if ((readSize % sizeof(struct input_event)) != 0) {
+                    LOGE("could not get event (wrong size: %d)", readSize);
+                } else {
+                    mInputBufferCount = readSize / sizeof(struct input_event);
+                    mInputBufferIndex = 0;
                 }
             }
         }
-        
+
         // read_notify() will modify mFDs and mFDCount, so this must be done after
         // processing all other events.
         if(mFDs[0].revents & POLLIN) {
             read_notify(mFDs[0].fd);
         }
+
+        // Poll for events.  Mind the wake lock dance!
+        // We hold a wake lock at all times except during poll().  This works due to some
+        // subtle choreography.  When a device driver has pending (unread) events, it acquires
+        // a kernel wake lock.  However, once the last pending event has been read, the device
+        // driver will release the kernel wake lock.  To prevent the system from going to sleep
+        // when this happens, the EventHub holds onto its own user wake lock while the client
+        // is processing events.  Thus the system can only sleep if there are no events
+        // pending or currently being processed.
+        release_wake_lock(WAKE_LOCK_ID);
+
+        int pollResult = poll(mFDs, mFDCount, -1);
+
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
+
+        if (pollResult <= 0) {
+            if (errno != EINTR) {
+                LOGW("select failed (errno=%d)\n", errno);
+                usleep(100000);
+            }
+        }
     }
 }
 
@@ -476,6 +488,7 @@
     mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
     mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
     mFDs[0].events = POLLIN;
+    mFDs[0].revents = 0;
     mDevices[0] = NULL;
 #ifdef HAVE_INOTIFY
     mFDs[0].fd = inotify_init();
@@ -582,6 +595,12 @@
         idstr[0] = '\0';
     }
 
+    if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
+        LOGE("Error %d making device file descriptor non-blocking.", errno);
+        close(fd);
+        return -1;
+    }
+
     int devid = 0;
     while (devid < mNumDevicesById) {
         if (mDevicesById[devid].device == NULL) {
@@ -639,6 +658,7 @@
     device->fd = fd;
     mFDs[mFDCount].fd = fd;
     mFDs[mFDCount].events = POLLIN;
+    mFDs[mFDCount].revents = 0;
 
     // Figure out the kinds of events the device reports.
     
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b53f140..13030b5 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -433,8 +433,7 @@
     for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
         const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
 
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(
-                inputTarget.inputChannel->getReceivePipeFd());
+        ssize_t connectionIndex = getConnectionIndex(inputTarget.inputChannel);
         if (connectionIndex >= 0) {
             sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
@@ -1367,12 +1366,10 @@
     LOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().string());
 #endif
 
-    int receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        if (mConnectionsByReceiveFd.indexOfKey(receiveFd) >= 0) {
+        if (getConnectionIndex(inputChannel) >= 0) {
             LOGW("Attempted to register already registered input channel '%s'",
                     inputChannel->getName().string());
             return BAD_VALUE;
@@ -1386,12 +1383,13 @@
             return status;
         }
 
+        int32_t receiveFd = inputChannel->getReceivePipeFd();
         mConnectionsByReceiveFd.add(receiveFd, connection);
 
+        mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
+
         runCommandsLockedInterruptible();
     } // release lock
-
-    mPollLoop->setCallback(receiveFd, POLLIN, handleReceiveCallback, this);
     return OK;
 }
 
@@ -1400,12 +1398,10 @@
     LOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
 #endif
 
-    int32_t receiveFd;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        receiveFd = inputChannel->getReceivePipeFd();
-        ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(receiveFd);
+        ssize_t connectionIndex = getConnectionIndex(inputChannel);
         if (connectionIndex < 0) {
             LOGW("Attempted to unregister already unregistered input channel '%s'",
                     inputChannel->getName().string());
@@ -1417,20 +1413,32 @@
 
         connection->status = Connection::STATUS_ZOMBIE;
 
+        mPollLoop->removeCallback(inputChannel->getReceivePipeFd());
+
         nsecs_t currentTime = now();
         abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
 
         runCommandsLockedInterruptible();
     } // release lock
 
-    mPollLoop->removeCallback(receiveFd);
-
     // Wake the poll loop because removing the connection may have changed the current
     // synchronization state.
     mPollLoop->wake();
     return OK;
 }
 
+ssize_t InputDispatcher::getConnectionIndex(const sp<InputChannel>& inputChannel) {
+    ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+    if (connectionIndex >= 0) {
+        sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+        if (connection->inputChannel.get() == inputChannel.get()) {
+            return connectionIndex;
+        }
+    }
+
+    return -1;
+}
+
 void InputDispatcher::activateConnectionLocked(Connection* connection) {
     for (size_t i = 0; i < mActiveConnections.size(); i++) {
         if (mActiveConnections.itemAt(i) == connection) {
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 5f5a4ac..6f042ec 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -945,7 +945,6 @@
         mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
         mAccumulator.btnMouse = false;
         sync(when);
-        mAccumulator.clear();
     }
 
     InputMapper::reset();
@@ -958,9 +957,9 @@
         case BTN_MOUSE:
             mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
             mAccumulator.btnMouse = rawEvent->value != 0;
-
+            // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and
+            // we need to ensure that we report the up/down promptly.
             sync(rawEvent->when);
-            mAccumulator.clear();
             break;
         }
         break;
@@ -981,10 +980,7 @@
     case EV_SYN:
         switch (rawEvent->scanCode) {
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -992,13 +988,17 @@
 }
 
 void TrackballInputMapper::sync(nsecs_t when) {
+    uint32_t fields = mAccumulator.fields;
+    if (fields == 0) {
+        return; // no new state changes, so nothing to do
+    }
+
     int motionEventAction;
     PointerCoords pointerCoords;
     nsecs_t downTime;
     { // acquire lock
         AutoMutex _l(mLock);
 
-        uint32_t fields = mAccumulator.fields;
         bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
 
         if (downChanged) {
@@ -1061,6 +1061,8 @@
     } // release lock
 
     applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
+
+    mAccumulator.clear();
 }
 
 void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
@@ -2380,8 +2382,8 @@
     mDown = false;
     mX = 0;
     mY = 0;
-    mPressure = 0;
-    mSize = 0;
+    mPressure = 1; // default to 1 for devices that don't report pressure
+    mSize = 0; // default to 0 for devices that don't report size
 }
 
 void SingleTouchInputMapper::reset() {
@@ -2397,9 +2399,9 @@
         case BTN_TOUCH:
             mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
             mAccumulator.btnTouch = rawEvent->value != 0;
-
-            sync(rawEvent->when);
-            mAccumulator.clear();
+            // Don't sync immediately.  Wait until the next SYN_REPORT since we might
+            // not have received valid position information yet.  This logic assumes that
+            // BTN_TOUCH is always followed by SYN_REPORT as part of a complete packet.
             break;
         }
         break;
@@ -2428,10 +2430,7 @@
     case EV_SYN:
         switch (rawEvent->scanCode) {
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -2439,9 +2438,10 @@
 }
 
 void SingleTouchInputMapper::sync(nsecs_t when) {
-    /* Update device state */
-
     uint32_t fields = mAccumulator.fields;
+    if (fields == 0) {
+        return; // no new state changes, so nothing to do
+    }
 
     if (fields & Accumulator::FIELD_BTN_TOUCH) {
         mDown = mAccumulator.btnTouch;
@@ -2472,8 +2472,8 @@
         mCurrentTouch.pointers[0].y = mY;
         mCurrentTouch.pointers[0].pressure = mPressure;
         mCurrentTouch.pointers[0].size = mSize;
-        mCurrentTouch.pointers[0].touchMajor = mPressure;
-        mCurrentTouch.pointers[0].touchMinor = mPressure;
+        mCurrentTouch.pointers[0].touchMajor = mSize;
+        mCurrentTouch.pointers[0].touchMinor = mSize;
         mCurrentTouch.pointers[0].toolMajor = mSize;
         mCurrentTouch.pointers[0].toolMinor = mSize;
         mCurrentTouch.pointers[0].orientation = 0;
@@ -2482,6 +2482,8 @@
     }
 
     syncTouch(when, true);
+
+    mAccumulator.clear();
 }
 
 void SingleTouchInputMapper::configureAxes() {
@@ -2494,8 +2496,8 @@
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size);
 
-    mAxes.touchMajor = mAxes.pressure;
-    mAxes.touchMinor = mAxes.pressure;
+    mAxes.touchMajor = mAxes.size;
+    mAxes.touchMinor = mAxes.size;
     mAxes.toolMajor = mAxes.size;
     mAxes.toolMinor = mAxes.size;
 }
@@ -2585,10 +2587,7 @@
         }
 
         case SYN_REPORT:
-            if (mAccumulator.isDirty()) {
-                sync(rawEvent->when);
-                mAccumulator.clear();
-            }
+            sync(rawEvent->when);
             break;
         }
         break;
@@ -2598,11 +2597,7 @@
 void MultiTouchInputMapper::sync(nsecs_t when) {
     static const uint32_t REQUIRED_FIELDS =
             Accumulator::FIELD_ABS_MT_POSITION_X
-            | Accumulator::FIELD_ABS_MT_POSITION_Y
-            | Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
-            | Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
-
-    /* Update device state */
+            | Accumulator::FIELD_ABS_MT_POSITION_Y;
 
     uint32_t inCount = mAccumulator.pointerCount;
     uint32_t outCount = 0;
@@ -2611,53 +2606,76 @@
     mCurrentTouch.clear();
 
     for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
-        uint32_t fields = mAccumulator.pointers[inIndex].fields;
+        const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex];
+        uint32_t fields = inPointer.fields;
 
         if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
-#if DEBUG_POINTERS
-            LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
-                    inIndex, fields);
-            continue;
-#endif
-        }
-
-        if (mAccumulator.pointers[inIndex].absMTTouchMajor <= 0) {
-            // Pointer is not down.  Drop it.
+            // Some drivers send empty MT sync packets without X / Y to indicate a pointer up.
+            // Drop this finger.
             continue;
         }
 
-        mCurrentTouch.pointers[outCount].x = mAccumulator.pointers[inIndex].absMTPositionX;
-        mCurrentTouch.pointers[outCount].y = mAccumulator.pointers[inIndex].absMTPositionY;
+        PointerData& outPointer = mCurrentTouch.pointers[outCount];
+        outPointer.x = inPointer.absMTPositionX;
+        outPointer.y = inPointer.absMTPositionY;
 
-        mCurrentTouch.pointers[outCount].touchMajor =
-                mAccumulator.pointers[inIndex].absMTTouchMajor;
-        mCurrentTouch.pointers[outCount].touchMinor =
-                (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
-                ? mAccumulator.pointers[inIndex].absMTTouchMinor
-                        : mAccumulator.pointers[inIndex].absMTTouchMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) {
+            int32_t value = inPointer.absMTTouchMajor;
+            if (value <= 0) {
+                // Some devices send sync packets with X / Y but with a 0 touch major to indicate
+                // a pointer up.  Drop this finger.
+                continue;
+            }
+            outPointer.touchMajor = inPointer.absMTTouchMajor;
+        } else {
+            outPointer.touchMajor = 0;
+        }
 
-        mCurrentTouch.pointers[outCount].toolMajor =
-                mAccumulator.pointers[inIndex].absMTWidthMajor;
-        mCurrentTouch.pointers[outCount].toolMinor =
-                (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
-                ? mAccumulator.pointers[inIndex].absMTWidthMinor
-                        : mAccumulator.pointers[inIndex].absMTWidthMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) {
+            outPointer.touchMinor = inPointer.absMTTouchMinor;
+        } else {
+            outPointer.touchMinor = outPointer.touchMajor;
+        }
 
-        mCurrentTouch.pointers[outCount].orientation =
-                (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
-                ? mAccumulator.pointers[inIndex].absMTOrientation : 0;
+        if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) {
+            outPointer.toolMajor = inPointer.absMTWidthMajor;
+        } else {
+            outPointer.toolMajor = outPointer.touchMajor;
+        }
 
-        // Derive an approximation of pressure and size.
-        // FIXME assignment of pressure may be incorrect, probably better to let
-        // pressure = touch / width.  Later on we pass width to MotionEvent as a size, which
-        // isn't quite right either.  Should be using touch for that.
-        mCurrentTouch.pointers[outCount].pressure = mAccumulator.pointers[inIndex].absMTTouchMajor;
-        mCurrentTouch.pointers[outCount].size = mAccumulator.pointers[inIndex].absMTWidthMajor;
+        if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) {
+            outPointer.toolMinor = inPointer.absMTWidthMinor;
+        } else {
+            outPointer.toolMinor = outPointer.toolMajor;
+        }
+
+        if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) {
+            outPointer.orientation = inPointer.absMTOrientation;
+        } else {
+            outPointer.orientation = 0;
+        }
+
+        if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
+            outPointer.pressure = inPointer.absMTPressure;
+        } else {
+            // Derive an approximation of pressure.
+            // FIXME Traditionally we have just passed a normalized value based on
+            //       ABS_MT_TOUCH_MAJOR as an estimate of pressure but the result is not
+            //       very meaningful, particularly on large displays.  We should probably let
+            //       pressure = touch_major / tool_major but it is unclear whether that will
+            //       break applications.
+            outPointer.pressure = outPointer.touchMajor;
+        }
+
+        // Size is an alias for a normalized tool width.
+        // FIXME Normalized tool width doesn't actually make much sense since it literally
+        //       means the approaching contact major axis is divided by its full range as
+        //       reported by the driver.  On a large display this could produce very small values.
+        outPointer.size = outPointer.toolMajor;
 
         if (havePointerIds) {
-            if (fields & Accumulator::
-                    FIELD_ABS_MT_TRACKING_ID) {
-                uint32_t id = uint32_t(mAccumulator.pointers[inIndex].absMTTrackingId);
+            if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
+                uint32_t id = uint32_t(inPointer.absMTTrackingId);
 
                 if (id > MAX_POINTER_ID) {
 #if DEBUG_POINTERS
@@ -2668,7 +2686,7 @@
                     havePointerIds = false;
                 }
                 else {
-                    mCurrentTouch.pointers[outCount].id = id;
+                    outPointer.id = id;
                     mCurrentTouch.idToIndex[id] = outCount;
                     mCurrentTouch.idBits.markBit(id);
                 }
@@ -2683,6 +2701,8 @@
     mCurrentTouch.pointerCount = outCount;
 
     syncTouch(when, havePointerIds);
+
+    mAccumulator.clear();
 }
 
 void MultiTouchInputMapper::configureAxes() {
@@ -2697,6 +2717,7 @@
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor);
     getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation);
+    getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mAxes.pressure);
 
     if (! mAxes.touchMinor.valid) {
         mAxes.touchMinor = mAxes.touchMajor;
@@ -2706,7 +2727,10 @@
         mAxes.toolMinor = mAxes.toolMajor;
     }
 
-    mAxes.pressure = mAxes.touchMajor;
+    if (! mAxes.pressure.valid) {
+        mAxes.pressure = mAxes.touchMajor;
+    }
+
     mAxes.size = mAxes.toolMajor;
 }