summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-05-24 01:07:44 -0700
committerJeff Brown <jeffbrown@google.com>2011-05-24 14:39:19 -0700
commit80fd47ce75253dcdc2cfa85d7a3f42634b923a47 (patch)
tree1edece586e3143d7f4e27e2f497f6d629365628a
parentebed7d6e35f7f960e6e6add2b8ab7c7a31a511c3 (diff)
downloadframeworks_base-80fd47ce75253dcdc2cfa85d7a3f42634b923a47.zip
frameworks_base-80fd47ce75253dcdc2cfa85d7a3f42634b923a47.tar.gz
frameworks_base-80fd47ce75253dcdc2cfa85d7a3f42634b923a47.tar.bz2
Input device protocol enhancements.
Added support for Linux multitouch protocol B (slots). Added support for using the device's input properties as a hint to determine the intended usage of a touch device. Added support for the ABS_MT_DISTANCE axis. Fixed a bug reporting the presence of the orientation axis. Change-Id: Icf7b5a5a0f1a9cdf6ad2b35be8ea0c1a35815d48
-rw-r--r--core/java/android/view/MotionEvent.java4
-rw-r--r--core/java/com/android/internal/widget/PointerLocationView.java1
-rw-r--r--services/input/EventHub.cpp39
-rw-r--r--services/input/EventHub.h52
-rw-r--r--services/input/InputReader.cpp358
-rw-r--r--services/input/InputReader.h90
-rw-r--r--services/input/tests/InputReader_test.cpp4
7 files changed, 408 insertions, 140 deletions
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 82fd581..3436cd1 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -883,8 +883,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
* <p>
* <ul>
* <li>For a stylus, reports the distance of the stylus from the screen.
- * The value is normalized to a range from 0.0 (direct contact) to 1.0 (furthest measurable
- * distance).
+ * The value is nominally measured in millimeters where 0.0 indicates direct contact
+ * and larger values indicate increasing distance from the surface.
* </ul>
* </p>
*
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index d789584..bf1c637 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -385,6 +385,7 @@ public class PointerLocationView extends View {
.append(" ToolMinor=").append(coords.toolMinor, 3)
.append(" Orientation=").append((float)(coords.orientation * 180 / Math.PI), 1)
.append("deg")
+ .append(" Distance=").append(coords.getAxisValue(MotionEvent.AXIS_DISTANCE), 1)
.append(" VScroll=").append(coords.getAxisValue(MotionEvent.AXIS_VSCROLL), 1)
.append(" HScroll=").append(coords.getAxisValue(MotionEvent.AXIS_HSCROLL), 1)
.append(" ToolType=").append(MotionEvent.toolTypeToString(toolType))
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index ff4b11a..af30887 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -101,7 +101,7 @@ EventHub::Device::Device(int fd, int32_t id, const String8& path,
const InputDeviceIdentifier& identifier) :
next(NULL),
fd(fd), id(id), path(path), identifier(identifier),
- classes(0), keyBitmask(NULL), relBitmask(NULL),
+ classes(0), keyBitmask(NULL), relBitmask(NULL), propBitmask(NULL),
configuration(NULL), virtualKeyMap(NULL) {
}
@@ -109,6 +109,7 @@ EventHub::Device::~Device() {
close();
delete[] keyBitmask;
delete[] relBitmask;
+ delete[] propBitmask;
delete configuration;
delete virtualKeyMap;
}
@@ -205,6 +206,18 @@ bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
return false;
}
+bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
+ if (property >= 0 && property <= INPUT_PROP_MAX) {
+ AutoMutex _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device && device->propBitmask) {
+ return test_bit(property, device->propBitmask);
+ }
+ }
+ return false;
+}
+
int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
if (scanCode >= 0 && scanCode <= KEY_MAX) {
AutoMutex _l(mLock);
@@ -834,24 +847,24 @@ int EventHub::openDevice(const char *devicePath) {
memset(sw_bitmask, 0, sizeof(sw_bitmask));
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask);
- device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
- if (device->keyBitmask != NULL) {
- memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
- } else {
- delete device;
- LOGE("out of memory allocating key bitmask");
- return -1;
- }
+ uint8_t prop_bitmask[sizeof_bit_array(INPUT_PROP_MAX + 1)];
+ memset(prop_bitmask, 0, sizeof(prop_bitmask));
+ ioctl(fd, EVIOCGPROP(sizeof(prop_bitmask)), prop_bitmask);
+ device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
device->relBitmask = new uint8_t[sizeof(rel_bitmask)];
- if (device->relBitmask != NULL) {
- memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask));
- } else {
+ device->propBitmask = new uint8_t[sizeof(prop_bitmask)];
+
+ if (!device->keyBitmask || !device->relBitmask || !device->propBitmask) {
delete device;
- LOGE("out of memory allocating rel bitmask");
+ LOGE("out of memory allocating bitmasks");
return -1;
}
+ memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
+ memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask));
+ memcpy(device->propBitmask, prop_bitmask, sizeof(prop_bitmask));
+
// See if this is a keyboard. Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 4d26a95..ca33619 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -34,25 +34,38 @@
#include <linux/input.h>
-/* These constants are not defined in linux/input.h but they are part of the multitouch
- * input protocol. */
-
-#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
-#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
-#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
-#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
-#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
-#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
-#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
-#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device (finger, pen, ...) */
-#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
-#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
-#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
-
-#define MT_TOOL_FINGER 0 /* Identifies a finger */
-#define MT_TOOL_PEN 1 /* Identifies a pen */
+/* These constants are not defined in linux/input.h in the version of the kernel
+ * headers currently provided with Bionic. */
+
+#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len)
+
+#define INPUT_PROP_POINTER 0x00
+#define INPUT_PROP_DIRECT 0x01
+#define INPUT_PROP_BUTTONPAD 0x02
+#define INPUT_PROP_SEMI_MT 0x03
+#define INPUT_PROP_MAX 0x1f
+#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
+
+#define ABS_MT_SLOT 0x2f
+#define ABS_MT_TOUCH_MAJOR 0x30
+#define ABS_MT_TOUCH_MINOR 0x31
+#define ABS_MT_WIDTH_MAJOR 0x32
+#define ABS_MT_WIDTH_MINOR 0x33
+#define ABS_MT_ORIENTATION 0x34
+#define ABS_MT_POSITION_X 0x35
+#define ABS_MT_POSITION_Y 0x36
+#define ABS_MT_TOOL_TYPE 0x37
+#define ABS_MT_BLOB_ID 0x38
+#define ABS_MT_TRACKING_ID 0x39
+#define ABS_MT_PRESSURE 0x3a
+#define ABS_MT_DISTANCE 0x3b
+
+#define MT_TOOL_FINGER 0
+#define MT_TOOL_PEN 1
#define SYN_MT_REPORT 2
+#define SYN_DROPPED 3
+
/* Convenience constants. */
@@ -172,6 +185,8 @@ public:
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0;
+ virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
+
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const = 0;
@@ -236,6 +251,8 @@ public:
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const;
+ virtual bool hasInputProperty(int32_t deviceId, int property) const;
+
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const;
@@ -286,6 +303,7 @@ private:
uint32_t classes;
uint8_t* keyBitmask;
uint8_t* relBitmask;
+ uint8_t* propBitmask;
String8 configurationFile;
PropertyMap* configuration;
VirtualKeyMap* virtualKeyMap;
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 6003207..f07b01d 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -28,7 +28,7 @@
#define DEBUG_VIRTUAL_KEYS 0
// Log debug messages about pointers.
-#define DEBUG_POINTERS 0
+#define DEBUG_POINTERS 1
// Log debug messages about pointer assignment calculations.
#define DEBUG_POINTER_ASSIGNMENT 0
@@ -58,6 +58,9 @@ namespace android {
// --- Constants ---
+// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
+static const size_t MAX_SLOTS = 32;
+
// Quiet time between certain gesture transitions.
// Time to allow for all fingers or buttons to settle into a stable state before
// starting a new gesture.
@@ -809,7 +812,8 @@ bool InputReaderThread::threadLoop() {
// --- InputDevice ---
InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) :
- mContext(context), mId(id), mName(name), mSources(0), mIsExternal(false) {
+ mContext(context), mId(id), mName(name), mSources(0),
+ mIsExternal(false), mDropUntilNextSync(false) {
}
InputDevice::~InputDevice() {
@@ -898,9 +902,26 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) {
rawEvent->value, rawEvent->flags);
#endif
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
- mapper->process(rawEvent);
+ if (mDropUntilNextSync) {
+ if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) {
+ mDropUntilNextSync = false;
+#if DEBUG_RAW_EVENTS
+ LOGD("Recovered from input event buffer overrun.");
+#endif
+ } else {
+#if DEBUG_RAW_EVENTS
+ LOGD("Dropped input event while waiting for next input sync.");
+#endif
+ }
+ } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) {
+ LOGI("Detected input event buffer overrun for device %s.", mName.string());
+ mDropUntilNextSync = true;
+ reset();
+ } else {
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->process(rawEvent);
+ }
}
}
}
@@ -1812,6 +1833,10 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
info->addMotionRange(mLocked.orientedRanges.orientation);
}
+ if (mLocked.orientedRanges.haveDistance) {
+ info->addMotionRange(mLocked.orientedRanges.distance);
+ }
+
if (mPointerController != NULL) {
float minX, minY, maxX, maxY;
if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
@@ -1849,6 +1874,7 @@ void TouchInputMapper::dump(String8& dump) {
dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale);
dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale);
dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mLocked.orientationScale);
+ dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mLocked.distanceScale);
dump.appendFormat(INDENT3 "Last Touch:\n");
dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
@@ -1889,6 +1915,7 @@ void TouchInputMapper::initializeLocked() {
mLocked.orientedRanges.haveTouchSize = false;
mLocked.orientedRanges.haveToolSize = false;
mLocked.orientedRanges.haveOrientation = false;
+ mLocked.orientedRanges.haveDistance = false;
mPointerGesture.reset();
}
@@ -1947,9 +1974,14 @@ void TouchInputMapper::configureParameters() {
// The device is a cursor device with a touch pad attached.
// By default don't use the touch pad to move the pointer.
mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
+ // The device is a pointing device like a track pad.
+ mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
+ } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
+ // The device is a touch screen.
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
} else {
- // The device is just a touch pad.
- // By default use the touch pad to move the pointer and to perform related gestures.
+ // The device is a touch pad of unknown purpose.
mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
}
@@ -2016,6 +2048,9 @@ void TouchInputMapper::configureRawAxes() {
mRawAxes.toolMajor.clear();
mRawAxes.toolMinor.clear();
mRawAxes.orientation.clear();
+ mRawAxes.distance.clear();
+ mRawAxes.trackingId.clear();
+ mRawAxes.slot.clear();
}
void TouchInputMapper::dumpRawAxes(String8& dump) {
@@ -2028,6 +2063,9 @@ void TouchInputMapper::dumpRawAxes(String8& dump) {
dumpRawAbsoluteAxisInfo(dump, mRawAxes.toolMajor, "ToolMajor");
dumpRawAbsoluteAxisInfo(dump, mRawAxes.toolMinor, "ToolMinor");
dumpRawAbsoluteAxisInfo(dump, mRawAxes.orientation, "Orientation");
+ dumpRawAbsoluteAxisInfo(dump, mRawAxes.distance, "Distance");
+ dumpRawAbsoluteAxisInfo(dump, mRawAxes.trackingId, "TrackingId");
+ dumpRawAbsoluteAxisInfo(dump, mRawAxes.slot, "Slot");
}
bool TouchInputMapper::configureSurfaceLocked() {
@@ -2234,6 +2272,8 @@ bool TouchInputMapper::configureSurfaceLocked() {
}
}
+ mLocked.orientedRanges.haveOrientation = true;
+
mLocked.orientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
mLocked.orientedRanges.orientation.source = mTouchSource;
mLocked.orientedRanges.orientation.min = - M_PI_2;
@@ -2241,6 +2281,31 @@ bool TouchInputMapper::configureSurfaceLocked() {
mLocked.orientedRanges.orientation.flat = 0;
mLocked.orientedRanges.orientation.fuzz = 0;
}
+
+ // Distance
+ mLocked.distanceScale = 0;
+ if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
+ if (mCalibration.distanceCalibration
+ == Calibration::DISTANCE_CALIBRATION_SCALED) {
+ if (mCalibration.haveDistanceScale) {
+ mLocked.distanceScale = mCalibration.distanceScale;
+ } else {
+ mLocked.distanceScale = 1.0f;
+ }
+ }
+
+ mLocked.orientedRanges.haveDistance = true;
+
+ mLocked.orientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
+ mLocked.orientedRanges.distance.source = mTouchSource;
+ mLocked.orientedRanges.distance.min =
+ mRawAxes.distance.minValue * mLocked.distanceScale;
+ mLocked.orientedRanges.distance.max =
+ mRawAxes.distance.minValue * mLocked.distanceScale;
+ mLocked.orientedRanges.distance.flat = 0;
+ mLocked.orientedRanges.distance.fuzz =
+ mRawAxes.distance.fuzz * mLocked.distanceScale;
+ }
}
if (orientationChanged || sizeChanged) {
@@ -2518,6 +2583,23 @@ void TouchInputMapper::parseCalibration() {
orientationCalibrationString.string());
}
}
+
+ // Distance
+ out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
+ String8 distanceCalibrationString;
+ if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
+ if (distanceCalibrationString == "none") {
+ out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
+ } else if (distanceCalibrationString == "scaled") {
+ out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
+ } else if (distanceCalibrationString != "default") {
+ LOGW("Invalid value for touch.distance.calibration: '%s'",
+ distanceCalibrationString.string());
+ }
+ }
+
+ out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"),
+ out.distanceScale);
}
void TouchInputMapper::resolveCalibration() {
@@ -2618,6 +2700,20 @@ void TouchInputMapper::resolveCalibration() {
default:
break;
}
+
+ // Distance
+ switch (mCalibration.distanceCalibration) {
+ case Calibration::DISTANCE_CALIBRATION_DEFAULT:
+ if (mRawAxes.distance.valid) {
+ mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
+ } else {
+ mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
+ }
+ break;
+
+ default:
+ break;
+ }
}
void TouchInputMapper::dumpCalibration(String8& dump) {
@@ -2740,6 +2836,23 @@ void TouchInputMapper::dumpCalibration(String8& dump) {
default:
LOG_ASSERT(false);
}
+
+ // Distance
+ switch (mCalibration.distanceCalibration) {
+ case Calibration::DISTANCE_CALIBRATION_NONE:
+ dump.append(INDENT4 "touch.distance.calibration: none\n");
+ break;
+ case Calibration::DISTANCE_CALIBRATION_SCALED:
+ dump.append(INDENT4 "touch.distance.calibration: scaled\n");
+ break;
+ default:
+ LOG_ASSERT(false);
+ }
+
+ if (mCalibration.haveDistanceScale) {
+ dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n",
+ mCalibration.distanceScale);
+ }
}
void TouchInputMapper::reset() {
@@ -3247,6 +3360,16 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
orientation = 0;
}
+ // Distance
+ float distance;
+ switch (mCalibration.distanceCalibration) {
+ case Calibration::DISTANCE_CALIBRATION_SCALED:
+ distance = in.distance * mLocked.distanceScale;
+ break;
+ default:
+ distance = 0;
+ }
+
// X and Y
// Adjust coords for surface orientation.
float x, y;
@@ -3289,6 +3412,9 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor);
out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor);
out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation);
+ if (distance != 0) {
+ out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance);
+ }
// Write output properties.
PointerProperties& properties = mCurrentTouchProperties[i];
@@ -5020,13 +5146,13 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode
SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) :
TouchInputMapper(device) {
- initialize();
+ clearState();
}
SingleTouchInputMapper::~SingleTouchInputMapper() {
}
-void SingleTouchInputMapper::initialize() {
+void SingleTouchInputMapper::clearState() {
mAccumulator.clear();
mDown = false;
@@ -5040,7 +5166,7 @@ void SingleTouchInputMapper::initialize() {
void SingleTouchInputMapper::reset() {
TouchInputMapper::reset();
- initialize();
+ clearState();
}
void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
@@ -5144,6 +5270,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) {
mCurrentTouch.pointers[0].toolMajor = mToolWidth;
mCurrentTouch.pointers[0].toolMinor = mToolWidth;
mCurrentTouch.pointers[0].orientation = 0;
+ mCurrentTouch.pointers[0].distance = 0;
mCurrentTouch.pointers[0].isStylus = false; // TODO: Set stylus
mCurrentTouch.idToIndex[0] = 0;
mCurrentTouch.idBits.markBit(0);
@@ -5168,22 +5295,22 @@ void SingleTouchInputMapper::configureRawAxes() {
// --- MultiTouchInputMapper ---
MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
- TouchInputMapper(device) {
- initialize();
+ TouchInputMapper(device), mSlotCount(0), mUsingSlotsProtocol(false) {
+ clearState();
}
MultiTouchInputMapper::~MultiTouchInputMapper() {
}
-void MultiTouchInputMapper::initialize() {
- mAccumulator.clear();
+void MultiTouchInputMapper::clearState() {
+ mAccumulator.clear(mSlotCount);
mButtonState = 0;
}
void MultiTouchInputMapper::reset() {
TouchInputMapper::reset();
- initialize();
+ clearState();
}
void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
@@ -5203,45 +5330,69 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
}
case EV_ABS: {
- uint32_t pointerIndex = mAccumulator.pointerCount;
- Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];
+ bool newSlot = false;
+ if (mUsingSlotsProtocol && rawEvent->scanCode == ABS_MT_SLOT) {
+ mAccumulator.currentSlot = rawEvent->value;
+ newSlot = true;
+ }
+
+ if (mAccumulator.currentSlot < 0 || size_t(mAccumulator.currentSlot) >= mSlotCount) {
+ if (newSlot) {
+#if DEBUG_POINTERS
+ LOGW("MultiTouch device %s emitted invalid slot index %d but it "
+ "should be between 0 and %d; ignoring this slot.",
+ getDeviceName().string(), mAccumulator.currentSlot, mSlotCount);
+#endif
+ }
+ break;
+ }
+
+ Accumulator::Slot* slot = &mAccumulator.slots[mAccumulator.currentSlot];
switch (rawEvent->scanCode) {
case ABS_MT_POSITION_X:
- pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;
- pointer->absMTPositionX = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;
+ slot->absMTPositionX = rawEvent->value;
break;
case ABS_MT_POSITION_Y:
- pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;
- pointer->absMTPositionY = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;
+ slot->absMTPositionY = rawEvent->value;
break;
case ABS_MT_TOUCH_MAJOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
- pointer->absMTTouchMajor = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
+ slot->absMTTouchMajor = rawEvent->value;
break;
case ABS_MT_TOUCH_MINOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
- pointer->absMTTouchMinor = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
+ slot->absMTTouchMinor = rawEvent->value;
break;
case ABS_MT_WIDTH_MAJOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- pointer->absMTWidthMajor = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
+ slot->absMTWidthMajor = rawEvent->value;
break;
case ABS_MT_WIDTH_MINOR:
- pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
- pointer->absMTWidthMinor = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
+ slot->absMTWidthMinor = rawEvent->value;
break;
case ABS_MT_ORIENTATION:
- pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;
- pointer->absMTOrientation = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;
+ slot->absMTOrientation = rawEvent->value;
break;
case ABS_MT_TRACKING_ID:
- pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
- pointer->absMTTrackingId = rawEvent->value;
+ if (mUsingSlotsProtocol && rawEvent->value < 0) {
+ slot->clear();
+ } else {
+ slot->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
+ slot->absMTTrackingId = rawEvent->value;
+ }
break;
case ABS_MT_PRESSURE:
- pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE;
- pointer->absMTPressure = rawEvent->value;
+ slot->fields |= Accumulator::FIELD_ABS_MT_PRESSURE;
+ slot->absMTPressure = rawEvent->value;
+ break;
+ case ABS_MT_TOOL_TYPE:
+ slot->fields |= Accumulator::FIELD_ABS_MT_TOOL_TYPE;
+ slot->absMTToolType = rawEvent->value;
break;
}
break;
@@ -5251,19 +5402,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->scanCode) {
case SYN_MT_REPORT: {
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
- uint32_t pointerIndex = mAccumulator.pointerCount;
-
- if (mAccumulator.pointers[pointerIndex].fields) {
- if (pointerIndex == MAX_POINTERS) {
- LOGW("MultiTouch device driver returned more than maximum of %d pointers.",
- MAX_POINTERS);
- } else {
- pointerIndex += 1;
- mAccumulator.pointerCount = pointerIndex;
- }
- }
-
- mAccumulator.pointers[pointerIndex].clear();
+ mAccumulator.currentSlot += 1;
break;
}
@@ -5279,99 +5418,120 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
static const uint32_t REQUIRED_FIELDS =
Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y;
- uint32_t inCount = mAccumulator.pointerCount;
- uint32_t outCount = 0;
+ size_t inCount = mSlotCount;
+ size_t outCount = 0;
bool havePointerIds = true;
mCurrentTouch.clear();
- for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
- const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex];
- uint32_t fields = inPointer.fields;
+ for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
+ const Accumulator::Slot& inSlot = mAccumulator.slots[inIndex];
+ uint32_t fields = inSlot.fields;
if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
// Some drivers send empty MT sync packets without X / Y to indicate a pointer up.
+ // This may also indicate an unused slot.
// Drop this finger.
continue;
}
+ if (outCount >= MAX_POINTERS) {
+#if DEBUG_POINTERS
+ LOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
+ "ignoring the rest.",
+ getDeviceName().string(), MAX_POINTERS);
+#endif
+ break; // too many fingers!
+ }
+
PointerData& outPointer = mCurrentTouch.pointers[outCount];
- outPointer.x = inPointer.absMTPositionX;
- outPointer.y = inPointer.absMTPositionY;
+ outPointer.x = inSlot.absMTPositionX;
+ outPointer.y = inSlot.absMTPositionY;
if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) {
- if (inPointer.absMTPressure <= 0) {
- // Some devices send sync packets with X / Y but with a 0 pressure to indicate
- // a pointer going up. Drop this finger.
- continue;
- }
- outPointer.pressure = inPointer.absMTPressure;
+ outPointer.pressure = inSlot.absMTPressure;
} else {
// Default pressure to 0 if absent.
outPointer.pressure = 0;
}
if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) {
- if (inPointer.absMTTouchMajor <= 0) {
+ if (inSlot.absMTTouchMajor <= 0) {
// Some devices send sync packets with X / Y but with a 0 touch major to indicate
// a pointer going up. Drop this finger.
continue;
}
- outPointer.touchMajor = inPointer.absMTTouchMajor;
+ outPointer.touchMajor = inSlot.absMTTouchMajor;
} else {
// Default touch area to 0 if absent.
outPointer.touchMajor = 0;
}
if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) {
- outPointer.touchMinor = inPointer.absMTTouchMinor;
+ outPointer.touchMinor = inSlot.absMTTouchMinor;
} else {
// Assume touch area is circular.
outPointer.touchMinor = outPointer.touchMajor;
}
if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) {
- outPointer.toolMajor = inPointer.absMTWidthMajor;
+ outPointer.toolMajor = inSlot.absMTWidthMajor;
} else {
// Default tool area to 0 if absent.
outPointer.toolMajor = 0;
}
if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) {
- outPointer.toolMinor = inPointer.absMTWidthMinor;
+ outPointer.toolMinor = inSlot.absMTWidthMinor;
} else {
// Assume tool area is circular.
outPointer.toolMinor = outPointer.toolMajor;
}
if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) {
- outPointer.orientation = inPointer.absMTOrientation;
+ outPointer.orientation = inSlot.absMTOrientation;
} else {
// Default orientation to vertical if absent.
outPointer.orientation = 0;
}
- outPointer.isStylus = false; // TODO: Handle stylus
+ if (fields & Accumulator::FIELD_ABS_MT_DISTANCE) {
+ outPointer.distance = inSlot.absMTDistance;
+ } else {
+ // Default distance is 0 (direct contact).
+ outPointer.distance = 0;
+ }
+
+ if (fields & Accumulator::FIELD_ABS_MT_TOOL_TYPE) {
+ outPointer.isStylus = (inSlot.absMTToolType == MT_TOOL_PEN);
+ } else {
+ // Assume this is not a stylus.
+ outPointer.isStylus = false;
+ }
// Assign pointer id using tracking id if available.
if (havePointerIds) {
- if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
- uint32_t id = uint32_t(inPointer.absMTTrackingId);
+ int32_t id;
+ if (mUsingSlotsProtocol) {
+ id = inIndex;
+ } else if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) {
+ id = inSlot.absMTTrackingId;
+ } else {
+ id = -1;
+ }
- if (id > MAX_POINTER_ID) {
+ if (id >= 0 && id <= MAX_POINTER_ID) {
+ outPointer.id = id;
+ mCurrentTouch.idToIndex[id] = outCount;
+ mCurrentTouch.idBits.markBit(id);
+ } else {
+ if (id >= 0) {
#if DEBUG_POINTERS
- LOGD("Pointers: Ignoring driver provided pointer id %d because "
- "it is larger than max supported id %d",
+ LOGD("Pointers: Ignoring driver provided slot index or tracking id %d because "
+ "it is larger than the maximum supported pointer id %d",
id, MAX_POINTER_ID);
#endif
- havePointerIds = false;
- }
- else {
- outPointer.id = id;
- mCurrentTouch.idToIndex[id] = outCount;
- mCurrentTouch.idBits.markBit(id);
}
- } else {
havePointerIds = false;
}
}
@@ -5386,20 +5546,40 @@ void MultiTouchInputMapper::sync(nsecs_t when) {
syncTouch(when, havePointerIds);
- mAccumulator.clear();
+ mAccumulator.clear(mUsingSlotsProtocol ? 0 : mSlotCount);
}
void MultiTouchInputMapper::configureRawAxes() {
TouchInputMapper::configureRawAxes();
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mRawAxes.x);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mRawAxes.y);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mRawAxes.touchMajor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mRawAxes.touchMinor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mRawAxes.toolMajor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mRawAxes.toolMinor);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mRawAxes.orientation);
- getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mRawAxes.pressure);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, &mRawAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, &mRawAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, &mRawAxes.touchMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, &mRawAxes.touchMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, &mRawAxes.toolMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, &mRawAxes.toolMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, &mRawAxes.orientation);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, &mRawAxes.pressure);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_DISTANCE, &mRawAxes.distance);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TRACKING_ID, &mRawAxes.trackingId);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_SLOT, &mRawAxes.slot);
+
+ if (mRawAxes.trackingId.valid
+ && mRawAxes.slot.valid && mRawAxes.slot.minValue == 0 && mRawAxes.slot.maxValue > 0) {
+ mSlotCount = mRawAxes.slot.maxValue + 1;
+ if (mSlotCount > MAX_SLOTS) {
+ LOGW("MultiTouch Device %s reported %d slots but the framework "
+ "only supports a maximum of %d slots at this time.",
+ getDeviceName().string(), mSlotCount, MAX_SLOTS);
+ mSlotCount = MAX_SLOTS;
+ }
+ mUsingSlotsProtocol = true;
+ } else {
+ mSlotCount = MAX_POINTERS;
+ mUsingSlotsProtocol = false;
+ }
+
+ mAccumulator.allocateSlots(mSlotCount);
}
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 62ac4b2..85338b6 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -331,6 +331,7 @@ private:
String8 mName;
uint32_t mSources;
bool mIsExternal;
+ bool mDropUntilNextSync;
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
@@ -602,6 +603,7 @@ protected:
int32_t toolMajor;
int32_t toolMinor;
int32_t orientation;
+ int32_t distance;
bool isStylus;
inline bool operator== (const PointerData& other) const {
@@ -613,7 +615,8 @@ protected:
&& touchMinor == other.touchMinor
&& toolMajor == other.toolMajor
&& toolMinor == other.toolMinor
- && orientation == other.orientation;
+ && orientation == other.orientation
+ && distance == other.distance;
}
inline bool operator!= (const PointerData& other) const {
return !(*this == other);
@@ -759,6 +762,17 @@ protected:
};
OrientationCalibration orientationCalibration;
+
+ // Distance
+ enum DistanceCalibration {
+ DISTANCE_CALIBRATION_DEFAULT,
+ DISTANCE_CALIBRATION_NONE,
+ DISTANCE_CALIBRATION_SCALED,
+ };
+
+ DistanceCalibration distanceCalibration;
+ bool haveDistanceScale;
+ float distanceScale;
} mCalibration;
// Raw axis information from the driver.
@@ -771,6 +785,9 @@ protected:
RawAbsoluteAxisInfo toolMajor;
RawAbsoluteAxisInfo toolMinor;
RawAbsoluteAxisInfo orientation;
+ RawAbsoluteAxisInfo distance;
+ RawAbsoluteAxisInfo trackingId;
+ RawAbsoluteAxisInfo slot;
} mRawAxes;
// Current and previous touch sample data.
@@ -819,6 +836,8 @@ protected:
float orientationScale;
+ float distanceScale;
+
// Oriented motion ranges for input device info.
struct OrientedRanges {
InputDeviceInfo::MotionRange x;
@@ -840,6 +859,9 @@ protected:
bool haveOrientation;
InputDeviceInfo::MotionRange orientation;
+
+ bool haveDistance;
+ InputDeviceInfo::MotionRange distance;
} orientedRanges;
// Oriented dimensions and precision.
@@ -1146,7 +1168,7 @@ private:
int32_t mToolWidth;
int32_t mButtonState;
- void initialize();
+ void clearState();
void sync(nsecs_t when);
};
@@ -1166,20 +1188,21 @@ protected:
private:
struct Accumulator {
enum {
- FIELD_ABS_MT_POSITION_X = 1,
- FIELD_ABS_MT_POSITION_Y = 2,
- FIELD_ABS_MT_TOUCH_MAJOR = 4,
- FIELD_ABS_MT_TOUCH_MINOR = 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_PRESSURE = 256,
+ FIELD_ABS_MT_POSITION_X = 1 << 0,
+ FIELD_ABS_MT_POSITION_Y = 1 << 1,
+ FIELD_ABS_MT_TOUCH_MAJOR = 1 << 2,
+ FIELD_ABS_MT_TOUCH_MINOR = 1 << 3,
+ FIELD_ABS_MT_WIDTH_MAJOR = 1 << 4,
+ FIELD_ABS_MT_WIDTH_MINOR = 1 << 5,
+ FIELD_ABS_MT_ORIENTATION = 1 << 6,
+ FIELD_ABS_MT_TRACKING_ID = 1 << 7,
+ FIELD_ABS_MT_PRESSURE = 1 << 8,
+ FIELD_ABS_MT_TOOL_TYPE = 1 << 9,
+ FIELD_ABS_MT_DISTANCE = 1 << 10,
};
- uint32_t pointerCount;
- struct Pointer {
- uint32_t fields;
+ struct Slot {
+ uint32_t fields; // 0 if slot is unused
int32_t absMTPositionX;
int32_t absMTPositionY;
@@ -1190,27 +1213,56 @@ private:
int32_t absMTOrientation;
int32_t absMTTrackingId;
int32_t absMTPressure;
+ int32_t absMTToolType;
+ int32_t absMTDistance;
+
+ inline Slot() {
+ clear();
+ }
inline void clear() {
fields = 0;
}
- } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
+ };
+
+ // Current slot index.
+ int32_t currentSlot;
+
+ // Array of slots.
+ Slot* slots;
// Bitfield of buttons that went down or up.
uint32_t buttonDown;
uint32_t buttonUp;
- inline void clear() {
- pointerCount = 0;
- pointers[0].clear();
+ Accumulator() : slots(NULL) {
+ clear(false);
+ }
+
+ ~Accumulator() {
+ delete[] slots;
+ }
+
+ void allocateSlots(size_t slotCount) {
+ slots = new Slot[slotCount];
+ }
+
+ void clear(size_t slotCount) {
+ for (size_t i = 0; i < slotCount; i++) {
+ slots[i].clear();
+ }
+ currentSlot = 0;
buttonDown = 0;
buttonUp = 0;
}
} mAccumulator;
+ size_t mSlotCount;
+ bool mUsingSlotsProtocol;
+
int32_t mButtonState;
- void initialize();
+ void clearState();
void sync(nsecs_t when);
};
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index f5d7ae8..1ab2a3e 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -613,6 +613,10 @@ private:
return false;
}
+ virtual bool hasInputProperty(int32_t deviceId, int property) const {
+ return false;
+ }
+
virtual status_t mapKey(int32_t deviceId, int scancode,
int32_t* outKeycode, uint32_t* outFlags) const {
Device* device = getDevice(deviceId);