summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-07-21 12:09:04 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-07-21 12:09:04 +0000
commitdc07032296a6cd8525b5c7c1648ed7aed6f7769c (patch)
treee07eed6a54cd5f016ce2c428d2d180c4097a0759
parent5896c6247111f2f0984f76e614bc53315c9a3825 (diff)
parentcc7f98045f3b64af894c9454ca536e7e9d19c18c (diff)
Merge "Allow touch if some pointers are MT_TOOL_PALM"
-rw-r--r--include/input/Input.h7
-rw-r--r--services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp21
-rw-r--r--services/inputflinger/reader/mapper/MultiTouchInputMapper.h2
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.cpp22
-rw-r--r--services/inputflinger/reader/mapper/TouchInputMapper.h5
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp305
-rw-r--r--services/inputflinger/tests/UinputDevice.cpp5
-rw-r--r--services/inputflinger/tests/UinputDevice.h1
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);