Loading include/input/InputConsumer.h +3 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,7 @@ private: BitSet32 idBits; int32_t idToIndex[MAX_POINTER_ID + 1]; PointerCoords pointers[MAX_POINTERS]; int32_t displayId; void initializeFrom(const InputMessage& msg) { eventTime = msg.body.motion.eventTime; Loading @@ -145,6 +146,7 @@ private: idToIndex[id] = i; pointers[i].copyFrom(msg.body.motion.pointers[i].coords); } displayId = msg.body.motion.displayId; } void initializeFrom(const History& other) { Loading @@ -157,6 +159,7 @@ private: pointers[index].copyFrom(other.pointers[index]); } idBits = other.idBits; // final copy displayId = other.displayId; } const PointerCoords& getPointerById(uint32_t id) const { return pointers[idToIndex[id]]; } Loading include/input/InputConsumerNoResampling.h +5 −0 Original line number Diff line number Diff line Loading @@ -260,6 +260,11 @@ private: * the batched MotionEvent that it received. */ std::map<uint32_t, std::vector<uint32_t>> mBatchedSequenceNumbers; /** * Checks if a given input event is okay to be added to an existing batch or not. */ bool isBatchableEvent(const InputMessage& message) const; }; } // namespace android libs/input/InputConsumer.cpp +8 −1 Original line number Diff line number Diff line Loading @@ -658,6 +658,11 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, } } if (current->displayId != other->displayId) { ALOGD_IF(debugResampling(), "Not resampled, the other is on a different display"); return; } // Resample touch coordinates. History oldLastResample; oldLastResample.initializeFrom(touchState.lastResample); Loading Loading @@ -840,9 +845,11 @@ bool InputConsumer::canAddSample(const Batch& batch, const InputMessage* msg) { const InputMessage& head = batch.samples[0]; uint32_t pointerCount = msg->body.motion.pointerCount; if (head.body.motion.pointerCount != pointerCount || head.body.motion.action != msg->body.motion.action) { head.body.motion.action != msg->body.motion.action || head.body.motion.displayId != msg->body.motion.displayId) { return false; } for (size_t i = 0; i < pointerCount; i++) { if (head.body.motion.pointers[i].properties != msg->body.motion.pointers[i].properties) { return false; Loading libs/input/InputConsumerNoResampling.cpp +22 −4 Original line number Diff line number Diff line Loading @@ -348,10 +348,7 @@ void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messa const int32_t action = msg.body.motion.action; const DeviceId deviceId = msg.body.motion.deviceId; const int32_t source = msg.body.motion.source; const bool batchableEvent = (action == AMOTION_EVENT_ACTION_MOVE || action == AMOTION_EVENT_ACTION_HOVER_MOVE) && (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) || isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK)); const bool batchableEvent = isBatchableEvent(msg); const bool canResample = (mResamplerCreator != nullptr) && (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER)); Loading Loading @@ -624,4 +621,25 @@ std::string InputConsumerNoResampling::dump() const { return out; } bool InputConsumerNoResampling::isBatchableEvent(const InputMessage& message) const { const int32_t action = message.body.motion.action; const int32_t source = message.body.motion.source; const bool batchableEventTypeAndSource = (action == AMOTION_EVENT_ACTION_MOVE || action == AMOTION_EVENT_ACTION_HOVER_MOVE) && (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) || isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK)); if (!batchableEventTypeAndSource) { return false; } const DeviceId deviceId = message.body.motion.deviceId; const auto& it = mBatches.find(deviceId); // If there is no pending event from the device, it's okay to add the event to the batch. if (it == mBatches.end() || it->second.size() == 0) { return true; } // It's okay to add the event to the existing batch if it's on the same display. return it->second.front().body.motion.displayId == message.body.motion.displayId; } } // namespace android libs/input/tests/InputConsumerResampling_test.cpp +49 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ struct InputEventEntry { std::chrono::nanoseconds eventTime{0}; std::vector<Pointer> pointers{}; int32_t action{-1}; ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT; }; } // namespace Loading Loading @@ -137,7 +138,8 @@ InputMessage InputConsumerResamplingTest::nextPointerMessage(const InputEventEnt .eventTime(entry.eventTime.count()) .deviceId(1) .action(entry.action) .downTime(0); .downTime(0) .displayId(entry.displayId); for (const Pointer& pointer : entry.pointers) { messageBuilder.pointer(pointer.asPointerBuilder()); } Loading Loading @@ -741,4 +743,50 @@ TEST_F(InputConsumerResamplingTest, TwoPointersAreResampledIndependently) { AMOTION_EVENT_ACTION_MOVE}}); } /** * Events should not be resampled when they are on different displays. */ TEST_F(InputConsumerResamplingTest, EventsOnDifferentDisplaysAreNotResampled) { // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an // InputEvent with a single action. mClientTestChannel->enqueueMessage(nextPointerMessage( {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN})); invokeLooperCallback(); assertReceivedMotionEvent({InputEventEntry{0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}}); // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y, but on // different displays mClientTestChannel->enqueueMessage( nextPointerMessage({10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId::DEFAULT})); mClientTestChannel->enqueueMessage( nextPointerMessage({20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId{1}})); invokeLooperCallback(); mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + RESAMPLE_LATENCY * 2}.count()); // MotionEvent should not be resampled because the resample time falls exactly on the existing // event time. assertReceivedMotionEvent({InputEventEntry{10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId::DEFAULT}}); assertReceivedMotionEvent({InputEventEntry{20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId{1}}}); mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true); mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true); mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true); } } // namespace android Loading
include/input/InputConsumer.h +3 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,7 @@ private: BitSet32 idBits; int32_t idToIndex[MAX_POINTER_ID + 1]; PointerCoords pointers[MAX_POINTERS]; int32_t displayId; void initializeFrom(const InputMessage& msg) { eventTime = msg.body.motion.eventTime; Loading @@ -145,6 +146,7 @@ private: idToIndex[id] = i; pointers[i].copyFrom(msg.body.motion.pointers[i].coords); } displayId = msg.body.motion.displayId; } void initializeFrom(const History& other) { Loading @@ -157,6 +159,7 @@ private: pointers[index].copyFrom(other.pointers[index]); } idBits = other.idBits; // final copy displayId = other.displayId; } const PointerCoords& getPointerById(uint32_t id) const { return pointers[idToIndex[id]]; } Loading
include/input/InputConsumerNoResampling.h +5 −0 Original line number Diff line number Diff line Loading @@ -260,6 +260,11 @@ private: * the batched MotionEvent that it received. */ std::map<uint32_t, std::vector<uint32_t>> mBatchedSequenceNumbers; /** * Checks if a given input event is okay to be added to an existing batch or not. */ bool isBatchableEvent(const InputMessage& message) const; }; } // namespace android
libs/input/InputConsumer.cpp +8 −1 Original line number Diff line number Diff line Loading @@ -658,6 +658,11 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, } } if (current->displayId != other->displayId) { ALOGD_IF(debugResampling(), "Not resampled, the other is on a different display"); return; } // Resample touch coordinates. History oldLastResample; oldLastResample.initializeFrom(touchState.lastResample); Loading Loading @@ -840,9 +845,11 @@ bool InputConsumer::canAddSample(const Batch& batch, const InputMessage* msg) { const InputMessage& head = batch.samples[0]; uint32_t pointerCount = msg->body.motion.pointerCount; if (head.body.motion.pointerCount != pointerCount || head.body.motion.action != msg->body.motion.action) { head.body.motion.action != msg->body.motion.action || head.body.motion.displayId != msg->body.motion.displayId) { return false; } for (size_t i = 0; i < pointerCount; i++) { if (head.body.motion.pointers[i].properties != msg->body.motion.pointers[i].properties) { return false; Loading
libs/input/InputConsumerNoResampling.cpp +22 −4 Original line number Diff line number Diff line Loading @@ -348,10 +348,7 @@ void InputConsumerNoResampling::handleMessages(std::vector<InputMessage>&& messa const int32_t action = msg.body.motion.action; const DeviceId deviceId = msg.body.motion.deviceId; const int32_t source = msg.body.motion.source; const bool batchableEvent = (action == AMOTION_EVENT_ACTION_MOVE || action == AMOTION_EVENT_ACTION_HOVER_MOVE) && (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) || isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK)); const bool batchableEvent = isBatchableEvent(msg); const bool canResample = (mResamplerCreator != nullptr) && (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER)); Loading Loading @@ -624,4 +621,25 @@ std::string InputConsumerNoResampling::dump() const { return out; } bool InputConsumerNoResampling::isBatchableEvent(const InputMessage& message) const { const int32_t action = message.body.motion.action; const int32_t source = message.body.motion.source; const bool batchableEventTypeAndSource = (action == AMOTION_EVENT_ACTION_MOVE || action == AMOTION_EVENT_ACTION_HOVER_MOVE) && (isFromSource(source, AINPUT_SOURCE_CLASS_POINTER) || isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK)); if (!batchableEventTypeAndSource) { return false; } const DeviceId deviceId = message.body.motion.deviceId; const auto& it = mBatches.find(deviceId); // If there is no pending event from the device, it's okay to add the event to the batch. if (it == mBatches.end() || it->second.size() == 0) { return true; } // It's okay to add the event to the existing batch if it's on the same display. return it->second.front().body.motion.displayId == message.body.motion.displayId; } } // namespace android
libs/input/tests/InputConsumerResampling_test.cpp +49 −1 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ struct InputEventEntry { std::chrono::nanoseconds eventTime{0}; std::vector<Pointer> pointers{}; int32_t action{-1}; ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT; }; } // namespace Loading Loading @@ -137,7 +138,8 @@ InputMessage InputConsumerResamplingTest::nextPointerMessage(const InputEventEnt .eventTime(entry.eventTime.count()) .deviceId(1) .action(entry.action) .downTime(0); .downTime(0) .displayId(entry.displayId); for (const Pointer& pointer : entry.pointers) { messageBuilder.pointer(pointer.asPointerBuilder()); } Loading Loading @@ -741,4 +743,50 @@ TEST_F(InputConsumerResamplingTest, TwoPointersAreResampledIndependently) { AMOTION_EVENT_ACTION_MOVE}}); } /** * Events should not be resampled when they are on different displays. */ TEST_F(InputConsumerResamplingTest, EventsOnDifferentDisplaysAreNotResampled) { // Send the initial ACTION_DOWN separately, so that the first consumed event will only return an // InputEvent with a single action. mClientTestChannel->enqueueMessage(nextPointerMessage( {0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN})); invokeLooperCallback(); assertReceivedMotionEvent({InputEventEntry{0ms, {Pointer{.id = 0, .x = 10.0f, .y = 20.0f}}, AMOTION_EVENT_ACTION_DOWN}}); // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y, but on // different displays mClientTestChannel->enqueueMessage( nextPointerMessage({10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId::DEFAULT})); mClientTestChannel->enqueueMessage( nextPointerMessage({20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId{1}})); invokeLooperCallback(); mConsumer->consumeBatchedInputEvents(nanoseconds{20ms + RESAMPLE_LATENCY * 2}.count()); // MotionEvent should not be resampled because the resample time falls exactly on the existing // event time. assertReceivedMotionEvent({InputEventEntry{10ms, {Pointer{.id = 0, .x = 20.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId::DEFAULT}}); assertReceivedMotionEvent({InputEventEntry{20ms, {Pointer{.id = 0, .x = 30.0f, .y = 30.0f}}, AMOTION_EVENT_ACTION_MOVE, ui::LogicalDisplayId{1}}}); mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true); mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true); mClientTestChannel->assertFinishMessage(/*seq=*/3, /*handled=*/true); } } // namespace android