Query input device for initial slot index.

This fixes a problem where touches can get stuck because the
driver and the framework have different ideas of what the
initial slot index is.  The framework assumed it was slot 0
but it could in principle be any slot, such as slot 1.  When
that happened, the framework would start tracking the first
touch as slot 0, but it might never receive an "up" for that slot.

Change-Id: Idaffc4534b275d66b9d4360987b28dc2d0f63218
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 95b8a57..ca2540b 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -212,8 +212,8 @@
     struct input_absinfo info;
 
     if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
-        LOGW("Error reading absolute controller %d for device %s fd %d\n",
-             axis, device->identifier.name.string(), device->fd);
+        LOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
+             axis, device->identifier.name.string(), device->fd, errno);
         return -errno;
     }
 
@@ -335,6 +335,33 @@
     return AKEY_STATE_UNKNOWN;
 }
 
+status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const {
+    if (axis >= 0 && axis <= ABS_MAX) {
+        AutoMutex _l(mLock);
+
+        Device* device = getDeviceLocked(deviceId);
+        if (device != NULL) {
+            return getAbsoluteAxisValueLocked(device, axis, outValue);
+        }
+    }
+    *outValue = 0;
+    return -1;
+}
+
+status_t EventHub::getAbsoluteAxisValueLocked(Device* device, int32_t axis,
+        int32_t* outValue) const {
+    struct input_absinfo info;
+
+     if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
+         LOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
+              axis, device->identifier.name.string(), device->fd, errno);
+         return -errno;
+     }
+
+     *outValue = info.value;
+     return OK;
+}
+
 bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
         const int32_t* keyCodes, uint8_t* outFlags) const {
     AutoMutex _l(mLock);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 0a34e45..695dfdf 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -186,6 +186,8 @@
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
     virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
     virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
+    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+            int32_t* outValue) const = 0;
 
     /*
      * Examine key input devices for specific framework keycode support
@@ -237,6 +239,7 @@
     virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
     virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
     virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const;
+    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const;
 
     virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags) const;
@@ -305,6 +308,7 @@
     int32_t getScanCodeStateLocked(Device* device, int32_t scanCode) const;
     int32_t getKeyCodeStateLocked(Device* device, int32_t keyCode) const;
     int32_t getSwitchStateLocked(Device* device, int32_t sw) const;
+    int32_t getAbsoluteAxisValueLocked(Device* device, int32_t axis, int32_t* outValue) const;
     bool markSupportedKeyCodesLocked(Device* device, size_t numCodes,
             const int32_t* keyCodes, uint8_t* outFlags) const;
 
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 85ce38a..10b9083 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -1239,8 +1239,9 @@
     const InputWindow* newHoverWindow = NULL;
 
     bool isSplit = mTouchState.split;
-    bool switchedDevice = mTouchState.deviceId != entry->deviceId
-            || mTouchState.source != entry->source;
+    bool switchedDevice = mTouchState.deviceId >= 0
+            && (mTouchState.deviceId != entry->deviceId
+                    || mTouchState.source != entry->source);
     bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
             || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
             || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 82c3af3..79218a5 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -5394,7 +5394,6 @@
 
 MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
         TouchInputMapper(device), mSlotCount(0), mUsingSlotsProtocol(false) {
-    clearState();
 }
 
 MultiTouchInputMapper::~MultiTouchInputMapper() {
@@ -5404,6 +5403,24 @@
     mAccumulator.clearSlots(mSlotCount);
     mAccumulator.clearButtons();
     mButtonState = 0;
+
+    if (mUsingSlotsProtocol) {
+        // Query the driver for the current slot index and use it as the initial slot
+        // before we start reading events from the device.  It is possible that the
+        // current slot index will not be the same as it was when the first event was
+        // written into the evdev buffer, which means the input mapper could start
+        // out of sync with the initial state of the events in the evdev buffer.
+        // In the extremely unlikely case that this happens, the data from
+        // two slots will be confused until the next ABS_MT_SLOT event is received.
+        // This can cause the touch point to "jump", but at least there will be
+        // no stuck touches.
+        status_t status = getEventHub()->getAbsoluteAxisValue(getDeviceId(), ABS_MT_SLOT,
+                &mAccumulator.currentSlot);
+        if (status) {
+            LOGW("Could not retrieve current multitouch slot index.  status=%d", status);
+            mAccumulator.currentSlot = -1;
+        }
+    }
 }
 
 void MultiTouchInputMapper::reset() {
@@ -5682,6 +5699,8 @@
     }
 
     mAccumulator.allocateSlots(mSlotCount);
+
+    clearState();
 }
 
 
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index e349248..d3c5ece 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -429,6 +429,7 @@
         KeyedVector<int32_t, int32_t> keyCodeStates;
         KeyedVector<int32_t, int32_t> scanCodeStates;
         KeyedVector<int32_t, int32_t> switchStates;
+        KeyedVector<int32_t, int32_t> absoluteAxisValue;
         KeyedVector<int32_t, KeyInfo> keys;
         KeyedVector<int32_t, bool> leds;
         Vector<VirtualKeyDefinition> virtualKeys;
@@ -514,6 +515,11 @@
         device->switchStates.replaceValueFor(switchCode, state);
     }
 
+    void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) {
+        Device* device = getDevice(deviceId);
+        device->absoluteAxisValue.replaceValueFor(axis, value);
+    }
+
     void addKey(int32_t deviceId, int32_t scanCode, int32_t keyCode, uint32_t flags) {
         Device* device = getDevice(deviceId);
         KeyInfo info;
@@ -677,6 +683,20 @@
         return AKEY_STATE_UNKNOWN;
     }
 
+    virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+            int32_t* outValue) const {
+        Device* device = getDevice(deviceId);
+        if (device) {
+            ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
+            if (index >= 0) {
+                *outValue = device->absoluteAxisValue.valueAt(index);
+                return OK;
+            }
+        }
+        *outValue = 0;
+        return -1;
+    }
+
     virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
             uint8_t* outFlags) const {
         bool result = false;