touchpad: add touchpad system gesture setting
This new setting is implemented as a simple boolean check before
handling three- and four-finger swipe gestures. The only gotcha is to
make sure we end any ongoing swipe when they're disabled, so we don't
produce an inconsistent event stream.
Test: disable the setting, check three- and four-finger swipes on the
touchpad stop working; re-enable, check they work again
Test: $ adb shell 'stop && setprop log.tag.InputDispatcherVerifyEvents
DEBUG && start'
then toggle the setting while performing gestures, check there are
no crashes
Test: atest inputflinger_tests
Flag: com.android.hardware.input.touchpad_system_gesture_disable
Bug: 353947750
Change-Id: I4333e3d3bb6f89d29332c701937ea4c870b1cbc5
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 580cde3..4d6b6c7 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -245,6 +245,9 @@
// True to use three-finger tap as a customizable shortcut; false to use it as a middle-click.
bool touchpadThreeFingerTapShortcutEnabled;
+ // True to enable system gestures (three- and four-finger swipes) on touchpads.
+ bool touchpadSystemGesturesEnabled;
+
// The set of currently disabled input devices.
std::set<int32_t> disabledDevices;
@@ -297,6 +300,7 @@
shouldNotifyTouchpadHardwareState(false),
touchpadRightClickZoneEnabled(false),
touchpadThreeFingerTapShortcutEnabled(false),
+ touchpadSystemGesturesEnabled(true),
stylusButtonMotionEventsEnabled(true),
stylusPointerIconEnabled(false),
mouseReverseVerticalScrollingEnabled(false),
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index ca8266b..0c094e6 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -351,6 +351,7 @@
bumpGeneration();
}
+ std::list<NotifyArgs> out;
if (!changes.any() || changes.test(InputReaderConfiguration::Change::TOUCHPAD_SETTINGS)) {
mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve")
.setBoolValues({true});
@@ -375,11 +376,11 @@
mPropertyProvider.getProperty("Button Right Click Zone Enable")
.setBoolValues({config.touchpadRightClickZoneEnabled});
mTouchpadHardwareStateNotificationsEnabled = config.shouldNotifyTouchpadHardwareState;
-
mGestureConverter.setThreeFingerTapShortcutEnabled(
config.touchpadThreeFingerTapShortcutEnabled);
+ out += mGestureConverter.setEnableSystemGestures(when,
+ config.touchpadSystemGesturesEnabled);
}
- std::list<NotifyArgs> out;
if ((!changes.any() && config.pointerCaptureRequest.isEnable()) ||
changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE)) {
mPointerCaptured = config.pointerCaptureRequest.isEnable();
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 54270eb..6bd949a 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -132,6 +132,15 @@
return out;
}
+std::list<NotifyArgs> GestureConverter::setEnableSystemGestures(nsecs_t when, bool enable) {
+ std::list<NotifyArgs> out;
+ if (!enable && mCurrentClassification == MotionClassification::MULTI_FINGER_SWIPE) {
+ out += handleMultiFingerSwipeLift(when, when);
+ }
+ mEnableSystemGestures = enable;
+ return out;
+}
+
void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const {
info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, SOURCE, 0.0f, 1.0f, 0, 0, 0);
@@ -461,6 +470,9 @@
uint32_t fingerCount,
float dx, float dy) {
std::list<NotifyArgs> out = {};
+ if (!mEnableSystemGestures) {
+ return out;
+ }
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
// If the user changes the number of fingers mid-way through a swipe (e.g. they start with
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index ad40721..8d92ead 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -59,6 +59,8 @@
mThreeFingerTapShortcutEnabled = enabled;
}
+ [[nodiscard]] std::list<NotifyArgs> setEnableSystemGestures(nsecs_t when, bool enable);
+
void populateMotionRanges(InputDeviceInfo& info) const;
[[nodiscard]] std::list<NotifyArgs> handleGesture(nsecs_t when, nsecs_t readTime,
@@ -104,6 +106,7 @@
InputReaderContext& mReaderContext;
const bool mEnableFlingStop;
const bool mEnableNoFocusChange;
+ bool mEnableSystemGestures{true};
bool mThreeFingerTapShortcutEnabled;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index fad8f05..fe40a5e 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -48,6 +48,7 @@
using testing::AllOf;
using testing::Each;
using testing::ElementsAre;
+using testing::IsEmpty;
using testing::VariantWith;
class GestureConverterTest : public testing::Test {
@@ -849,6 +850,107 @@
WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
}
+TEST_F(GestureConverterTest, DisablingSystemGestures_IgnoresMultiFingerSwipe) {
+ InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+ GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
+ converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
+
+ std::list<NotifyArgs> args = converter.setEnableSystemGestures(ARBITRARY_TIME, false);
+ ASSERT_THAT(args, IsEmpty());
+
+ Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0,
+ /*dy=*/10);
+ Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0,
+ /*dy=*/5);
+ Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
+
+ args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
+ args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
+ args += converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
+ ASSERT_THAT(args, IsEmpty());
+
+ args = converter.setEnableSystemGestures(ARBITRARY_TIME, true);
+ ASSERT_THAT(args, IsEmpty());
+
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)),
+ VariantWith<NotifyMotionArgs>(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)),
+ VariantWith<NotifyMotionArgs>(
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE))));
+ ASSERT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE))));
+}
+
+TEST_F(GestureConverterTest, DisablingSystemGestures_EndsOngoingMultiFingerSwipe) {
+ InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+ GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
+ converter.setDisplayId(ui::LogicalDisplayId::DEFAULT);
+
+ Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0,
+ /*dy=*/10);
+ std::list<NotifyArgs> args;
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
+ ASSERT_FALSE(args.empty());
+
+ // Disabling system gestures should end the swipe early.
+ args = converter.setEnableSystemGestures(ARBITRARY_TIME, false);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithGestureOffset(0, 0, EPSILON),
+ WithMotionClassification(
+ MotionClassification::MULTI_FINGER_SWIPE),
+ WithPointerCount(3u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithGestureOffset(0, 0, EPSILON),
+ WithMotionClassification(
+ MotionClassification::MULTI_FINGER_SWIPE),
+ WithPointerCount(2u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithGestureOffset(0, 0, EPSILON),
+ WithMotionClassification(
+ MotionClassification::MULTI_FINGER_SWIPE),
+ WithPointerCount(1u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
+ WithMotionClassification(MotionClassification::NONE)))));
+ ASSERT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithToolType(ToolType::FINGER),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)))));
+
+ // Further movement in the same swipe should be ignored.
+ Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0,
+ /*dy=*/5);
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
+ ASSERT_THAT(args, IsEmpty());
+ Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
+ ASSERT_THAT(args, IsEmpty());
+
+ // But single-finger pointer motion should be reported.
+ Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithRelativeMotion(-5, 10), WithButtonState(0)))));
+}
+
TEST_F(GestureConverterTest, Pinch_Inwards) {
input_flags::enable_touchpad_no_focus_change(true);