diff options
author | 2020-07-21 12:09:04 +0000 | |
---|---|---|
committer | 2020-07-21 12:09:04 +0000 | |
commit | dc07032296a6cd8525b5c7c1648ed7aed6f7769c (patch) | |
tree | e07eed6a54cd5f016ce2c428d2d180c4097a0759 | |
parent | 5896c6247111f2f0984f76e614bc53315c9a3825 (diff) | |
parent | cc7f98045f3b64af894c9454ca536e7e9d19c18c (diff) |
Merge "Allow touch if some pointers are MT_TOOL_PALM"
-rw-r--r-- | include/input/Input.h | 7 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp | 21 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/MultiTouchInputMapper.h | 2 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/TouchInputMapper.cpp | 22 | ||||
-rw-r--r-- | services/inputflinger/reader/mapper/TouchInputMapper.h | 5 | ||||
-rw-r--r-- | services/inputflinger/tests/InputReader_test.cpp | 305 | ||||
-rw-r--r-- | services/inputflinger/tests/UinputDevice.cpp | 5 | ||||
-rw-r--r-- | services/inputflinger/tests/UinputDevice.h | 1 |
8 files changed, 299 insertions, 69 deletions
diff --git a/include/input/Input.h b/include/input/Input.h index 40d655fb43..9525bcbef4 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -87,6 +87,13 @@ constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED; constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; +/** + * This flag indicates that the point up event has been canceled. + * Typically this is used for palm event when the user has accidental touches. + * TODO: Adjust flag to public api + */ +constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20; + enum { /* Used when a motion event is not associated with any display. * Typically used for non-pointer events. */ diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index 43bd9f1f99..0440f49f02 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -236,6 +236,20 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { mMultiTouchMotionAccumulator.process(rawEvent); } +std::optional<int32_t> MultiTouchInputMapper::getActiveBitId( + const MultiTouchMotionAccumulator::Slot& inSlot) { + if (mHavePointerIds) { + int32_t trackingId = inSlot.getTrackingId(); + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { + int32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + return std::make_optional(n); + } + } + } + return std::nullopt; +} + void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; @@ -250,10 +264,9 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { } if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { - if (!mCurrentMotionAborted) { - ALOGI("Canceling touch gesture from device %s because the palm event was detected", - getDeviceName().c_str()); - cancelTouch(when); + std::optional<int32_t> id = getActiveBitId(*inSlot); + if (id) { + outState->rawPointerData.canceledIdBits.markBit(id.value()); } continue; } diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index 190282f428..ea6f2078d7 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -103,6 +103,8 @@ protected: bool hasStylus() const override; private: + // If the slot is in use, return the bit id. Return std::nullopt otherwise. + std::optional<int32_t> getActiveBitId(const MultiTouchMotionAccumulator::Slot& inSlot); MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; // Specifies the pointer id bits that are in use, and their associated tracking id. diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 4274ca8b0f..15d528896f 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -104,6 +104,7 @@ void RawPointerData::copyFrom(const RawPointerData& other) { pointerCount = other.pointerCount; hoveringIdBits = other.hoveringIdBits; touchingIdBits = other.touchingIdBits; + canceledIdBits = other.canceledIdBits; for (uint32_t i = 0; i < pointerCount; i++) { pointers[i] = other.pointers[i]; @@ -140,6 +141,7 @@ void CookedPointerData::clear() { pointerCount = 0; hoveringIdBits.clear(); touchingIdBits.clear(); + canceledIdBits.clear(); } void CookedPointerData::copyFrom(const CookedPointerData& other) { @@ -1444,10 +1446,11 @@ void TouchInputMapper::sync(nsecs_t when) { #if DEBUG_RAW_EVENTS ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", + "hovering ids 0x%08x -> 0x%08x, canceled ids 0x%08x", last->rawPointerData.pointerCount, next->rawPointerData.pointerCount, last->rawPointerData.touchingIdBits.value, next->rawPointerData.touchingIdBits.value, - last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value); + last->rawPointerData.hoveringIdBits.value, next->rawPointerData.hoveringIdBits.value, + next->rawPointerData.canceledIdBits.value); #endif processRawTouches(false /*timeout*/); @@ -1892,14 +1895,15 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Dispatch pointer up events. while (!upIdBits.isEmpty()) { uint32_t upId = upIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0, - metaState, buttonState, 0, + bool isCanceled = mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId); + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, + isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0, mLastCookedState.cookedPointerData.pointerProperties, mLastCookedState.cookedPointerData.pointerCoords, mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); + mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId); } // Dispatch move events if any of the remaining pointers moved from their old locations. @@ -2025,6 +2029,8 @@ void TouchInputMapper::cookPointerData() { mCurrentRawState.rawPointerData.hoveringIdBits; mCurrentCookedState.cookedPointerData.touchingIdBits = mCurrentRawState.rawPointerData.touchingIdBits; + mCurrentCookedState.cookedPointerData.canceledIdBits = + mCurrentRawState.rawPointerData.canceledIdBits; if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { mCurrentCookedState.buttonState = 0; @@ -3563,7 +3569,11 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { action = AMOTION_EVENT_ACTION_DOWN; } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { - action = AMOTION_EVENT_ACTION_UP; + if ((flags & AMOTION_EVENT_FLAG_CANCELED) != 0) { + action = AMOTION_EVENT_ACTION_CANCEL; + } else { + action = AMOTION_EVENT_ACTION_UP; + } } else { // Can't happen. ALOG_ASSERT(false); diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index d437e0124f..94486a67b0 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -71,7 +71,7 @@ struct RawPointerData { uint32_t pointerCount; Pointer pointers[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; + BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits; uint32_t idToIndex[MAX_POINTER_ID + 1]; RawPointerData(); @@ -90,6 +90,7 @@ struct RawPointerData { inline void clearIdBits() { hoveringIdBits.clear(); touchingIdBits.clear(); + canceledIdBits.clear(); } inline const Pointer& pointerForId(uint32_t id) const { return pointers[idToIndex[id]]; } @@ -102,7 +103,7 @@ struct CookedPointerData { uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; + BitSet32 hoveringIdBits, touchingIdBits, canceledIdBits; uint32_t idToIndex[MAX_POINTER_ID + 1]; CookedPointerData(); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index fae7e64c5e..b2c16d05c9 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -45,16 +45,24 @@ static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms; static const nsecs_t ARBITRARY_TIME = 1234; // Arbitrary display properties. -static const int32_t DISPLAY_ID = 0; -static const int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1; -static const int32_t DISPLAY_WIDTH = 480; -static const int32_t DISPLAY_HEIGHT = 800; -static const int32_t VIRTUAL_DISPLAY_ID = 1; -static const int32_t VIRTUAL_DISPLAY_WIDTH = 400; -static const int32_t VIRTUAL_DISPLAY_HEIGHT = 500; +static constexpr int32_t DISPLAY_ID = 0; +static constexpr int32_t SECONDARY_DISPLAY_ID = DISPLAY_ID + 1; +static constexpr int32_t DISPLAY_WIDTH = 480; +static constexpr int32_t DISPLAY_HEIGHT = 800; +static constexpr int32_t VIRTUAL_DISPLAY_ID = 1; +static constexpr int32_t VIRTUAL_DISPLAY_WIDTH = 400; +static constexpr int32_t VIRTUAL_DISPLAY_HEIGHT = 500; static const char* VIRTUAL_DISPLAY_UNIQUE_ID = "virtual:1"; static constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified +static constexpr int32_t FIRST_SLOT = 0; +static constexpr int32_t SECOND_SLOT = 1; +static constexpr int32_t THIRD_SLOT = 2; +static constexpr int32_t INVALID_TRACKING_ID = -1; +static constexpr int32_t FIRST_TRACKING_ID = 0; +static constexpr int32_t SECOND_TRACKING_ID = 1; +static constexpr int32_t THIRD_TRACKING_ID = 2; + // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; @@ -1880,10 +1888,6 @@ TEST_F(InputReaderIntegrationTest, SendsGearDownAndUpToInputListener) { // --- TouchProcessTest --- class TouchIntegrationTest : public InputReaderIntegrationTest { protected: - static const int32_t FIRST_SLOT = 0; - static const int32_t SECOND_SLOT = 1; - static const int32_t FIRST_TRACKING_ID = 0; - static const int32_t SECOND_TRACKING_ID = 1; const std::string UNIQUE_ID = "local:0"; virtual void SetUp() override { @@ -1954,9 +1958,9 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // ACTION_POINTER_UP (Second slot) - mDevice->sendUp(); + mDevice->sendPointerUp(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), args.action); // ACTION_UP @@ -1971,11 +1975,13 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { const Point centerPoint = mDevice->getCenterPoint(); // ACTION_DOWN + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - // ACTION_POINTER_DOWN (Second slot) + // ACTION_POINTER_DOWN (second slot) const Point secondPoint = centerPoint + Point(100, 100); mDevice->sendSlot(SECOND_SLOT); mDevice->sendTrackingId(SECOND_TRACKING_ID); @@ -1984,26 +1990,31 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), args.action); - // ACTION_MOVE (Second slot) + // ACTION_MOVE (second slot) mDevice->sendMove(secondPoint + Point(1, 1)); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event. - // Expect to receive ACTION_CANCEL, to abort the entire gesture. + // Send MT_TOOL_PALM (second slot), which indicates that the touch IC has determined this to be + // a palm event. + // Expect to receive the ACTION_POINTER_UP with cancel flag. mDevice->sendToolType(MT_TOOL_PALM); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + args.action); + ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags); - // ACTION_POINTER_UP (Second slot) - mDevice->sendUp(); + // Send up to second slot, expect first slot send moving. + mDevice->sendPointerUp(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - // ACTION_UP + // Send ACTION_UP (first slot) mDevice->sendSlot(FIRST_SLOT); mDevice->sendUp(); - // Expect no event received after abort the entire gesture. - ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } // --- InputDeviceTest --- @@ -7064,10 +7075,10 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { } /** - * Test touch should be canceled when received the MT_TOOL_PALM event, and the following MOVE and - * UP events should be ignored. + * Test single touch should be canceled when received the MT_TOOL_PALM event, and the following + * MOVE and UP events should be ignored. */ -TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) { +TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); @@ -7077,7 +7088,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) { // default tool type is finger constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240; - processId(mapper, 1); + processId(mapper, FIRST_TRACKING_ID); processPosition(mapper, x1, y1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -7091,19 +7102,19 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) { ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action); // Ignore the following MOVE and UP events if had detect a palm event. - processId(mapper, 1); + processId(mapper, FIRST_TRACKING_ID); processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); // finger up. - processId(mapper, -1); + processId(mapper, INVALID_TRACKING_ID); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); // new finger down + processId(mapper, FIRST_TRACKING_ID); processToolType(mapper, MT_TOOL_FINGER); - processId(mapper, 1); processPosition(mapper, x3, y3); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -7112,11 +7123,10 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType) { } /** - * Test multi-touch should be canceled when received the MT_TOOL_PALM event from some finger, - * and could be allowed again after all non-MT_TOOL_PALM is release and the new point is - * MT_TOOL_FINGER. + * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger, + * and the rest active fingers could still be allowed to receive the events */ -TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) { +TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); @@ -7125,8 +7135,85 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) { NotifyMotionArgs motionArgs; // default tool type is finger + constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220; + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // Second finger down. + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + + // If the tool type of the first finger changes to MT_TOOL_PALM, + // we expect to receive ACTION_POINTER_UP with cancel flag. + processSlot(mapper, FIRST_SLOT); + processId(mapper, FIRST_TRACKING_ID); + processToolType(mapper, MT_TOOL_PALM); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); + + // The following MOVE events of second finger should be processed. + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2 + 1, y2 + 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // First finger up. It used to be in palm mode, and we already generated ACTION_POINTER_UP for + // it. Second finger receive move. + processSlot(mapper, FIRST_SLOT); + processId(mapper, INVALID_TRACKING_ID); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // Second finger keeps moving. + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2 + 2, y2 + 2); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // Second finger up. + processId(mapper, INVALID_TRACKING_ID); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); +} + +/** + * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event, if only 1 finger + * is active, it should send CANCEL after receiving the MT_TOOL_PALM event. + */ +TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelWhenAllTouchIsPalm) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(DISPLAY_ORIENTATION_0); + prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + NotifyMotionArgs motionArgs; + constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220, x3 = 140, y3 = 240; - processId(mapper, 1); + // First finger down. + processId(mapper, FIRST_TRACKING_ID); processPosition(mapper, x1, y1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -7134,51 +7221,155 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType2) { ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // Second finger down. - processSlot(mapper, 1); + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); processPosition(mapper, x2, y2); - processId(mapper, 2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); - // If the tool type of the first pointer changes to MT_TOOL_PALM, - // the entire gesture should be aborted, so we expect to receive ACTION_CANCEL. - processSlot(mapper, 0); - processId(mapper, 1); + // If the tool type of the first finger changes to MT_TOOL_PALM, + // we expect to receive ACTION_POINTER_UP with cancel flag. + processSlot(mapper, FIRST_SLOT); + processId(mapper, FIRST_TRACKING_ID); + processToolType(mapper, MT_TOOL_PALM); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); + + // Second finger keeps moving. + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2 + 1, y2 + 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + + // second finger becomes palm, receive cancel due to only 1 finger is active. + processId(mapper, SECOND_TRACKING_ID); processToolType(mapper, MT_TOOL_PALM); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action); - // Ignore the following MOVE and UP events if had detect a palm event. - processSlot(mapper, 1); - processId(mapper, 2); + // third finger down. + processSlot(mapper, THIRD_SLOT); + processId(mapper, THIRD_TRACKING_ID); + processToolType(mapper, MT_TOOL_FINGER); processPosition(mapper, x3, y3); processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); - // second finger up. - processId(mapper, -1); + // third finger move + processId(mapper, THIRD_TRACKING_ID); + processPosition(mapper, x3 + 1, y3 + 1); processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - // first finger move, but still in palm - processSlot(mapper, 0); - processId(mapper, 1); - processPosition(mapper, x1 - 1, y1 - 1); + // first finger up, third finger receive move. + processSlot(mapper, FIRST_SLOT); + processId(mapper, INVALID_TRACKING_ID); processSync(mapper); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); - // second finger down, expect as new finger down. - processSlot(mapper, 1); - processId(mapper, 2); - processPosition(mapper, x2, y2); + // second finger up, third finger receive move. + processSlot(mapper, SECOND_SLOT); + processId(mapper, INVALID_TRACKING_ID); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // third finger up. + processSlot(mapper, THIRD_SLOT); + processId(mapper, INVALID_TRACKING_ID); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); +} + +/** + * Test multi-touch should sent POINTER_UP when received the MT_TOOL_PALM event from some finger, + * and the active finger could still be allowed to receive the events + */ +TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPointer) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(DISPLAY_ORIENTATION_0); + prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + NotifyMotionArgs motionArgs; + + // default tool type is finger + constexpr int32_t x1 = 100, y1 = 200, x2 = 120, y2 = 220; + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // Second finger down. + processSlot(mapper, SECOND_SLOT); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // If the tool type of the second finger changes to MT_TOOL_PALM, + // we expect to receive ACTION_POINTER_UP with cancel flag. + processId(mapper, SECOND_TRACKING_ID); + processToolType(mapper, MT_TOOL_PALM); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); + + // The following MOVE event should be processed. + processSlot(mapper, FIRST_SLOT); + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1 + 1, y1 + 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); + + // second finger up. + processSlot(mapper, SECOND_SLOT); + processId(mapper, INVALID_TRACKING_ID); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + + // first finger keep moving + processSlot(mapper, FIRST_SLOT); + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1 + 2, y1 + 2); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + + // first finger up. + processId(mapper, INVALID_TRACKING_ID); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); + ASSERT_NE(AMOTION_EVENT_FLAG_CANCELED, motionArgs.flags); } // --- MultiTouchInputMapperTest_ExternalDevice --- diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 0659511d25..7fec2c8b4b 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -179,6 +179,11 @@ void UinputTouchScreen::sendMove(const Point& point) { injectEvent(EV_SYN, SYN_REPORT, 0); } +void UinputTouchScreen::sendPointerUp() { + sendTrackingId(0xffffffff); + injectEvent(EV_SYN, SYN_REPORT, 0); +} + void UinputTouchScreen::sendUp() { sendTrackingId(0xffffffff); injectEvent(EV_KEY, BTN_TOUCH, 0); diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 22d1f630fc..01a557cc70 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -139,6 +139,7 @@ public: void sendTrackingId(int32_t trackingId); void sendDown(const Point& point); void sendMove(const Point& point); + void sendPointerUp(); void sendUp(); void sendToolType(int32_t toolType); |