Extract HardwareState conversion into a class and test it
Putting the conversion logic into its own class makes it more obvious
which variables are used for HardwareState conversion, and also provides
a clean public API to write tests against.
Bug: 251196347
Test: m inputflinger_tests && \
$ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests \
--gtest_filter='*HardwareStateConverterTest*'
Test: atest inputflinger_tests
Change-Id: I26771887b6b2eae46c9cec7190499da0016fdb1f
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index f37f0fa..1535df3 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -29,6 +29,7 @@
"include",
"mapper",
"mapper/accumulator",
+ "mapper/gestures",
],
}
@@ -61,6 +62,7 @@
"mapper/accumulator/SingleTouchMotionAccumulator.cpp",
"mapper/accumulator/TouchButtonAccumulator.cpp",
"mapper/gestures/GesturesLogging.cpp",
+ "mapper/gestures/HardwareStateConverter.cpp",
],
}
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 956a7aa..f535ab4 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -16,8 +16,6 @@
#include "../Macros.h"
-#include <chrono>
-
#include <android/input.h>
#include <log/log_main.h>
#include "TouchCursorInputMapperCommon.h"
@@ -106,7 +104,7 @@
: InputMapper(deviceContext),
mGestureInterpreter(NewGestureInterpreter(), DeleteGestureInterpreter),
mPointerController(getContext()->getPointerController(getDeviceId())),
- mTouchButtonAccumulator(deviceContext) {
+ mStateConverter(deviceContext) {
mGestureInterpreter->Initialize(GESTURES_DEVCLASS_TOUCHPAD);
mGestureInterpreter->SetHardwareProperties(createHardwareProperties(deviceContext));
// Even though we don't explicitly delete copy/move semantics, it's safe to
@@ -116,16 +114,6 @@
mGestureInterpreter->SetCallback(gestureInterpreterCallback, this);
// TODO(b/251196347): set a property provider, so we can change gesture properties.
// TODO(b/251196347): set a timer provider, so the library can use timers.
-
- RawAbsoluteAxisInfo slotAxisInfo;
- getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
- if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) {
- ALOGW("Touchpad \"%s\" doesn't have a valid ABS_MT_SLOT axis, and probably won't work "
- "properly.",
- getDeviceName().c_str());
- }
- mMotionAccumulator.configure(getDeviceContext(), slotAxisInfo.maxValue + 1, true);
- mTouchButtonAccumulator.configure();
}
TouchpadInputMapper::~TouchpadInputMapper() {
@@ -139,82 +127,28 @@
}
std::list<NotifyArgs> TouchpadInputMapper::reset(nsecs_t when) {
- mCursorButtonAccumulator.reset(getDeviceContext());
- mTouchButtonAccumulator.reset();
- mMscTimestamp = 0;
+ mStateConverter.reset();
mButtonState = 0;
return InputMapper::reset(when);
}
std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent* rawEvent) {
- std::list<NotifyArgs> out = {};
- if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- out = sync(rawEvent->when, rawEvent->readTime);
+ std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent);
+ if (state) {
+ return sendHardwareState(rawEvent->when, rawEvent->readTime, *state);
+ } else {
+ return {};
}
- if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {
- mMscTimestamp = rawEvent->value;
- }
- mCursorButtonAccumulator.process(rawEvent);
- mMotionAccumulator.process(rawEvent);
- mTouchButtonAccumulator.process(rawEvent);
- return out;
}
-std::list<NotifyArgs> TouchpadInputMapper::sync(nsecs_t when, nsecs_t readTime) {
- HardwareState hwState;
- // The gestures library uses doubles to represent timestamps in seconds.
- hwState.timestamp = std::chrono::duration<stime_t>(std::chrono::nanoseconds(when)).count();
- hwState.msc_timestamp =
- std::chrono::duration<stime_t>(std::chrono::microseconds(mMscTimestamp)).count();
-
- hwState.buttons_down = 0;
- if (mCursorButtonAccumulator.isLeftPressed()) {
- hwState.buttons_down |= GESTURES_BUTTON_LEFT;
- }
- if (mCursorButtonAccumulator.isMiddlePressed()) {
- hwState.buttons_down |= GESTURES_BUTTON_MIDDLE;
- }
- if (mCursorButtonAccumulator.isRightPressed()) {
- hwState.buttons_down |= GESTURES_BUTTON_RIGHT;
- }
- if (mCursorButtonAccumulator.isBackPressed() || mCursorButtonAccumulator.isSidePressed()) {
- hwState.buttons_down |= GESTURES_BUTTON_BACK;
- }
- if (mCursorButtonAccumulator.isForwardPressed() || mCursorButtonAccumulator.isExtraPressed()) {
- hwState.buttons_down |= GESTURES_BUTTON_FORWARD;
- }
-
- std::vector<FingerState> fingers;
- for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
- MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i);
- if (slot.isInUse()) {
- FingerState& fingerState = fingers.emplace_back();
- fingerState = {};
- fingerState.touch_major = slot.getTouchMajor();
- fingerState.touch_minor = slot.getTouchMinor();
- fingerState.width_major = slot.getToolMajor();
- fingerState.width_minor = slot.getToolMinor();
- fingerState.pressure = slot.getPressure();
- fingerState.orientation = slot.getOrientation();
- fingerState.position_x = slot.getX();
- fingerState.position_y = slot.getY();
- fingerState.tracking_id = slot.getTrackingId();
- }
- }
- hwState.fingers = fingers.data();
- hwState.finger_cnt = fingers.size();
- hwState.touch_cnt = mTouchButtonAccumulator.getTouchCount();
-
+std::list<NotifyArgs> TouchpadInputMapper::sendHardwareState(nsecs_t when, nsecs_t readTime,
+ SelfContainedHardwareState schs) {
mProcessing = true;
- mGestureInterpreter->PushHardwareState(&hwState);
+ mGestureInterpreter->PushHardwareState(&schs.state);
mProcessing = false;
- std::list<NotifyArgs> out = processGestures(when, readTime);
-
- mMotionAccumulator.finishSync();
- mMscTimestamp = 0;
- return out;
+ return processGestures(when, readTime);
}
void TouchpadInputMapper::consumeGesture(const Gesture* gesture) {
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index fe6b1fe..c6863f5 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -17,6 +17,7 @@
#pragma once
#include <memory>
+#include <vector>
#include <PointerControllerInterface.h>
@@ -24,9 +25,7 @@
#include "InputDevice.h"
#include "InputMapper.h"
#include "NotifyArgs.h"
-#include "accumulator/CursorButtonAccumulator.h"
-#include "accumulator/MultiTouchMotionAccumulator.h"
-#include "accumulator/TouchButtonAccumulator.h"
+#include "gestures/HardwareStateConverter.h"
#include "include/gestures.h"
@@ -44,7 +43,8 @@
void consumeGesture(const Gesture* gesture);
private:
- [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> sendHardwareState(nsecs_t when, nsecs_t readTime,
+ SelfContainedHardwareState schs);
[[nodiscard]] std::list<NotifyArgs> processGestures(nsecs_t when, nsecs_t readTime);
NotifyArgs handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture);
[[nodiscard]] std::list<NotifyArgs> handleButtonsChange(nsecs_t when, nsecs_t readTime,
@@ -61,10 +61,7 @@
mGestureInterpreter;
std::shared_ptr<PointerControllerInterface> mPointerController;
- CursorButtonAccumulator mCursorButtonAccumulator;
- MultiTouchMotionAccumulator mMotionAccumulator;
- TouchButtonAccumulator mTouchButtonAccumulator;
- int32_t mMscTimestamp = 0;
+ HardwareStateConverter mStateConverter;
bool mProcessing = false;
std::vector<Gesture> mGesturesToProcess;
diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
new file mode 100644
index 0000000..49c13ca
--- /dev/null
+++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gestures/HardwareStateConverter.h"
+
+#include <chrono>
+#include <vector>
+
+#include <linux/input-event-codes.h>
+
+namespace android {
+
+HardwareStateConverter::HardwareStateConverter(InputDeviceContext& deviceContext)
+ : mDeviceContext(deviceContext), mTouchButtonAccumulator(deviceContext) {
+ RawAbsoluteAxisInfo slotAxisInfo;
+ deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
+ if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) {
+ ALOGW("Touchpad \"%s\" doesn't have a valid ABS_MT_SLOT axis, and probably won't work "
+ "properly.",
+ deviceContext.getName().c_str());
+ }
+ mMotionAccumulator.configure(deviceContext, slotAxisInfo.maxValue + 1, true);
+ mTouchButtonAccumulator.configure();
+}
+
+std::optional<SelfContainedHardwareState> HardwareStateConverter::processRawEvent(
+ const RawEvent* rawEvent) {
+ std::optional<SelfContainedHardwareState> out;
+ if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+ out = produceHardwareState(rawEvent->when);
+ mMotionAccumulator.finishSync();
+ mMscTimestamp = 0;
+ }
+ if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {
+ mMscTimestamp = rawEvent->value;
+ }
+ mCursorButtonAccumulator.process(rawEvent);
+ mMotionAccumulator.process(rawEvent);
+ mTouchButtonAccumulator.process(rawEvent);
+ return out;
+}
+
+SelfContainedHardwareState HardwareStateConverter::produceHardwareState(nsecs_t when) {
+ SelfContainedHardwareState schs;
+ // The gestures library uses doubles to represent timestamps in seconds.
+ schs.state.timestamp = std::chrono::duration<stime_t>(std::chrono::nanoseconds(when)).count();
+ schs.state.msc_timestamp =
+ std::chrono::duration<stime_t>(std::chrono::microseconds(mMscTimestamp)).count();
+
+ schs.state.buttons_down = 0;
+ if (mCursorButtonAccumulator.isLeftPressed()) {
+ schs.state.buttons_down |= GESTURES_BUTTON_LEFT;
+ }
+ if (mCursorButtonAccumulator.isMiddlePressed()) {
+ schs.state.buttons_down |= GESTURES_BUTTON_MIDDLE;
+ }
+ if (mCursorButtonAccumulator.isRightPressed()) {
+ schs.state.buttons_down |= GESTURES_BUTTON_RIGHT;
+ }
+ if (mCursorButtonAccumulator.isBackPressed() || mCursorButtonAccumulator.isSidePressed()) {
+ schs.state.buttons_down |= GESTURES_BUTTON_BACK;
+ }
+ if (mCursorButtonAccumulator.isForwardPressed() || mCursorButtonAccumulator.isExtraPressed()) {
+ schs.state.buttons_down |= GESTURES_BUTTON_FORWARD;
+ }
+
+ schs.fingers.clear();
+ for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
+ MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i);
+ if (slot.isInUse()) {
+ FingerState& fingerState = schs.fingers.emplace_back();
+ fingerState = {};
+ fingerState.touch_major = slot.getTouchMajor();
+ fingerState.touch_minor = slot.getTouchMinor();
+ fingerState.width_major = slot.getToolMajor();
+ fingerState.width_minor = slot.getToolMinor();
+ fingerState.pressure = slot.getPressure();
+ fingerState.orientation = slot.getOrientation();
+ fingerState.position_x = slot.getX();
+ fingerState.position_y = slot.getY();
+ fingerState.tracking_id = slot.getTrackingId();
+ }
+ }
+ schs.state.fingers = schs.fingers.data();
+ schs.state.finger_cnt = schs.fingers.size();
+ schs.state.touch_cnt = mTouchButtonAccumulator.getTouchCount();
+ return schs;
+}
+
+void HardwareStateConverter::reset() {
+ mCursorButtonAccumulator.reset(mDeviceContext);
+ mTouchButtonAccumulator.reset();
+ mMscTimestamp = 0;
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h
new file mode 100644
index 0000000..fd63c05
--- /dev/null
+++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <utils/Timers.h>
+
+#include "EventHub.h"
+#include "InputDevice.h"
+#include "accumulator/CursorButtonAccumulator.h"
+#include "accumulator/MultiTouchMotionAccumulator.h"
+#include "accumulator/TouchButtonAccumulator.h"
+
+#include "include/gestures.h"
+
+namespace android {
+
+// A HardwareState struct, but bundled with a vector to contain its FingerStates, so you don't have
+// to worry about where that memory is allocated.
+struct SelfContainedHardwareState {
+ HardwareState state;
+ std::vector<FingerState> fingers;
+};
+
+// Converts RawEvents into the HardwareState structs used by the gestures library.
+class HardwareStateConverter {
+public:
+ HardwareStateConverter(InputDeviceContext& deviceContext);
+
+ std::optional<SelfContainedHardwareState> processRawEvent(const RawEvent* event);
+ void reset();
+
+private:
+ SelfContainedHardwareState produceHardwareState(nsecs_t when);
+
+ InputDeviceContext& mDeviceContext;
+ CursorButtonAccumulator mCursorButtonAccumulator;
+ MultiTouchMotionAccumulator mMotionAccumulator;
+ TouchButtonAccumulator mTouchButtonAccumulator;
+ int32_t mMscTimestamp = 0;
+};
+
+} // namespace android