Loading include/ui/InputReader.h +23 −5 Original line number Diff line number Diff line Loading @@ -170,11 +170,10 @@ public: * and parameters maintained by the input reader. */ class InputReaderContext { protected: public: InputReaderContext() { } virtual ~InputReaderContext() { } public: virtual void updateGlobalMetaState() = 0; virtual int32_t getGlobalMetaState() = 0; Loading @@ -193,7 +192,7 @@ public: * the input reader, the input reader never calls into other components while holding * an exclusive internal lock whenever re-entrance can happen. */ class InputReader : public InputReaderInterface, private InputReaderContext { class InputReader : public InputReaderInterface, protected InputReaderContext { public: InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, Loading @@ -219,6 +218,11 @@ public: virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); protected: // These methods are protected virtual so they can be overridden and instrumented // by test cases. virtual InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); private: sp<EventHubInterface> mEventHub; sp<InputReaderPolicyInterface> mPolicy; Loading @@ -244,12 +248,11 @@ private: void addDevice(int32_t deviceId); void removeDevice(int32_t deviceId); InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); void configureExcludedDevices(); void consumeEvent(const RawEvent* rawEvent); void handleConfigurationChanged(); void handleConfigurationChanged(nsecs_t when); // state management for all devices Mutex mStateLock; Loading Loading @@ -546,6 +549,21 @@ protected: int32_t toolMajor; int32_t toolMinor; int32_t orientation; inline bool operator== (const PointerData& other) const { return id == other.id && x == other.x && y == other.y && pressure == other.pressure && touchMajor == other.touchMajor && touchMinor == other.touchMinor && toolMajor == other.toolMajor && toolMinor == other.toolMinor && orientation == other.orientation; } inline bool operator!= (const PointerData& other) const { return !(*this == other); } }; // Raw data for a collection of pointers including a pointer id mapping table. Loading libs/ui/EventHub.cpp +4 −1 Original line number Diff line number Diff line Loading @@ -403,6 +403,7 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_REMOVED; outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); delete device; mNeedToSendFinishedDeviceScan = true; return true; Loading @@ -419,6 +420,7 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_ADDED; outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); mNeedToSendFinishedDeviceScan = true; return true; } Loading @@ -426,6 +428,7 @@ bool EventHub::getEvent(RawEvent* outEvent) if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; outEvent->type = FINISHED_DEVICE_SCAN; outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); return true; } Loading Loading @@ -839,7 +842,7 @@ int EventHub::openDevice(const char *deviceName) { } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) { for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; Loading libs/ui/InputDispatcher.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -124,12 +124,19 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, pointerCount, MAX_POINTERS); return false; } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { if (pointerIds[i] < 0 || pointerIds[i] > MAX_POINTER_ID) { int32_t id = pointerIds[i]; if (id < 0 || id > MAX_POINTER_ID) { LOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", pointerIds[i], MAX_POINTER_ID); id, MAX_POINTER_ID); return false; } if (pointerIdBits.hasBit(id)) { LOGE("Motion event has duplicate pointer id %d", id); return false; } pointerIdBits.markBit(id); } return true; } Loading libs/ui/InputReader.cpp +55 −16 Original line number Diff line number Diff line Loading @@ -266,7 +266,7 @@ void InputReader::process(const RawEvent* rawEvent) { break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChanged(); handleConfigurationChanged(rawEvent->when); break; default: Loading Loading @@ -404,7 +404,7 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) { } // release device registry reader lock } void InputReader::handleConfigurationChanged() { void InputReader::handleConfigurationChanged(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaState(); Loading @@ -412,7 +412,6 @@ void InputReader::handleConfigurationChanged() { updateInputConfiguration(); // Enqueue configuration changed. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mDispatcher->notifyConfigurationChanged(when); } Loading Loading @@ -2189,7 +2188,7 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_UP; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; Loading @@ -2214,13 +2213,22 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_UP; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED; // Check whether the pointer moved inside the display area where we should // start a new stroke. int32_t x = mCurrentTouch.pointers[0].x; int32_t y = mCurrentTouch.pointers[0].y; if (isPointInsideSurfaceLocked(x, y)) { mLastTouch.clear(); touchResult = DISPATCH_TOUCH; } else { touchResult = DROP_STROKE; goto DispatchVirtualKey; } } else { if (mCurrentTouch.pointerCount >= 1 && mLastTouch.pointerCount == 0) { // Pointer just went down. Handle off-screen touches, if needed. Loading @@ -2238,7 +2246,8 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.scanCode = virtualKey->scanCode; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_DOWN; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM Loading Loading @@ -2285,13 +2294,34 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchTouch(when, policyFlags, & mCurrentTouch, 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. // There may be pointers going up and pointers going down and pointers moving // all at the same time. BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); BitSet32 activeIdBits(lastIdBits.value); uint32_t pointerCount = lastPointerCount; // Produce an intermediate representation of the touch data that consists of the // old location of pointers that have just gone up and the new location of pointers that // have just moved but omits the location of pointers that have just gone down. TouchData interimTouch; interimTouch.copyFrom(mLastTouch); BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); bool moveNeeded = false; while (!moveIdBits.isEmpty()) { uint32_t moveId = moveIdBits.firstMarkedBit(); moveIdBits.clearBit(moveId); int32_t oldIndex = mLastTouch.idToIndex[moveId]; int32_t newIndex = mCurrentTouch.idToIndex[moveId]; if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) { interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex]; moveNeeded = true; } } // Dispatch pointer up events using the interim pointer locations. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.firstMarkedBit(); upIdBits.clearBit(upId); Loading @@ -2305,11 +2335,20 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP; } dispatchTouch(when, policyFlags, & mLastTouch, dispatchTouch(when, policyFlags, &interimTouch, oldActiveIdBits, upId, pointerCount, motionEventAction); pointerCount -= 1; } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { dispatchTouch(when, policyFlags, &mCurrentTouch, activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.firstMarkedBit(); downIdBits.clearBit(downId); Loading Loading @@ -3434,8 +3473,8 @@ void MultiTouchInputMapper::sync(nsecs_t when) { 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. // 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; Loading libs/ui/tests/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ ifneq ($(TARGET_SIMULATOR),true) # Build the unit tests. test_src_files := \ InputChannel_test.cpp \ InputReader_test.cpp \ InputDispatcher_test.cpp \ InputPublisherAndConsumer_test.cpp Loading Loading
include/ui/InputReader.h +23 −5 Original line number Diff line number Diff line Loading @@ -170,11 +170,10 @@ public: * and parameters maintained by the input reader. */ class InputReaderContext { protected: public: InputReaderContext() { } virtual ~InputReaderContext() { } public: virtual void updateGlobalMetaState() = 0; virtual int32_t getGlobalMetaState() = 0; Loading @@ -193,7 +192,7 @@ public: * the input reader, the input reader never calls into other components while holding * an exclusive internal lock whenever re-entrance can happen. */ class InputReader : public InputReaderInterface, private InputReaderContext { class InputReader : public InputReaderInterface, protected InputReaderContext { public: InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy, Loading @@ -219,6 +218,11 @@ public: virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); protected: // These methods are protected virtual so they can be overridden and instrumented // by test cases. virtual InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); private: sp<EventHubInterface> mEventHub; sp<InputReaderPolicyInterface> mPolicy; Loading @@ -244,12 +248,11 @@ private: void addDevice(int32_t deviceId); void removeDevice(int32_t deviceId); InputDevice* createDevice(int32_t deviceId, const String8& name, uint32_t classes); void configureExcludedDevices(); void consumeEvent(const RawEvent* rawEvent); void handleConfigurationChanged(); void handleConfigurationChanged(nsecs_t when); // state management for all devices Mutex mStateLock; Loading Loading @@ -546,6 +549,21 @@ protected: int32_t toolMajor; int32_t toolMinor; int32_t orientation; inline bool operator== (const PointerData& other) const { return id == other.id && x == other.x && y == other.y && pressure == other.pressure && touchMajor == other.touchMajor && touchMinor == other.touchMinor && toolMajor == other.toolMajor && toolMinor == other.toolMinor && orientation == other.orientation; } inline bool operator!= (const PointerData& other) const { return !(*this == other); } }; // Raw data for a collection of pointers including a pointer id mapping table. Loading
libs/ui/EventHub.cpp +4 −1 Original line number Diff line number Diff line Loading @@ -403,6 +403,7 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_REMOVED; outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); delete device; mNeedToSendFinishedDeviceScan = true; return true; Loading @@ -419,6 +420,7 @@ bool EventHub::getEvent(RawEvent* outEvent) outEvent->deviceId = device->id; } outEvent->type = DEVICE_ADDED; outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); mNeedToSendFinishedDeviceScan = true; return true; } Loading @@ -426,6 +428,7 @@ bool EventHub::getEvent(RawEvent* outEvent) if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; outEvent->type = FINISHED_DEVICE_SCAN; outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); return true; } Loading Loading @@ -839,7 +842,7 @@ int EventHub::openDevice(const char *deviceName) { } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) { for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; Loading
libs/ui/InputDispatcher.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -124,12 +124,19 @@ static bool validateMotionEvent(int32_t action, size_t pointerCount, pointerCount, MAX_POINTERS); return false; } BitSet32 pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { if (pointerIds[i] < 0 || pointerIds[i] > MAX_POINTER_ID) { int32_t id = pointerIds[i]; if (id < 0 || id > MAX_POINTER_ID) { LOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", pointerIds[i], MAX_POINTER_ID); id, MAX_POINTER_ID); return false; } if (pointerIdBits.hasBit(id)) { LOGE("Motion event has duplicate pointer id %d", id); return false; } pointerIdBits.markBit(id); } return true; } Loading
libs/ui/InputReader.cpp +55 −16 Original line number Diff line number Diff line Loading @@ -266,7 +266,7 @@ void InputReader::process(const RawEvent* rawEvent) { break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChanged(); handleConfigurationChanged(rawEvent->when); break; default: Loading Loading @@ -404,7 +404,7 @@ void InputReader::consumeEvent(const RawEvent* rawEvent) { } // release device registry reader lock } void InputReader::handleConfigurationChanged() { void InputReader::handleConfigurationChanged(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaState(); Loading @@ -412,7 +412,6 @@ void InputReader::handleConfigurationChanged() { updateInputConfiguration(); // Enqueue configuration changed. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); mDispatcher->notifyConfigurationChanged(when); } Loading Loading @@ -2189,7 +2188,7 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_UP; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; Loading @@ -2214,13 +2213,22 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.down = false; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_UP; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED; // Check whether the pointer moved inside the display area where we should // start a new stroke. int32_t x = mCurrentTouch.pointers[0].x; int32_t y = mCurrentTouch.pointers[0].y; if (isPointInsideSurfaceLocked(x, y)) { mLastTouch.clear(); touchResult = DISPATCH_TOUCH; } else { touchResult = DROP_STROKE; goto DispatchVirtualKey; } } else { if (mCurrentTouch.pointerCount >= 1 && mLastTouch.pointerCount == 0) { // Pointer just went down. Handle off-screen touches, if needed. Loading @@ -2238,7 +2246,8 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( mLocked.currentVirtualKey.scanCode = virtualKey->scanCode; #if DEBUG_VIRTUAL_KEYS LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); mLocked.currentVirtualKey.keyCode, mLocked.currentVirtualKey.scanCode); #endif keyEventAction = AKEY_EVENT_ACTION_DOWN; keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM Loading Loading @@ -2285,13 +2294,34 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchTouch(when, policyFlags, & mCurrentTouch, 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. // There may be pointers going up and pointers going down and pointers moving // all at the same time. BitSet32 upIdBits(lastIdBits.value & ~ currentIdBits.value); BitSet32 downIdBits(currentIdBits.value & ~ lastIdBits.value); BitSet32 activeIdBits(lastIdBits.value); uint32_t pointerCount = lastPointerCount; // Produce an intermediate representation of the touch data that consists of the // old location of pointers that have just gone up and the new location of pointers that // have just moved but omits the location of pointers that have just gone down. TouchData interimTouch; interimTouch.copyFrom(mLastTouch); BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); bool moveNeeded = false; while (!moveIdBits.isEmpty()) { uint32_t moveId = moveIdBits.firstMarkedBit(); moveIdBits.clearBit(moveId); int32_t oldIndex = mLastTouch.idToIndex[moveId]; int32_t newIndex = mCurrentTouch.idToIndex[moveId]; if (mLastTouch.pointers[oldIndex] != mCurrentTouch.pointers[newIndex]) { interimTouch.pointers[oldIndex] = mCurrentTouch.pointers[newIndex]; moveNeeded = true; } } // Dispatch pointer up events using the interim pointer locations. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.firstMarkedBit(); upIdBits.clearBit(upId); Loading @@ -2305,11 +2335,20 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP; } dispatchTouch(when, policyFlags, & mLastTouch, dispatchTouch(when, policyFlags, &interimTouch, oldActiveIdBits, upId, pointerCount, motionEventAction); pointerCount -= 1; } // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { dispatchTouch(when, policyFlags, &mCurrentTouch, activeIdBits, -1, pointerCount, AMOTION_EVENT_ACTION_MOVE); } // Dispatch pointer down events using the new pointer locations. while (!downIdBits.isEmpty()) { uint32_t downId = downIdBits.firstMarkedBit(); downIdBits.clearBit(downId); Loading Loading @@ -3434,8 +3473,8 @@ void MultiTouchInputMapper::sync(nsecs_t when) { 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. // 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; Loading
libs/ui/tests/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ ifneq ($(TARGET_SIMULATOR),true) # Build the unit tests. test_src_files := \ InputChannel_test.cpp \ InputReader_test.cpp \ InputDispatcher_test.cpp \ InputPublisherAndConsumer_test.cpp Loading