/*
* Maximum number of pointers supported per motion event.
* Smallest number of pointers is 1.
+ * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
+ * will occasionally emit 11. There is not much harm making this constant bigger.)
*/
-#define MAX_POINTERS 10
+#define MAX_POINTERS 16
/*
* Maximum pointer id value supported in a motion event.
// Is this a new modern multi-touch driver?
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;
+ device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
// Is this an old style single-touch driver?
} else if (test_bit(BTN_TOUCH, key_bitmask)
&& test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
- device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
+ device->classes |= INPUT_DEVICE_CLASS_TOUCH;
}
}
}
#endif
- if ((device->classes & INPUT_DEVICE_CLASS_TOUCHSCREEN)) {
+ if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
status_t status = loadVirtualKeyMap(device);
/* The input device is an alpha-numeric keyboard (not just a dial pad). */
INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,
- /* The input device is a touchscreen (either single-touch or multi-touch). */
- INPUT_DEVICE_CLASS_TOUCHSCREEN = 0x00000004,
+ /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
+ INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
/* The input device is a cursor device such as a trackball or mouse. */
INPUT_DEVICE_CLASS_CURSOR = 0x00000008,
/* The input device is a multi-touch touchscreen. */
- INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
+ INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,
/* The input device is a directional pad (implies keyboard, has DPAD keys). */
INPUT_DEVICE_CLASS_DPAD = 0x00000020,
mTempTouchState.reset();
mTempTouchState.down = true;
mTempTouchState.deviceId = entry->deviceId;
+ mTempTouchState.source = entry->source;
isSplit = false;
wrongDevice = false;
} else {
mTempTouchState.copyFrom(mTouchState);
isSplit = mTempTouchState.split;
- wrongDevice = mTempTouchState.down && mTempTouchState.deviceId != entry->deviceId;
+ wrongDevice = mTempTouchState.down
+ && (mTempTouchState.deviceId != entry->deviceId
+ || mTempTouchState.source != entry->source);
if (wrongDevice) {
#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("Dropping event because a pointer for a different device is already down.");
if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {
MotionEntry* splitMotionEntry = splitMotionEvent(
originalMotionEntry, inputTarget->pointerIds);
+ if (!splitMotionEntry) {
+ return; // split event was dropped
+ }
#if DEBUG_FOCUS
LOGD("channel '%s' ~ Split motion event.",
connection->getInputChannelName());
splitPointerCount += 1;
}
}
- assert(splitPointerCount == pointerIds.count());
+
+ if (splitPointerCount != pointerIds.count()) {
+ // This is bad. We are missing some of the pointers that we expected to deliver.
+ // Most likely this indicates that we received an ACTION_MOVE events that has
+ // different pointer ids than we expected based on the previous ACTION_DOWN
+ // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers
+ // in this way.
+ LOGW("Dropping split motion event because the pointer count is %d but "
+ "we expected there to be %d pointers. This probably means we received "
+ "a broken sequence of pointer ids from the input device.",
+ splitPointerCount, pointerIds.count());
+ return NULL;
+ }
int32_t action = originalMotionEntry->action;
int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
}
}
-void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
+void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
#if DEBUG_INBOUND_EVENT_DETAILS
}
}
-void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
+void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) {
}
if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
+ || motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
// Last motion event in the queue for this device is not compatible for
dispatchEntry->eventEntry);
if (motionEntry->action != AMOTION_EVENT_ACTION_MOVE
|| motionEntry->deviceId != deviceId
+ || motionEntry->source != source
|| motionEntry->pointerCount != pointerCount
|| motionEntry->isInjected()) {
// The motion event is not compatible with this move.
dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId);
+ dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source);
if (!mTouchState.windows.isEmpty()) {
dump.append(INDENT "TouchedWindows:\n");
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
}
InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t eventTime,
- int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
+ int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
int32_t repeatCount, nsecs_t downTime) {
KeyEntry* entry = mKeyEntryPool.alloc();
}
InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime,
- int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
+ int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags,
int32_t metaState, int32_t edgeFlags, float xPrecision, float yPrecision,
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords) {
// --- InputDispatcher::TouchState ---
InputDispatcher::TouchState::TouchState() :
- down(false), split(false), deviceId(-1) {
+ down(false), split(false), deviceId(-1), source(0) {
}
InputDispatcher::TouchState::~TouchState() {
down = false;
split = false;
deviceId = -1;
+ source = 0;
windows.clear();
}
down = other.down;
split = other.split;
deviceId = other.deviceId;
+ source = other.source;
windows.clear();
windows.appendVector(other.windows);
}
* These methods should only be called on the input reader thread.
*/
virtual void notifyConfigurationChanged(nsecs_t eventTime) = 0;
- virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
+ virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime) = 0;
- virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
+ virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
virtual void dispatchOnce();
virtual void notifyConfigurationChanged(nsecs_t eventTime);
- virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
+ virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime);
- virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
+ virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
struct KeyEntry : EventEntry {
int32_t deviceId;
- int32_t source;
+ uint32_t source;
int32_t action;
int32_t flags;
int32_t keyCode;
struct MotionEntry : EventEntry {
int32_t deviceId;
- int32_t source;
+ uint32_t source;
int32_t action;
int32_t flags;
int32_t metaState;
InjectionState* obtainInjectionState(int32_t injectorPid, int32_t injectorUid);
ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime);
KeyEntry* obtainKeyEntry(nsecs_t eventTime,
- int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
+ int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
int32_t repeatCount, nsecs_t downTime);
MotionEntry* obtainMotionEntry(nsecs_t eventTime,
- int32_t deviceId, int32_t source, uint32_t policyFlags, int32_t action,
+ int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
int32_t flags, int32_t metaState, int32_t edgeFlags,
float xPrecision, float yPrecision,
nsecs_t downTime, uint32_t pointerCount,
private:
struct KeyMemento {
int32_t deviceId;
- int32_t source;
+ uint32_t source;
int32_t keyCode;
int32_t scanCode;
int32_t flags;
struct MotionMemento {
int32_t deviceId;
- int32_t source;
+ uint32_t source;
float xPrecision;
float yPrecision;
nsecs_t downTime;
bool down;
bool split;
int32_t deviceId; // id of the device that is currently down, others are rejected
+ uint32_t source; // source of the device that is current down, others are rejected
Vector<TouchedWindow> windows;
TouchState();
device->addMapper(new CursorInputMapper(device));
}
- // Touchscreen-like devices.
- if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
+ // Touchscreens and touchpad devices.
+ if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
device->addMapper(new MultiTouchInputMapper(device));
- } else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
+ } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
device->addMapper(new SingleTouchInputMapper(device));
}
mParameters.virtualKeyQuietTime = getPolicy()->getVirtualKeyQuietTime();
String8 deviceTypeString;
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
deviceTypeString)) {
- if (deviceTypeString == "touchPad") {
- mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
- } else if (deviceTypeString != "touchScreen") {
+ if (deviceTypeString == "touchScreen") {
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ } else if (deviceTypeString != "touchPad") {
LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
}
}
struct NotifyKeyArgs {
nsecs_t eventTime;
int32_t deviceId;
- int32_t source;
+ uint32_t source;
uint32_t policyFlags;
int32_t action;
int32_t flags;
struct NotifyMotionArgs {
nsecs_t eventTime;
int32_t deviceId;
- int32_t source;
+ uint32_t source;
uint32_t policyFlags;
int32_t action;
int32_t flags;
mNotifyConfigurationChangedArgs.push_back(args);
}
- virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,
+ virtual void notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, nsecs_t downTime) {
NotifyKeyArgs args;
mNotifyKeyArgs.push_back(args);
}
- virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, int32_t source,
+ virtual void notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t source,
uint32_t policyFlags, int32_t action, int32_t flags,
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
}
TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchScreenPresent_ReturnsFingerTouchScreen) {
+ PropertyMap configuration;
+ configuration.addProperty(String8("touch.deviceType"), String8("touchScreen"));
ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("touchscreen"),
- INPUT_DEVICE_CLASS_TOUCHSCREEN, NULL));
+ INPUT_DEVICE_CLASS_TOUCH, &configuration));
InputConfiguration config;
mReader->getInputConfiguration(&config);
ASSERT_EQ(InputConfiguration::TOUCHSCREEN_FINGER, config.touchScreen);
}
+TEST_F(InputReaderTest, GetInputConfiguration_WhenTouchPadPresent_ReturnsFingerNoTouch) {
+ ASSERT_NO_FATAL_FAILURE(addDevice(0, String8("touchpad"),
+ INPUT_DEVICE_CLASS_TOUCH, NULL));
+
+ InputConfiguration config;
+ mReader->getInputConfiguration(&config);
+
+ ASSERT_EQ(InputConfiguration::KEYBOARD_NOKEYS, config.keyboard);
+ ASSERT_EQ(InputConfiguration::NAVIGATION_NONAV, config.navigation);
+ ASSERT_EQ(InputConfiguration::TOUCHSCREEN_NOTOUCH, config.touchScreen);
+}
+
TEST_F(InputReaderTest, GetInputConfiguration_WhenMousePresent_ReturnsNoNavigation) {
sp<FakePointerController> controller = new FakePointerController();
mFakePolicy->setPointerController(0, controller);
}
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecified_ReturnsTouchPad) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
+}
+
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
// Note: Ideally we should send cancels but the implementation is more straightforward
// with up and this will only happen if a device is forcibly removed.
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareAxes(POSITION);
addConfigurationProperty("touch.orientationAware", "0");
addMapperAndConfigure(mapper);
TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | PRESSURE | TOOL);
addMapperAndConfigure(mapper);
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | ID);
prepareVirtualKeys();
TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR);
addMapperAndConfigure(mapper);
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | MINOR);
addConfigurationProperty("touch.touchSize.calibration", "geometric");
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
addConfigurationProperty("touch.touchSize.calibration", "pressure");
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) {
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
addConfigurationProperty("touch.touchSize.calibration", "pressure");