diff options
| author | 2010-08-30 03:02:23 -0700 | |
|---|---|---|
| committer | 2010-08-30 18:16:43 -0700 | |
| commit | 38a7fabd96566a229a276e7066ac1caf5157e127 (patch) | |
| tree | 155a049d00d0609f45229b7b3556f142f26b8f2b | |
| parent | 296e9b712b4de1eda5ade482f0d0672225b53f3a (diff) | |
Input device calibration and capabilities.
Finished the input device capability API.
Added a mechanism for calibrating touch devices to obtain more
accurate information about the touch contact area.
Improved pointer location to show new coordinates and capabilities.
Optimized pointer location display and formatting to avoid allocating large
numbers of temporary objects. The GC churn was causing the application to
stutter very badly when more than a couple of fingers were down).
Added more diagnostics.
Change-Id: Ie25380278ed6f16c5b04cd9df848015850383498
| -rw-r--r-- | include/ui/EventHub.h | 8 | ||||
| -rw-r--r-- | include/ui/Input.h | 4 | ||||
| -rw-r--r-- | include/ui/InputReader.h | 157 | ||||
| -rw-r--r-- | libs/ui/EventHub.cpp | 9 | ||||
| -rw-r--r-- | libs/ui/InputDispatcher.cpp | 22 | ||||
| -rw-r--r-- | libs/ui/InputReader.cpp | 1046 |
6 files changed, 973 insertions, 273 deletions
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h index 3d42856335..25d5afbf90 100644 --- a/include/ui/EventHub.h +++ b/include/ui/EventHub.h @@ -82,6 +82,14 @@ struct RawAbsoluteAxisInfo { int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise inline int32_t getRange() { return maxValue - minValue; } + + inline void clear() { + valid = false; + minValue = 0; + maxValue = 0; + flat = 0; + fuzz = 0; + } }; /* diff --git a/include/ui/Input.h b/include/ui/Input.h index 2385973e69..49347d3f89 100644 --- a/include/ui/Input.h +++ b/include/ui/Input.h @@ -453,6 +453,10 @@ public: inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } inline int32_t getKeyboardType() const { return mKeyboardType; } + inline const KeyedVector<int32_t, MotionRange> getMotionRanges() const { + return mMotionRanges; + } + private: int32_t mId; String8 mName; diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h index 56d2765152..7a089a45a1 100644 --- a/include/ui/InputReader.h +++ b/include/ui/InputReader.h @@ -35,6 +35,34 @@ namespace android { class InputDevice; class InputMapper; +/* Describes a virtual key. */ +struct VirtualKeyDefinition { + int32_t scanCode; + + // configured position data, specified in display coords + int32_t centerX; + int32_t centerY; + int32_t width; + int32_t height; +}; + + +/* Specifies input device calibration settings. */ +class InputDeviceCalibration { +public: + InputDeviceCalibration(); + + void clear(); + void addProperty(const String8& key, const String8& value); + + bool tryGetProperty(const String8& key, String8& outValue) const; + bool tryGetProperty(const String8& key, int32_t& outValue) const; + bool tryGetProperty(const String8& key, float& outValue) const; + +private: + KeyedVector<String8, String8> mProperties; +}; + /* * Input reader policy interface. @@ -73,17 +101,6 @@ public: ACTION_APP_SWITCH_COMING = 0x00000002, }; - /* Describes a virtual key. */ - struct VirtualKeyDefinition { - int32_t scanCode; - - // configured position data, specified in display coords - int32_t centerX; - int32_t centerY; - int32_t width; - int32_t height; - }; - /* Gets information about the display with the specified id. * Returns true if the display info is available, false otherwise. */ @@ -135,6 +152,10 @@ public: virtual void getVirtualKeyDefinitions(const String8& deviceName, Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0; + /* Gets the calibration for an input device. */ + virtual void getInputDeviceCalibration(const String8& deviceName, + InputDeviceCalibration& outCalibration) = 0; + /* Gets the excluded device names for the platform. */ virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0; }; @@ -327,6 +348,10 @@ public: int32_t getMetaState(); + inline const InputDeviceCalibration& getCalibration() { + return mCalibration; + } + private: InputReaderContext* mContext; int32_t mId; @@ -338,6 +363,8 @@ private: typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); + + InputDeviceCalibration mCalibration; }; @@ -538,12 +565,12 @@ protected: } }; + // Raw data for a single pointer. struct PointerData { uint32_t id; int32_t x; int32_t y; int32_t pressure; - int32_t size; int32_t touchMajor; int32_t touchMinor; int32_t toolMajor; @@ -551,6 +578,7 @@ protected: int32_t orientation; }; + // Raw data for a collection of pointers including a pointer id mapping table. struct TouchData { uint32_t pointerCount; PointerData pointers[MAX_POINTERS]; @@ -584,18 +612,82 @@ protected: bool useAveragingTouchFilter; } mParameters; - // Raw axis information. - struct Axes { + // Immutable calibration parameters in parsed form. + struct Calibration { + // Touch Area + enum TouchAreaCalibration { + TOUCH_AREA_CALIBRATION_DEFAULT, + TOUCH_AREA_CALIBRATION_NONE, + TOUCH_AREA_CALIBRATION_GEOMETRIC, + TOUCH_AREA_CALIBRATION_PRESSURE, + }; + + TouchAreaCalibration touchAreaCalibration; + + // Tool Area + enum ToolAreaCalibration { + TOOL_AREA_CALIBRATION_DEFAULT, + TOOL_AREA_CALIBRATION_NONE, + TOOL_AREA_CALIBRATION_GEOMETRIC, + TOOL_AREA_CALIBRATION_LINEAR, + }; + + ToolAreaCalibration toolAreaCalibration; + bool haveToolAreaLinearScale; + float toolAreaLinearScale; + bool haveToolAreaLinearBias; + float toolAreaLinearBias; + bool haveToolAreaIsSummed; + int32_t toolAreaIsSummed; + + // Pressure + enum PressureCalibration { + PRESSURE_CALIBRATION_DEFAULT, + PRESSURE_CALIBRATION_NONE, + PRESSURE_CALIBRATION_PHYSICAL, + PRESSURE_CALIBRATION_AMPLITUDE, + }; + enum PressureSource { + PRESSURE_SOURCE_DEFAULT, + PRESSURE_SOURCE_PRESSURE, + PRESSURE_SOURCE_TOUCH, + }; + + PressureCalibration pressureCalibration; + PressureSource pressureSource; + bool havePressureScale; + float pressureScale; + + // Size + enum SizeCalibration { + SIZE_CALIBRATION_DEFAULT, + SIZE_CALIBRATION_NONE, + SIZE_CALIBRATION_NORMALIZED, + }; + + SizeCalibration sizeCalibration; + + // Orientation + enum OrientationCalibration { + ORIENTATION_CALIBRATION_DEFAULT, + ORIENTATION_CALIBRATION_NONE, + ORIENTATION_CALIBRATION_INTERPOLATED, + }; + + OrientationCalibration orientationCalibration; + } mCalibration; + + // Raw axis information from the driver. + struct RawAxes { RawAbsoluteAxisInfo x; RawAbsoluteAxisInfo y; RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo size; RawAbsoluteAxisInfo touchMajor; RawAbsoluteAxisInfo touchMinor; RawAbsoluteAxisInfo toolMajor; RawAbsoluteAxisInfo toolMinor; RawAbsoluteAxisInfo orientation; - } mAxes; + } mRawAxes; // Current and previous touch sample data. TouchData mCurrentTouch; @@ -620,10 +712,13 @@ protected: float yScale; float yPrecision; - int32_t pressureOrigin; + float geometricScale; + + float toolAreaLinearScale; + float toolAreaLinearBias; + float pressureScale; - int32_t sizeOrigin; float sizeScale; float orientationScale; @@ -632,12 +727,22 @@ protected: struct OrientedRanges { InputDeviceInfo::MotionRange x; InputDeviceInfo::MotionRange y; + + bool havePressure; InputDeviceInfo::MotionRange pressure; + + bool haveSize; InputDeviceInfo::MotionRange size; + + bool haveTouchArea; InputDeviceInfo::MotionRange touchMajor; InputDeviceInfo::MotionRange touchMinor; + + bool haveToolArea; InputDeviceInfo::MotionRange toolMajor; InputDeviceInfo::MotionRange toolMinor; + + bool haveOrientation; InputDeviceInfo::MotionRange orientation; } orientedRanges; @@ -653,9 +758,14 @@ protected: } currentVirtualKey; } mLocked; - virtual void configureAxes(); + virtual void configureParameters(); + virtual void configureRawAxes(); + virtual void logRawAxes(); virtual bool configureSurfaceLocked(); virtual void configureVirtualKeysLocked(); + virtual void parseCalibration(); + virtual void resolveCalibration(); + virtual void logCalibration(); enum TouchResult { // Dispatch the touch normally. @@ -713,7 +823,8 @@ private: TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch, - BitSet32 idBits, uint32_t changedId, int32_t motionEventAction); + BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, + int32_t motionEventAction); void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags, @@ -738,7 +849,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void configureAxes(); + virtual void configureRawAxes(); private: struct Accumulator { @@ -767,7 +878,7 @@ private: int32_t mX; int32_t mY; int32_t mPressure; - int32_t mSize; + int32_t mToolWidth; void initialize(); @@ -784,7 +895,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void configureAxes(); + virtual void configureRawAxes(); private: struct Accumulator { diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp index 891661d690..1d38b4ba8f 100644 --- a/libs/ui/EventHub.cpp +++ b/libs/ui/EventHub.cpp @@ -139,11 +139,7 @@ uint32_t EventHub::getDeviceClasses(int32_t deviceId) const status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { - outAxisInfo->valid = false; - outAxisInfo->minValue = 0; - outAxisInfo->maxValue = 0; - outAxisInfo->flat = 0; - outAxisInfo->fuzz = 0; + outAxisInfo->clear(); AutoMutex _l(mLock); device_t* device = getDevice(deviceId); @@ -709,8 +705,7 @@ int EventHub::open_device(const char *deviceName) LOGV("Getting absolute controllers..."); if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) { // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) - && test_bit(ABS_MT_POSITION_X, abs_bitmask) + if (test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index e35050cb6e..886c7856de 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -405,12 +405,15 @@ void InputDispatcher::processMotionLockedInterruptible( sampleCount += 1; } for (uint32_t i = 0; i < entry->pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f", + LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, " + "orientation=%f", i, entry->pointerIds[i], - sample->pointerCoords[i].x, - sample->pointerCoords[i].y, - sample->pointerCoords[i].pressure, - sample->pointerCoords[i].size); + sample->pointerCoords[i].x, sample->pointerCoords[i].y, + sample->pointerCoords[i].pressure, sample->pointerCoords[i].size, + sample->pointerCoords[i].touchMajor, sample->pointerCoords[i].touchMinor, + sample->pointerCoords[i].toolMajor, sample->pointerCoords[i].toolMinor, + sample->pointerCoords[i].orientation); } // Keep in mind that due to batching, it is possible for the number of samples actually @@ -1080,9 +1083,14 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t eventTime, deviceId, source, policyFlags, action, metaState, edgeFlags, xPrecision, yPrecision, downTime); for (uint32_t i = 0; i < pointerCount; i++) { - LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f", + LOGD(" Pointer %d: id=%d, x=%f, y=%f, pressure=%f, size=%f, " + "touchMajor=%f, touchMinor=%d, toolMajor=%f, toolMinor=%f, " + "orientation=%f", i, pointerIds[i], pointerCoords[i].x, pointerCoords[i].y, - pointerCoords[i].pressure, pointerCoords[i].size); + pointerCoords[i].pressure, pointerCoords[i].size, + pointerCoords[i].touchMajor, pointerCoords[i].touchMinor, + pointerCoords[i].toolMajor, pointerCoords[i].toolMinor, + pointerCoords[i].orientation); } #endif diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp index 6f042ec7e8..8ffb48debe 100644 --- a/libs/ui/InputReader.cpp +++ b/libs/ui/InputReader.cpp @@ -26,11 +26,14 @@ #include <ui/InputReader.h> #include <stddef.h> +#include <stdlib.h> #include <unistd.h> #include <errno.h> #include <limits.h> #include <math.h> +#define INDENT " " + namespace android { // --- Static Functions --- @@ -52,6 +55,14 @@ inline static void swap(T& a, T& b) { b = temp; } +inline static float avg(float x, float y) { + return (x + y) / 2; +} + +inline static float pythag(float x, float y) { + return sqrtf(x * x + y * y); +} + int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; @@ -116,6 +127,64 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { } +// --- InputDeviceCalibration --- + +InputDeviceCalibration::InputDeviceCalibration() { +} + +void InputDeviceCalibration::clear() { + mProperties.clear(); +} + +void InputDeviceCalibration::addProperty(const String8& key, const String8& value) { + mProperties.add(key, value); +} + +bool InputDeviceCalibration::tryGetProperty(const String8& key, String8& outValue) const { + ssize_t index = mProperties.indexOfKey(key); + if (index < 0) { + return false; + } + + outValue = mProperties.valueAt(index); + return true; +} + +bool InputDeviceCalibration::tryGetProperty(const String8& key, int32_t& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + int value = strtol(stringValue.string(), & end, 10); + if (*end != '\0') { + LOGW("Input device calibration key '%s' has invalid value '%s'. Expected an integer.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + +bool InputDeviceCalibration::tryGetProperty(const String8& key, float& outValue) const { + String8 stringValue; + if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) { + return false; + } + + char* end; + float value = strtof(stringValue.string(), & end); + if (*end != '\0') { + LOGW("Input device calibration key '%s' has invalid value '%s'. Expected a float.", + key.string(), stringValue.string()); + return false; + } + outValue = value; + return true; +} + + // --- InputReader --- InputReader::InputReader(const sp<EventHubInterface>& eventHub, @@ -167,9 +236,18 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) { String8 name = mEventHub->getDeviceName(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); + // Write a log message about the added device as a heading for subsequent log messages. + LOGI("Device added: id=0x%x, name=%s", deviceId, name.string()); + InputDevice* device = createDevice(deviceId, name, classes); device->configure(); + if (device->isIgnored()) { + LOGI(INDENT "Sources: none (device is ignored)"); + } else { + LOGI(INDENT "Sources: 0x%08x", device->getSources()); + } + bool added = false; { // acquire device registry writer lock RWLock::AutoWLock _wl(mDeviceRegistryLock); @@ -187,14 +265,6 @@ void InputReader::addDevice(nsecs_t when, int32_t deviceId) { return; } - if (device->isIgnored()) { - LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", - deviceId, name.string()); - } else { - LOGI("Device added: id=0x%x, name=%s, sources=%08x", - deviceId, name.string(), device->getSources()); - } - handleConfigurationChanged(when); } @@ -217,8 +287,7 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { return; } - device->reset(); - + // Write a log message about the removed device as a heading for subsequent log messages. if (device->isIgnored()) { LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", device->getId(), device->getName().string()); @@ -227,6 +296,8 @@ void InputReader::removeDevice(nsecs_t when, int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } + device->reset(); + delete device; handleConfigurationChanged(when); @@ -537,6 +608,10 @@ void InputDevice::addMapper(InputMapper* mapper) { } void InputDevice::configure() { + if (! isIgnored()) { + mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration); + } + mSources = 0; size_t numMappers = mMappers.size(); @@ -1121,13 +1196,35 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x); info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y); - info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mLocked.orientedRanges.pressure); - info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mLocked.orientedRanges.size); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mLocked.orientedRanges.touchMinor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mLocked.orientedRanges.toolMajor); - info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mLocked.orientedRanges.toolMinor); - info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mLocked.orientedRanges.orientation); + + if (mLocked.orientedRanges.havePressure) { + info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, + mLocked.orientedRanges.pressure); + } + + if (mLocked.orientedRanges.haveSize) { + info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, + mLocked.orientedRanges.size); + } + + if (mLocked.orientedRanges.haveTouchArea) { + info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, + mLocked.orientedRanges.touchMajor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, + mLocked.orientedRanges.touchMinor); + } + + if (mLocked.orientedRanges.haveToolArea) { + info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, + mLocked.orientedRanges.toolMajor); + info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, + mLocked.orientedRanges.toolMinor); + } + + if (mLocked.orientedRanges.haveOrientation) { + info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, + mLocked.orientedRanges.orientation); + } } // release lock } @@ -1144,77 +1241,72 @@ void TouchInputMapper::initializeLocked() { mJumpyTouchFilter.jumpyPointsDropped = 0; mLocked.currentVirtualKey.down = false; + + mLocked.orientedRanges.havePressure = false; + mLocked.orientedRanges.haveSize = false; + mLocked.orientedRanges.haveTouchArea = false; + mLocked.orientedRanges.haveToolArea = false; + mLocked.orientedRanges.haveOrientation = false; +} + +static void logAxisInfo(RawAbsoluteAxisInfo axis, const char* name) { + if (axis.valid) { + LOGI(INDENT "Raw %s axis: min=%d, max=%d, flat=%d, fuzz=%d", + name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz); + } else { + LOGI(INDENT "Raw %s axis: unknown range", name); + } } void TouchInputMapper::configure() { InputMapper::configure(); // Configure basic parameters. - mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); - mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); + configureParameters(); // Configure absolute axis information. - configureAxes(); + configureRawAxes(); + logRawAxes(); + + // Prepare input device calibration. + parseCalibration(); + resolveCalibration(); + logCalibration(); { // acquire lock AutoMutex _l(mLock); - // Configure pressure factors. - if (mAxes.pressure.valid) { - mLocked.pressureOrigin = mAxes.pressure.minValue; - mLocked.pressureScale = 1.0f / mAxes.pressure.getRange(); - } else { - mLocked.pressureOrigin = 0; - mLocked.pressureScale = 1.0f; - } - - mLocked.orientedRanges.pressure.min = 0.0f; - mLocked.orientedRanges.pressure.max = 1.0f; - mLocked.orientedRanges.pressure.flat = 0.0f; - mLocked.orientedRanges.pressure.fuzz = mLocked.pressureScale; - - // Configure size factors. - if (mAxes.size.valid) { - mLocked.sizeOrigin = mAxes.size.minValue; - mLocked.sizeScale = 1.0f / mAxes.size.getRange(); - } else { - mLocked.sizeOrigin = 0; - mLocked.sizeScale = 1.0f; - } - - mLocked.orientedRanges.size.min = 0.0f; - mLocked.orientedRanges.size.max = 1.0f; - mLocked.orientedRanges.size.flat = 0.0f; - mLocked.orientedRanges.size.fuzz = mLocked.sizeScale; - - // Configure orientation factors. - if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) { - mLocked.orientationScale = float(M_PI_2) / mAxes.orientation.maxValue; - } else { - mLocked.orientationScale = 0.0f; - } - - mLocked.orientedRanges.orientation.min = - M_PI_2; - mLocked.orientedRanges.orientation.max = M_PI_2; - mLocked.orientedRanges.orientation.flat = 0; - mLocked.orientedRanges.orientation.fuzz = mLocked.orientationScale; - - // Configure surface dimensions and orientation. + // Configure surface dimensions and orientation. configureSurfaceLocked(); } // release lock } -void TouchInputMapper::configureAxes() { - mAxes.x.valid = false; - mAxes.y.valid = false; - mAxes.pressure.valid = false; - mAxes.size.valid = false; - mAxes.touchMajor.valid = false; - mAxes.touchMinor.valid = false; - mAxes.toolMajor.valid = false; - mAxes.toolMinor.valid = false; - mAxes.orientation.valid = false; +void TouchInputMapper::configureParameters() { + mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents(); + mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents(); + mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents(); +} + +void TouchInputMapper::configureRawAxes() { + mRawAxes.x.clear(); + mRawAxes.y.clear(); + mRawAxes.pressure.clear(); + mRawAxes.touchMajor.clear(); + mRawAxes.touchMinor.clear(); + mRawAxes.toolMajor.clear(); + mRawAxes.toolMinor.clear(); + mRawAxes.orientation.clear(); +} + +void TouchInputMapper::logRawAxes() { + logAxisInfo(mRawAxes.x, "x"); + logAxisInfo(mRawAxes.y, "y"); + logAxisInfo(mRawAxes.pressure, "pressure"); + logAxisInfo(mRawAxes.touchMajor, "touchMajor"); + logAxisInfo(mRawAxes.touchMinor, "touchMinor"); + logAxisInfo(mRawAxes.toolMajor, "toolMajor"); + logAxisInfo(mRawAxes.toolMinor, "toolMinor"); + logAxisInfo(mRawAxes.orientation, "orientation"); } bool TouchInputMapper::configureSurfaceLocked() { @@ -1228,8 +1320,8 @@ bool TouchInputMapper::configureSurfaceLocked() { } } else { orientation = InputReaderPolicyInterface::ROTATION_0; - width = mAxes.x.getRange(); - height = mAxes.y.getRange(); + width = mRawAxes.x.getRange(); + height = mRawAxes.y.getRange(); } bool orientationChanged = mLocked.surfaceOrientation != orientation; @@ -1239,24 +1331,24 @@ bool TouchInputMapper::configureSurfaceLocked() { bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { + LOGI("Device configured: id=0x%x, name=%s (display size was changed)", + getDeviceId(), getDeviceName().string()); + mLocked.surfaceWidth = width; mLocked.surfaceHeight = height; - // Compute size-dependent translation and scaling factors and place virtual keys. - if (mAxes.x.valid && mAxes.y.valid) { - mLocked.xOrigin = mAxes.x.minValue; - mLocked.yOrigin = mAxes.y.minValue; - - LOGI("Device configured: id=0x%x, name=%s (display size was changed)", - getDeviceId(), getDeviceName().string()); - - mLocked.xScale = float(width) / mAxes.x.getRange(); - mLocked.yScale = float(height) / mAxes.y.getRange(); + // Configure X and Y factors. + if (mRawAxes.x.valid && mRawAxes.y.valid) { + mLocked.xOrigin = mRawAxes.x.minValue; + mLocked.yOrigin = mRawAxes.y.minValue; + mLocked.xScale = float(width) / mRawAxes.x.getRange(); + mLocked.yScale = float(height) / mRawAxes.y.getRange(); mLocked.xPrecision = 1.0f / mLocked.xScale; mLocked.yPrecision = 1.0f / mLocked.yScale; configureVirtualKeysLocked(); } else { + LOGW(INDENT "Touch device did not report support for X or Y axis!"); mLocked.xOrigin = 0; mLocked.yOrigin = 0; mLocked.xScale = 1.0f; @@ -1265,22 +1357,112 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.yPrecision = 1.0f; } - // Configure touch and tool area ranges. - float diagonal = sqrt(float(width * width + height * height)); - float diagonalFuzz = sqrt(mLocked.xScale * mLocked.xScale - + mLocked.yScale * mLocked.yScale); + // Scale factor for terms that are not oriented in a particular axis. + // If the pixels are square then xScale == yScale otherwise we fake it + // by choosing an average. + mLocked.geometricScale = avg(mLocked.xScale, mLocked.yScale); + + // Size of diagonal axis. + float diagonalSize = pythag(width, height); + + // TouchMajor and TouchMinor factors. + if (mCalibration.touchAreaCalibration != Calibration::TOUCH_AREA_CALIBRATION_NONE) { + mLocked.orientedRanges.haveTouchArea = true; + mLocked.orientedRanges.touchMajor.min = 0; + mLocked.orientedRanges.touchMajor.max = diagonalSize; + mLocked.orientedRanges.touchMajor.flat = 0; + mLocked.orientedRanges.touchMajor.fuzz = 0; + mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor; + } + + // ToolMajor and ToolMinor factors. + if (mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) { + mLocked.toolAreaLinearScale = 0; + mLocked.toolAreaLinearBias = 0; + if (mCalibration.toolAreaCalibration == Calibration::TOOL_AREA_CALIBRATION_LINEAR) { + if (mCalibration.haveToolAreaLinearScale) { + mLocked.toolAreaLinearScale = mCalibration.toolAreaLinearScale; + } else if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { + mLocked.toolAreaLinearScale = float(min(width, height)) + / mRawAxes.toolMajor.maxValue; + } + + if (mCalibration.haveToolAreaLinearBias) { + mLocked.toolAreaLinearBias = mCalibration.toolAreaLinearBias; + } + } + + mLocked.orientedRanges.haveToolArea = true; + mLocked.orientedRanges.toolMajor.min = 0; + mLocked.orientedRanges.toolMajor.max = diagonalSize; + mLocked.orientedRanges.toolMajor.flat = 0; + mLocked.orientedRanges.toolMajor.fuzz = 0; + mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor; + } + + // Pressure factors. + if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE) { + RawAbsoluteAxisInfo rawPressureAxis; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + rawPressureAxis = mRawAxes.pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + rawPressureAxis = mRawAxes.touchMajor; + break; + default: + rawPressureAxis.clear(); + } + + mLocked.pressureScale = 0; + if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL + || mCalibration.pressureCalibration + == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { + if (mCalibration.havePressureScale) { + mLocked.pressureScale = mCalibration.pressureScale; + } else if (rawPressureAxis.valid && rawPressureAxis.maxValue != 0) { + mLocked.pressureScale = 1.0f / rawPressureAxis.maxValue; + } + } + + mLocked.orientedRanges.havePressure = true; + mLocked.orientedRanges.pressure.min = 0; + mLocked.orientedRanges.pressure.max = 1.0; + mLocked.orientedRanges.pressure.flat = 0; + mLocked.orientedRanges.pressure.fuzz = 0; + } + + // Size factors. + if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { + mLocked.sizeScale = 0; + if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_NORMALIZED) { + if (mRawAxes.toolMajor.valid && mRawAxes.toolMajor.maxValue != 0) { + mLocked.sizeScale = 1.0f / mRawAxes.toolMajor.maxValue; + } + } - InputDeviceInfo::MotionRange area; - area.min = 0.0f; - area.max = diagonal; - area.flat = 0.0f; - area.fuzz = diagonalFuzz; + mLocked.orientedRanges.haveSize = true; + mLocked.orientedRanges.size.min = 0; + mLocked.orientedRanges.size.max = 1.0; + mLocked.orientedRanges.size.flat = 0; + mLocked.orientedRanges.size.fuzz = 0; + } - mLocked.orientedRanges.touchMajor = area; - mLocked.orientedRanges.touchMinor = area; + // Orientation + if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) { + mLocked.orientationScale = 0; + if (mCalibration.orientationCalibration + == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { + if (mRawAxes.orientation.valid && mRawAxes.orientation.maxValue != 0) { + mLocked.orientationScale = float(M_PI_2) / mRawAxes.orientation.maxValue; + } + } - mLocked.orientedRanges.toolMajor = area; - mLocked.orientedRanges.toolMinor = area; + mLocked.orientedRanges.orientation.min = - M_PI_2; + mLocked.orientedRanges.orientation.max = M_PI_2; + mLocked.orientedRanges.orientation.flat = 0; + mLocked.orientedRanges.orientation.fuzz = 0; + } } if (orientationChanged || sizeChanged) { @@ -1322,10 +1504,10 @@ bool TouchInputMapper::configureSurfaceLocked() { } void TouchInputMapper::configureVirtualKeysLocked() { - assert(mAxes.x.valid && mAxes.y.valid); + assert(mRawAxes.x.valid && mRawAxes.y.valid); // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock. - Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions; + Vector<VirtualKeyDefinition> virtualKeyDefinitions; getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions); mLocked.virtualKeys.clear(); @@ -1336,13 +1518,13 @@ void TouchInputMapper::configureVirtualKeysLocked() { mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size()); - int32_t touchScreenLeft = mAxes.x.minValue; - int32_t touchScreenTop = mAxes.y.minValue; - int32_t touchScreenWidth = mAxes.x.getRange(); - int32_t touchScreenHeight = mAxes.y.getRange(); + int32_t touchScreenLeft = mRawAxes.x.minValue; + int32_t touchScreenTop = mRawAxes.y.minValue; + int32_t touchScreenWidth = mRawAxes.x.getRange(); + int32_t touchScreenHeight = mRawAxes.y.getRange(); for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition = + const VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i]; mLocked.virtualKeys.add(); @@ -1353,7 +1535,8 @@ void TouchInputMapper::configureVirtualKeysLocked() { uint32_t flags; if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode, & keyCode, & flags)) { - LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); + LOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", + virtualKey.scanCode); mLocked.virtualKeys.pop(); // drop the key continue; } @@ -1374,12 +1557,316 @@ void TouchInputMapper::configureVirtualKeysLocked() { virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", + LOGI(INDENT "VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d", virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); } } +void TouchInputMapper::parseCalibration() { + const InputDeviceCalibration& in = getDevice()->getCalibration(); + Calibration& out = mCalibration; + + // Touch Area + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_DEFAULT; + String8 touchAreaCalibrationString; + if (in.tryGetProperty(String8("touch.touchArea.calibration"), touchAreaCalibrationString)) { + if (touchAreaCalibrationString == "none") { + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE; + } else if (touchAreaCalibrationString == "geometric") { + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC; + } else if (touchAreaCalibrationString == "pressure") { + out.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE; + } else if (touchAreaCalibrationString != "default") { + LOGW("Invalid value for touch.touchArea.calibration: '%s'", + touchAreaCalibrationString.string()); + } + } + + // Tool Area + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_DEFAULT; + String8 toolAreaCalibrationString; + if (in.tryGetProperty(String8("tool.toolArea.calibration"), toolAreaCalibrationString)) { + if (toolAreaCalibrationString == "none") { + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE; + } else if (toolAreaCalibrationString == "geometric") { + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC; + } else if (toolAreaCalibrationString == "linear") { + out.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR; + } else if (toolAreaCalibrationString != "default") { + LOGW("Invalid value for tool.toolArea.calibration: '%s'", + toolAreaCalibrationString.string()); + } + } + + out.haveToolAreaLinearScale = in.tryGetProperty(String8("touch.toolArea.linearScale"), + out.toolAreaLinearScale); + out.haveToolAreaLinearBias = in.tryGetProperty(String8("touch.toolArea.linearBias"), + out.toolAreaLinearBias); + out.haveToolAreaIsSummed = in.tryGetProperty(String8("touch.toolArea.isSummed"), + out.toolAreaIsSummed); + + // Pressure + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; + String8 pressureCalibrationString; + if (in.tryGetProperty(String8("tool.pressure.calibration"), pressureCalibrationString)) { + if (pressureCalibrationString == "none") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } else if (pressureCalibrationString == "physical") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; + } else if (pressureCalibrationString == "amplitude") { + out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; + } else if (pressureCalibrationString != "default") { + LOGW("Invalid value for tool.pressure.calibration: '%s'", + pressureCalibrationString.string()); + } + } + + out.pressureSource = Calibration::PRESSURE_SOURCE_DEFAULT; + String8 pressureSourceString; + if (in.tryGetProperty(String8("touch.pressure.source"), pressureSourceString)) { + if (pressureSourceString == "pressure") { + out.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE; + } else if (pressureSourceString == "touch") { + out.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH; + } else if (pressureSourceString != "default") { + LOGW("Invalid value for touch.pressure.source: '%s'", + pressureSourceString.string()); + } + } + + out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), + out.pressureScale); + + // Size + out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; + String8 sizeCalibrationString; + if (in.tryGetProperty(String8("tool.size.calibration"), sizeCalibrationString)) { + if (sizeCalibrationString == "none") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } else if (sizeCalibrationString == "normalized") { + out.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED; + } else if (sizeCalibrationString != "default") { + LOGW("Invalid value for tool.size.calibration: '%s'", + sizeCalibrationString.string()); + } + } + + // Orientation + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; + String8 orientationCalibrationString; + if (in.tryGetProperty(String8("tool.orientation.calibration"), orientationCalibrationString)) { + if (orientationCalibrationString == "none") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } else if (orientationCalibrationString == "interpolated") { + out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } else if (orientationCalibrationString != "default") { + LOGW("Invalid value for tool.orientation.calibration: '%s'", + orientationCalibrationString.string()); + } + } +} + +void TouchInputMapper::resolveCalibration() { + // Pressure + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_DEFAULT: + if (mRawAxes.pressure.valid) { + mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_PRESSURE; + } else if (mRawAxes.touchMajor.valid) { + mCalibration.pressureSource = Calibration::PRESSURE_SOURCE_TOUCH; + } + break; + + case Calibration::PRESSURE_SOURCE_PRESSURE: + if (! mRawAxes.pressure.valid) { + LOGW("Calibration property touch.pressure.source is 'pressure' but " + "the pressure axis is not available."); + } + break; + + case Calibration::PRESSURE_SOURCE_TOUCH: + if (! mRawAxes.touchMajor.valid) { + LOGW("Calibration property touch.pressure.source is 'touch' but " + "the touchMajor axis is not available."); + } + break; + + default: + break; + } + + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_DEFAULT: + if (mCalibration.pressureSource != Calibration::PRESSURE_SOURCE_DEFAULT) { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; + } else { + mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Tool Area + switch (mCalibration.toolAreaCalibration) { + case Calibration::TOOL_AREA_CALIBRATION_DEFAULT: + if (mRawAxes.toolMajor.valid) { + mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_LINEAR; + } else { + mCalibration.toolAreaCalibration = Calibration::TOOL_AREA_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Touch Area + switch (mCalibration.touchAreaCalibration) { + case Calibration::TOUCH_AREA_CALIBRATION_DEFAULT: + if (mCalibration.pressureCalibration != Calibration::PRESSURE_CALIBRATION_NONE + && mCalibration.toolAreaCalibration != Calibration::TOOL_AREA_CALIBRATION_NONE) { + mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_PRESSURE; + } else { + mCalibration.touchAreaCalibration = Calibration::TOUCH_AREA_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Size + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_DEFAULT: + if (mRawAxes.toolMajor.valid) { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NORMALIZED; + } else { + mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; + } + break; + + default: + break; + } + + // Orientation + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_DEFAULT: + if (mRawAxes.orientation.valid) { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; + } else { + mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; + } + break; + + default: + break; + } +} + +void TouchInputMapper::logCalibration() { + // Touch Area + switch (mCalibration.touchAreaCalibration) { + case Calibration::TOUCH_AREA_CALIBRATION_NONE: + LOGI(INDENT " touch.touchArea.calibration: none"); + break; + case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC: + LOGI(INDENT " touch.touchArea.calibration: geometric"); + break; + case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE: + LOGI(INDENT " touch.touchArea.calibration: pressure"); + break; + default: + assert(false); + } + + // Tool Area + switch (mCalibration.toolAreaCalibration) { + case Calibration::TOOL_AREA_CALIBRATION_NONE: + LOGI(INDENT " touch.toolArea.calibration: none"); + break; + case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC: + LOGI(INDENT " touch.toolArea.calibration: geometric"); + break; + case Calibration::TOOL_AREA_CALIBRATION_LINEAR: + LOGI(INDENT " touch.toolArea.calibration: linear"); + break; + default: + assert(false); + } + + if (mCalibration.haveToolAreaLinearScale) { + LOGI(INDENT " touch.toolArea.linearScale: %f", mCalibration.toolAreaLinearScale); + } + + if (mCalibration.haveToolAreaLinearBias) { + LOGI(INDENT " touch.toolArea.linearBias: %f", mCalibration.toolAreaLinearBias); + } + + if (mCalibration.haveToolAreaIsSummed) { + LOGI(INDENT " touch.toolArea.isSummed: %d", mCalibration.toolAreaIsSummed); + } + + // Pressure + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_NONE: + LOGI(INDENT " touch.pressure.calibration: none"); + break; + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + LOGI(INDENT " touch.pressure.calibration: physical"); + break; + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + LOGI(INDENT " touch.pressure.calibration: amplitude"); + break; + default: + assert(false); + } + + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + LOGI(INDENT " touch.pressure.source: pressure"); + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + LOGI(INDENT " touch.pressure.source: touch"); + break; + case Calibration::PRESSURE_SOURCE_DEFAULT: + break; + default: + assert(false); + } + + if (mCalibration.havePressureScale) { + LOGI(INDENT " touch.pressure.scale: %f", mCalibration.pressureScale); + } + + // Size + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NONE: + LOGI(INDENT " touch.size.calibration: none"); + break; + case Calibration::SIZE_CALIBRATION_NORMALIZED: + LOGI(INDENT " touch.size.calibration: normalized"); + break; + default: + assert(false); + } + + // Orientation + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_NONE: + LOGI(INDENT " touch.orientation.calibration: none"); + break; + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + LOGI(INDENT " touch.orientation.calibration: interpolated"); + break; + default: + assert(false); + } +} + void TouchInputMapper::reset() { // Synthesize touch up event if touch is currently down. // This will also take care of finishing virtual key processing if needed. @@ -1584,13 +2071,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // The dispatcher takes care of batching moves so we don't have to deal with that here. int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE; dispatchTouch(when, policyFlags, & mCurrentTouch, - currentIdBits, -1, motionEventAction); + currentIdBits, -1, currentPointerCount, motionEventAction); } else { // There may be pointers going up and pointers going down at the same time when pointer // ids are reported by the device driver. BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); BitSet32 activeIdBits(lastIdBits.value); + uint32_t pointerCount = lastPointerCount; while (! upIdBits.isEmpty()) { uint32_t upId = upIdBits.firstMarkedBit(); @@ -1606,7 +2094,8 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { } dispatchTouch(when, policyFlags, & mLastTouch, - oldActiveIdBits, upId, motionEventAction); + oldActiveIdBits, upId, pointerCount, motionEventAction); + pointerCount -= 1; } while (! downIdBits.isEmpty()) { @@ -1623,16 +2112,16 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN; } + pointerCount += 1; dispatchTouch(when, policyFlags, & mCurrentTouch, - activeIdBits, downId, motionEventAction); + activeIdBits, downId, pointerCount, motionEventAction); } } } void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, - TouchData* touch, BitSet32 idBits, uint32_t changedId, + TouchData* touch, BitSet32 idBits, uint32_t changedId, uint32_t pointerCount, int32_t motionEventAction) { - uint32_t pointerCount = 0; int32_t pointerIds[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; int32_t motionEventEdgeFlags = 0; @@ -1643,36 +2132,130 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, // Walk through the the active pointers and map touch screen coordinates (TouchData) into // display coordinates (PointerCoords) and adjust for display orientation. - while (! idBits.isEmpty()) { + for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) { uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); - uint32_t index = touch->idToIndex[id]; - - float x = float(touch->pointers[index].x - mLocked.xOrigin) * mLocked.xScale; - float y = float(touch->pointers[index].y - mLocked.yOrigin) * mLocked.yScale; - float pressure = float(touch->pointers[index].pressure - mLocked.pressureOrigin) - * mLocked.pressureScale; - float size = float(touch->pointers[index].size - mLocked.sizeOrigin) - * mLocked.sizeScale; - - float orientation = float(touch->pointers[index].orientation) - * mLocked.orientationScale; - - float touchMajor, touchMinor, toolMajor, toolMinor; - if (abs(orientation) <= M_PI_4) { - // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X. - touchMajor = float(touch->pointers[index].touchMajor) * mLocked.yScale; - touchMinor = float(touch->pointers[index].touchMinor) * mLocked.xScale; - toolMajor = float(touch->pointers[index].toolMajor) * mLocked.yScale; - toolMinor = float(touch->pointers[index].toolMinor) * mLocked.xScale; - } else { - // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y. - touchMajor = float(touch->pointers[index].touchMajor) * mLocked.xScale; - touchMinor = float(touch->pointers[index].touchMinor) * mLocked.yScale; - toolMajor = float(touch->pointers[index].toolMajor) * mLocked.xScale; - toolMinor = float(touch->pointers[index].toolMinor) * mLocked.yScale; + uint32_t inIndex = touch->idToIndex[id]; + + const PointerData& in = touch->pointers[inIndex]; + + // X and Y + float x = float(in.x - mLocked.xOrigin) * mLocked.xScale; + float y = float(in.y - mLocked.yOrigin) * mLocked.yScale; + + // ToolMajor and ToolMinor + float toolMajor, toolMinor; + switch (mCalibration.toolAreaCalibration) { + case Calibration::TOOL_AREA_CALIBRATION_GEOMETRIC: + toolMajor = in.toolMajor * mLocked.geometricScale; + if (mRawAxes.toolMinor.valid) { + toolMinor = in.toolMinor * mLocked.geometricScale; + } else { + toolMinor = toolMajor; + } + break; + case Calibration::TOOL_AREA_CALIBRATION_LINEAR: + toolMajor = in.toolMajor != 0 + ? in.toolMajor * mLocked.toolAreaLinearScale + mLocked.toolAreaLinearBias + : 0; + if (mRawAxes.toolMinor.valid) { + toolMinor = in.toolMinor != 0 + ? in.toolMinor * mLocked.toolAreaLinearScale + + mLocked.toolAreaLinearBias + : 0; + } else { + toolMinor = toolMajor; + } + break; + default: + toolMajor = 0; + toolMinor = 0; + break; + } + + if (mCalibration.haveToolAreaIsSummed && mCalibration.toolAreaIsSummed) { + toolMajor /= pointerCount; + toolMinor /= pointerCount; + } + + // Pressure + float rawPressure; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + rawPressure = in.pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + rawPressure = in.touchMajor; + break; + default: + rawPressure = 0; + } + + float pressure; + switch (mCalibration.pressureCalibration) { + case Calibration::PRESSURE_CALIBRATION_PHYSICAL: + case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: + pressure = rawPressure * mLocked.pressureScale; + break; + default: + pressure = 1; + break; + } + + // TouchMajor and TouchMinor + float touchMajor, touchMinor; + switch (mCalibration.touchAreaCalibration) { + case Calibration::TOUCH_AREA_CALIBRATION_GEOMETRIC: + touchMajor = in.touchMajor * mLocked.geometricScale; + if (mRawAxes.touchMinor.valid) { + touchMinor = in.touchMinor * mLocked.geometricScale; + } else { + touchMinor = touchMajor; + } + break; + case Calibration::TOUCH_AREA_CALIBRATION_PRESSURE: + touchMajor = toolMajor * pressure; + touchMinor = toolMinor * pressure; + break; + default: + touchMajor = 0; + touchMinor = 0; + break; + } + + if (touchMajor > toolMajor) { + touchMajor = toolMajor; + } + if (touchMinor > toolMinor) { + touchMinor = toolMinor; + } + + // Size + float size; + switch (mCalibration.sizeCalibration) { + case Calibration::SIZE_CALIBRATION_NORMALIZED: { + float rawSize = mRawAxes.toolMinor.valid + ? avg(in.toolMajor, in.toolMinor) + : in.toolMajor; + size = rawSize * mLocked.sizeScale; + break; + } + default: + size = 0; + break; } + // Orientation + float orientation; + switch (mCalibration.orientationCalibration) { + case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: + orientation = in.orientation * mLocked.orientationScale; + break; + default: + orientation = 0; + } + + // Adjust coords for orientation. switch (mLocked.surfaceOrientation) { case InputReaderPolicyInterface::ROTATION_90: { float xTemp = x; @@ -1702,23 +2285,23 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, } } - pointerIds[pointerCount] = int32_t(id); + // Write output coords. + PointerCoords& out = pointerCoords[outIndex]; + out.x = x; + out.y = y; + out.pressure = pressure; + out.size = size; + out.touchMajor = touchMajor; + out.touchMinor = touchMinor; + out.toolMajor = toolMajor; + out.toolMinor = toolMinor; + out.orientation = orientation; - pointerCoords[pointerCount].x = x; - pointerCoords[pointerCount].y = y; - pointerCoords[pointerCount].pressure = pressure; - pointerCoords[pointerCount].size = size; - pointerCoords[pointerCount].touchMajor = touchMajor; - pointerCoords[pointerCount].touchMinor = touchMinor; - pointerCoords[pointerCount].toolMajor = toolMajor; - pointerCoords[pointerCount].toolMinor = toolMinor; - pointerCoords[pointerCount].orientation = orientation; + pointerIds[outIndex] = int32_t(id); if (id == changedId) { - motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + motionEventAction |= outIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } - - pointerCount += 1; } // Check edge flags by looking only at the first pointer since the flags are @@ -1747,9 +2330,9 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, } bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { - if (mAxes.x.valid && mAxes.y.valid) { - return x >= mAxes.x.minValue && x <= mAxes.x.maxValue - && y >= mAxes.y.minValue && y <= mAxes.y.maxValue; + if (mRawAxes.x.valid && mRawAxes.y.valid) { + return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue + && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue; } return true; } @@ -1960,7 +2543,7 @@ void TouchInputMapper::calculatePointerIds() { * then drop it. */ bool TouchInputMapper::applyBadTouchFilter() { // This hack requires valid axis parameters. - if (! mAxes.y.valid) { + if (! mRawAxes.y.valid) { return false; } @@ -1982,7 +2565,7 @@ bool TouchInputMapper::applyBadTouchFilter() { // the long size of the screen to be bad. This was a magic value // determined by looking at the maximum distance it is feasible // to actually move in one sample. - int32_t maxDeltaY = mAxes.y.getRange() * 7 / 16; + int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16; // XXX The original code in InputDevice.java included commented out // code for testing the X axis. Note that when we drop a point @@ -2044,7 +2627,7 @@ bool TouchInputMapper::applyBadTouchFilter() { */ bool TouchInputMapper::applyJumpyTouchFilter() { // This hack requires valid axis parameters. - if (! mAxes.y.valid) { + if (! mRawAxes.y.valid) { return false; } @@ -2104,7 +2687,7 @@ bool TouchInputMapper::applyJumpyTouchFilter() { } if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) { - int jumpyEpsilon = mAxes.y.getRange() / JUMPY_EPSILON_DIVISOR; + int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR; // We only replace the single worst jumpy point as characterized by pointer distance // in a single axis. @@ -2209,7 +2792,18 @@ void TouchInputMapper::applyAveragingTouchFilter() { uint32_t id = mCurrentTouch.pointers[currentIndex].id; int32_t x = mCurrentTouch.pointers[currentIndex].x; int32_t y = mCurrentTouch.pointers[currentIndex].y; - int32_t pressure = mCurrentTouch.pointers[currentIndex].pressure; + int32_t pressure; + switch (mCalibration.pressureSource) { + case Calibration::PRESSURE_SOURCE_PRESSURE: + pressure = mCurrentTouch.pointers[currentIndex].pressure; + break; + case Calibration::PRESSURE_SOURCE_TOUCH: + pressure = mCurrentTouch.pointers[currentIndex].touchMajor; + break; + default: + pressure = 1; + break; + } if (mLastTouch.idBits.hasBit(id)) { // Pointer was down before and is still down now. @@ -2274,17 +2868,19 @@ void TouchInputMapper::applyAveragingTouchFilter() { } } - averagedX /= totalPressure; - averagedY /= totalPressure; + if (totalPressure != 0) { + averagedX /= totalPressure; + averagedY /= totalPressure; #if DEBUG_HACKS - LOGD("AveragingTouchFilter: Pointer id %d - " - "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, - averagedX, averagedY); + LOGD("AveragingTouchFilter: Pointer id %d - " + "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure, + averagedX, averagedY); #endif - mCurrentTouch.pointers[currentIndex].x = averagedX; - mCurrentTouch.pointers[currentIndex].y = averagedY; + mCurrentTouch.pointers[currentIndex].x = averagedX; + mCurrentTouch.pointers[currentIndex].y = averagedY; + } } else { #if DEBUG_HACKS LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id); @@ -2382,8 +2978,8 @@ void SingleTouchInputMapper::initialize() { mDown = false; mX = 0; mY = 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 + mPressure = 0; // default to 0 for devices that don't report pressure + mToolWidth = 0; // default to 0 for devices that don't report tool width } void SingleTouchInputMapper::reset() { @@ -2460,7 +3056,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) { } if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) { - mSize = mAccumulator.absToolWidth; + mToolWidth = mAccumulator.absToolWidth; } mCurrentTouch.clear(); @@ -2471,11 +3067,10 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointers[0].x = mX; mCurrentTouch.pointers[0].y = mY; mCurrentTouch.pointers[0].pressure = mPressure; - mCurrentTouch.pointers[0].size = mSize; - mCurrentTouch.pointers[0].touchMajor = mSize; - mCurrentTouch.pointers[0].touchMinor = mSize; - mCurrentTouch.pointers[0].toolMajor = mSize; - mCurrentTouch.pointers[0].toolMinor = mSize; + mCurrentTouch.pointers[0].touchMajor = 0; + mCurrentTouch.pointers[0].touchMinor = 0; + mCurrentTouch.pointers[0].toolMajor = mToolWidth; + mCurrentTouch.pointers[0].toolMinor = mToolWidth; mCurrentTouch.pointers[0].orientation = 0; mCurrentTouch.idToIndex[0] = 0; mCurrentTouch.idBits.markBit(0); @@ -2486,20 +3081,13 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mAccumulator.clear(); } -void SingleTouchInputMapper::configureAxes() { - TouchInputMapper::configureAxes(); - - // The axes are aliased to take into account the manner in which they are presented - // as part of the TouchData during the sync. - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size); +void SingleTouchInputMapper::configureRawAxes() { + TouchInputMapper::configureRawAxes(); - mAxes.touchMajor = mAxes.size; - mAxes.touchMinor = mAxes.size; - mAxes.toolMajor = mAxes.size; - mAxes.toolMinor = mAxes.size; + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mRawAxes.x); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mRawAxes.y); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mRawAxes.pressure); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mRawAxes.toolMajor); } @@ -2562,6 +3150,10 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID; pointer->absMTTrackingId = rawEvent->value; break; + case ABS_MT_PRESSURE: + pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE; + pointer->absMTPressure = rawEvent->value; + break; } break; } @@ -2596,8 +3188,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { 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_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y; uint32_t inCount = mAccumulator.pointerCount; uint32_t outCount = 0; @@ -2619,60 +3210,59 @@ void MultiTouchInputMapper::sync(nsecs_t when) { outPointer.x = inPointer.absMTPositionX; outPointer.y = inPointer.absMTPositionY; + if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { + if (inPointer.absMTPressure <= 0) { + // Some devices send sync packets with X / Y but with a 0 presure to indicate + // a pointer up. Drop this finger. + continue; + } + outPointer.pressure = inPointer.absMTPressure; + } else { + // Default pressure to 0 if absent. + outPointer.pressure = 0; + } + if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) { - int32_t value = inPointer.absMTTouchMajor; - if (value <= 0) { + if (inPointer.absMTTouchMajor <= 0) { // Some devices send sync packets with X / Y but with a 0 touch major to indicate - // a pointer up. Drop this finger. + // a pointer going up. Drop this finger. continue; } outPointer.touchMajor = inPointer.absMTTouchMajor; } else { + // Default touch area to 0 if absent. outPointer.touchMajor = 0; } if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) { outPointer.touchMinor = inPointer.absMTTouchMinor; } else { + // Assume touch area is circular. outPointer.touchMinor = outPointer.touchMajor; } if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) { outPointer.toolMajor = inPointer.absMTWidthMajor; } else { - outPointer.toolMajor = outPointer.touchMajor; + // Default tool area to 0 if absent. + outPointer.toolMajor = 0; } if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) { outPointer.toolMinor = inPointer.absMTWidthMinor; } else { + // Assume tool area is circular. outPointer.toolMinor = outPointer.toolMajor; } if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) { outPointer.orientation = inPointer.absMTOrientation; } else { + // Default orientation to vertical if absent. 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; - + // 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); @@ -2705,33 +3295,17 @@ void MultiTouchInputMapper::sync(nsecs_t when) { mAccumulator.clear(); } -void MultiTouchInputMapper::configureAxes() { - TouchInputMapper::configureAxes(); - - // The axes are aliased to take into account the manner in which they are presented - // as part of the TouchData during the sync. - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mAxes.touchMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mAxes.touchMinor); - 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; - } - - if (! mAxes.toolMinor.valid) { - mAxes.toolMinor = mAxes.toolMajor; - } - - if (! mAxes.pressure.valid) { - mAxes.pressure = mAxes.touchMajor; - } +void MultiTouchInputMapper::configureRawAxes() { + TouchInputMapper::configureRawAxes(); - mAxes.size = mAxes.toolMajor; + 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); } |