Extract Gesture handling code and test it
Similarly to the HardwareState logic, extracting this code makes things
a bit clearer and easier to test.
Bug: 251196347
Test: m inputflinger_tests && \
$ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests \
--gtest_filter='*HardwareStateConverterTest*'
Test: atest inputflinger_tests
Change-Id: I6902e052fc5e193228aca4378587413b22889b26
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index f535ab4..c563dba 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -17,6 +17,7 @@
#include "../Macros.h"
#include <android/input.h>
+#include <linux/input-event-codes.h>
#include <log/log_main.h>
#include "TouchCursorInputMapperCommon.h"
#include "TouchpadInputMapper.h"
@@ -81,30 +82,14 @@
mapper->consumeGesture(gesture);
}
-uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) {
- switch (gesturesButton) {
- case GESTURES_BUTTON_LEFT:
- return AMOTION_EVENT_BUTTON_PRIMARY;
- case GESTURES_BUTTON_MIDDLE:
- return AMOTION_EVENT_BUTTON_TERTIARY;
- case GESTURES_BUTTON_RIGHT:
- return AMOTION_EVENT_BUTTON_SECONDARY;
- case GESTURES_BUTTON_BACK:
- return AMOTION_EVENT_BUTTON_BACK;
- case GESTURES_BUTTON_FORWARD:
- return AMOTION_EVENT_BUTTON_FORWARD;
- default:
- return 0;
- }
-}
-
} // namespace
TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext)
: InputMapper(deviceContext),
mGestureInterpreter(NewGestureInterpreter(), DeleteGestureInterpreter),
mPointerController(getContext()->getPointerController(getDeviceId())),
- mStateConverter(deviceContext) {
+ mStateConverter(deviceContext),
+ mGestureConverter(*getContext(), getDeviceId()) {
mGestureInterpreter->Initialize(GESTURES_DEVCLASS_TOUCHPAD);
mGestureInterpreter->SetHardwareProperties(createHardwareProperties(deviceContext));
// Even though we don't explicitly delete copy/move semantics, it's safe to
@@ -128,8 +113,7 @@
std::list<NotifyArgs> TouchpadInputMapper::reset(nsecs_t when) {
mStateConverter.reset();
-
- mButtonState = 0;
+ mGestureConverter.reset();
return InputMapper::reset(when);
}
@@ -163,137 +147,10 @@
std::list<NotifyArgs> TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out = {};
for (Gesture& gesture : mGesturesToProcess) {
- switch (gesture.type) {
- case kGestureTypeMove:
- out.push_back(handleMove(when, readTime, gesture));
- break;
- case kGestureTypeButtonsChange:
- out += handleButtonsChange(when, readTime, gesture);
- break;
- default:
- // TODO(b/251196347): handle more gesture types.
- break;
- }
+ out += mGestureConverter.handleGesture(when, readTime, gesture);
}
mGesturesToProcess.clear();
return out;
}
-NotifyArgs TouchpadInputMapper::handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture) {
- PointerProperties props;
- props.clear();
- props.id = 0;
- props.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- mPointerController->move(gesture.details.move.dx, gesture.details.move.dy);
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
-
- PointerCoords coords;
- coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, gesture.details.move.dx);
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, gesture.details.move.dy);
- const bool down = isPointerDown(mButtonState);
- coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
-
- const int32_t action = down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE;
- return makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState,
- /* pointerCount= */ 1, &props, &coords, xCursorPosition, yCursorPosition);
-}
-
-std::list<NotifyArgs> TouchpadInputMapper::handleButtonsChange(nsecs_t when, nsecs_t readTime,
- const Gesture& gesture) {
- std::list<NotifyArgs> out = {};
-
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
-
- PointerProperties props;
- props.clear();
- props.id = 0;
- props.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
-
- float xCursorPosition, yCursorPosition;
- mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
-
- PointerCoords coords;
- coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
- const uint32_t buttonsPressed = gesture.details.buttons.down;
- bool pointerDown = isPointerDown(mButtonState) ||
- buttonsPressed &
- (GESTURES_BUTTON_LEFT | GESTURES_BUTTON_MIDDLE | GESTURES_BUTTON_RIGHT);
- coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerDown ? 1.0f : 0.0f);
-
- uint32_t newButtonState = mButtonState;
- std::list<NotifyArgs> pressEvents = {};
- for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) {
- if (buttonsPressed & button) {
- uint32_t actionButton = gesturesButtonToMotionEventButton(button);
- newButtonState |= actionButton;
- pressEvents.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS,
- actionButton, newButtonState,
- /* pointerCount= */ 1, &props, &coords,
- xCursorPosition, yCursorPosition));
- }
- }
- if (!isPointerDown(mButtonState) && isPointerDown(newButtonState)) {
- mDownTime = when;
- out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
- /* actionButton= */ 0, newButtonState, /* pointerCount= */ 1,
- &props, &coords, xCursorPosition, yCursorPosition));
- }
- out.splice(out.end(), pressEvents);
-
- // The same button may be in both down and up in the same gesture, in which case we should treat
- // it as having gone down and then up. So, we treat a single button change gesture as two state
- // changes: a set of buttons going down, followed by a set of buttons going up.
- mButtonState = newButtonState;
-
- const uint32_t buttonsReleased = gesture.details.buttons.up;
- for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) {
- if (buttonsReleased & button) {
- uint32_t actionButton = gesturesButtonToMotionEventButton(button);
- newButtonState &= ~actionButton;
- out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
- actionButton, newButtonState, /* pointerCount= */ 1,
- &props, &coords, xCursorPosition, yCursorPosition));
- }
- }
- if (isPointerDown(mButtonState) && !isPointerDown(newButtonState)) {
- coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
- out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
- newButtonState, /* pointerCount= */ 1, &props, &coords,
- xCursorPosition, yCursorPosition));
- }
- mButtonState = newButtonState;
- return out;
-}
-
-NotifyMotionArgs TouchpadInputMapper::makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
- int32_t actionButton, int32_t buttonState,
- uint32_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords,
- float xCursorPosition, float yCursorPosition) {
- // TODO(b/260226362): consider what the appropriate source for these events is.
- const uint32_t source = AINPUT_SOURCE_MOUSE;
-
- return NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), source,
- mPointerController->getDisplayId(), /* policyFlags= */ 0, action,
- /* actionButton= */ actionButton, /* flags= */ 0,
- getContext()->getGlobalMetaState(), buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
- pointerProperties, pointerCoords,
- /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, xCursorPosition,
- yCursorPosition, /* downTime= */ mDownTime, /* videoFrames= */ {});
-}
-
} // namespace android
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index c6863f5..b3bc831 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -16,6 +16,7 @@
#pragma once
+#include <list>
#include <memory>
#include <vector>
@@ -25,6 +26,7 @@
#include "InputDevice.h"
#include "InputMapper.h"
#include "NotifyArgs.h"
+#include "gestures/GestureConverter.h"
#include "gestures/HardwareStateConverter.h"
#include "include/gestures.h"
@@ -46,30 +48,16 @@
[[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,
- const Gesture& gesture);
-
- NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
- int32_t actionButton, int32_t buttonState,
- uint32_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords, float xCursorPosition,
- float yCursorPosition);
std::unique_ptr<gestures::GestureInterpreter, void (*)(gestures::GestureInterpreter*)>
mGestureInterpreter;
std::shared_ptr<PointerControllerInterface> mPointerController;
HardwareStateConverter mStateConverter;
+ GestureConverter mGestureConverter;
bool mProcessing = false;
std::vector<Gesture> mGesturesToProcess;
-
- // The current button state according to the gestures library, but converted into MotionEvent
- // button values (AMOTION_EVENT_BUTTON_...).
- uint32_t mButtonState = 0;
- nsecs_t mDownTime = 0;
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
new file mode 100644
index 0000000..23216d3
--- /dev/null
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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/GestureConverter.h"
+
+#include <android/input.h>
+
+#include "TouchCursorInputMapperCommon.h"
+#include "input/Input.h"
+
+namespace android {
+
+namespace {
+
+uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) {
+ switch (gesturesButton) {
+ case GESTURES_BUTTON_LEFT:
+ return AMOTION_EVENT_BUTTON_PRIMARY;
+ case GESTURES_BUTTON_MIDDLE:
+ return AMOTION_EVENT_BUTTON_TERTIARY;
+ case GESTURES_BUTTON_RIGHT:
+ return AMOTION_EVENT_BUTTON_SECONDARY;
+ case GESTURES_BUTTON_BACK:
+ return AMOTION_EVENT_BUTTON_BACK;
+ case GESTURES_BUTTON_FORWARD:
+ return AMOTION_EVENT_BUTTON_FORWARD;
+ default:
+ return 0;
+ }
+}
+
+} // namespace
+
+GestureConverter::GestureConverter(InputReaderContext& readerContext, int32_t deviceId)
+ : mDeviceId(deviceId),
+ mReaderContext(readerContext),
+ mPointerController(readerContext.getPointerController(deviceId)) {}
+
+void GestureConverter::reset() {
+ mButtonState = 0;
+}
+
+std::list<NotifyArgs> GestureConverter::handleGesture(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture) {
+ switch (gesture.type) {
+ case kGestureTypeMove:
+ return {handleMove(when, readTime, gesture)};
+ case kGestureTypeButtonsChange:
+ return handleButtonsChange(when, readTime, gesture);
+ default:
+ // TODO(b/251196347): handle more gesture types.
+ return {};
+ }
+}
+
+NotifyArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture) {
+ PointerProperties props;
+ props.clear();
+ props.id = 0;
+ props.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
+ mPointerController->move(gesture.details.move.dx, gesture.details.move.dy);
+ mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
+ float xCursorPosition, yCursorPosition;
+ mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+
+ PointerCoords coords;
+ coords.clear();
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, gesture.details.move.dx);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, gesture.details.move.dy);
+ const bool down = isPointerDown(mButtonState);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
+
+ const int32_t action = down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE;
+ return makeMotionArgs(when, readTime, action, /* actionButton= */ 0, mButtonState,
+ /* pointerCount= */ 1, &props, &coords, xCursorPosition, yCursorPosition);
+}
+
+std::list<NotifyArgs> GestureConverter::handleButtonsChange(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture) {
+ std::list<NotifyArgs> out = {};
+
+ mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
+ mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
+
+ PointerProperties props;
+ props.clear();
+ props.id = 0;
+ props.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+ float xCursorPosition, yCursorPosition;
+ mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+
+ PointerCoords coords;
+ coords.clear();
+ coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
+ const uint32_t buttonsPressed = gesture.details.buttons.down;
+ bool pointerDown = isPointerDown(mButtonState) ||
+ buttonsPressed &
+ (GESTURES_BUTTON_LEFT | GESTURES_BUTTON_MIDDLE | GESTURES_BUTTON_RIGHT);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerDown ? 1.0f : 0.0f);
+
+ uint32_t newButtonState = mButtonState;
+ std::list<NotifyArgs> pressEvents = {};
+ for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) {
+ if (buttonsPressed & button) {
+ uint32_t actionButton = gesturesButtonToMotionEventButton(button);
+ newButtonState |= actionButton;
+ pressEvents.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS,
+ actionButton, newButtonState,
+ /* pointerCount= */ 1, &props, &coords,
+ xCursorPosition, yCursorPosition));
+ }
+ }
+ if (!isPointerDown(mButtonState) && isPointerDown(newButtonState)) {
+ mDownTime = when;
+ out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
+ /* actionButton= */ 0, newButtonState, /* pointerCount= */ 1,
+ &props, &coords, xCursorPosition, yCursorPosition));
+ }
+ out.splice(out.end(), pressEvents);
+
+ // The same button may be in both down and up in the same gesture, in which case we should treat
+ // it as having gone down and then up. So, we treat a single button change gesture as two state
+ // changes: a set of buttons going down, followed by a set of buttons going up.
+ mButtonState = newButtonState;
+
+ const uint32_t buttonsReleased = gesture.details.buttons.up;
+ for (uint32_t button = 1; button <= GESTURES_BUTTON_FORWARD; button <<= 1) {
+ if (buttonsReleased & button) {
+ uint32_t actionButton = gesturesButtonToMotionEventButton(button);
+ newButtonState &= ~actionButton;
+ out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ actionButton, newButtonState, /* pointerCount= */ 1,
+ &props, &coords, xCursorPosition, yCursorPosition));
+ }
+ }
+ if (isPointerDown(mButtonState) && !isPointerDown(newButtonState)) {
+ coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
+ out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
+ newButtonState, /* pointerCount= */ 1, &props, &coords,
+ xCursorPosition, yCursorPosition));
+ }
+ mButtonState = newButtonState;
+ return out;
+}
+
+NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
+ int32_t actionButton, int32_t buttonState,
+ uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords,
+ float xCursorPosition, float yCursorPosition) {
+ // TODO(b/260226362): consider what the appropriate source for these events is.
+ const uint32_t source = AINPUT_SOURCE_MOUSE;
+
+ return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, source,
+ mPointerController->getDisplayId(), /* policyFlags= */ 0, action,
+ /* actionButton= */ actionButton, /* flags= */ 0,
+ mReaderContext.getGlobalMetaState(), buttonState,
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
+ pointerProperties, pointerCoords,
+ /* xPrecision= */ 1.0f, /* yPrecision= */ 1.0f, xCursorPosition,
+ yCursorPosition, /* downTime= */ mDownTime, /* videoFrames= */ {});
+}
+
+} // namespace android
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
new file mode 100644
index 0000000..dc11f24
--- /dev/null
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -0,0 +1,65 @@
+/*
+ * 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 <list>
+#include <memory>
+
+#include <PointerControllerInterface.h>
+#include <utils/Timers.h>
+
+#include "InputReaderContext.h"
+#include "NotifyArgs.h"
+
+#include "include/gestures.h"
+
+namespace android {
+
+// Converts Gesture structs from the gestures library into NotifyArgs and the appropriate
+// PointerController calls.
+class GestureConverter {
+public:
+ GestureConverter(InputReaderContext& readerContext, int32_t deviceId);
+
+ void reset();
+
+ [[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture);
+
+private:
+ NotifyArgs handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture);
+ [[nodiscard]] std::list<NotifyArgs> handleButtonsChange(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture);
+
+ NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
+ int32_t actionButton, int32_t buttonState,
+ uint32_t pointerCount,
+ const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, float xCursorPosition,
+ float yCursorPosition);
+
+ const int32_t mDeviceId;
+ InputReaderContext& mReaderContext;
+ std::shared_ptr<PointerControllerInterface> mPointerController;
+
+ // The current button state according to the gestures library, but converted into MotionEvent
+ // button values (AMOTION_EVENT_BUTTON_...).
+ uint32_t mButtonState = 0;
+ nsecs_t mDownTime = 0;
+};
+
+} // namespace android